mirror of
https://github.com/minio/minio.git
synced 2025-04-08 21:55:44 -04:00
- Current implementation was spawning renewer goroutines without waiting for the lease duration to end. Remove vault renewer and call vault.RenewToken directly and manage reauthentication if lease expired.
This commit is contained in:
parent
1e82c4a7c4
commit
e098852a80
@ -16,7 +16,6 @@ package crypto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -24,7 +23,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
vault "github.com/hashicorp/vault/api"
|
vault "github.com/hashicorp/vault/api"
|
||||||
"github.com/minio/minio/cmd/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -64,6 +62,7 @@ type VaultConfig struct {
|
|||||||
type vaultService struct {
|
type vaultService struct {
|
||||||
config *VaultConfig
|
config *VaultConfig
|
||||||
client *vault.Client
|
client *vault.Client
|
||||||
|
secret *vault.Secret
|
||||||
leaseDuration time.Duration
|
leaseDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,86 +122,81 @@ func NewVault(config VaultConfig) (KMS, error) {
|
|||||||
client.SetNamespace(config.Namespace)
|
client.SetNamespace(config.Namespace)
|
||||||
}
|
}
|
||||||
v := &vaultService{client: client, config: &config}
|
v := &vaultService{client: client, config: &config}
|
||||||
|
|
||||||
if err := v.authenticate(); err != nil {
|
if err := v.authenticate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
v.renewToken()
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// renewSecret tries to renew the given secret. It blocks
|
// renewToken starts a new go-routine which renews
|
||||||
// until it receives either the new secret or encounters an error.
|
// the vault authentication token periodically and re-authenticates
|
||||||
func (v *vaultService) renewSecret(secret *vault.Secret) (*vault.Secret, error) {
|
// if the token renewal fails
|
||||||
renewer, err := v.client.NewRenewer(&vault.RenewerInput{
|
func (v *vaultService) renewToken() {
|
||||||
Secret: secret,
|
retryDelay := v.leaseDuration / 2
|
||||||
})
|
go func() {
|
||||||
if err != nil {
|
for {
|
||||||
logger.CriticalIf(context.Background(), fmt.Errorf("crypto: failed to create hashicorp vault renewer: %s", err))
|
if v.secret == nil {
|
||||||
}
|
if err := v.authenticate(); err != nil {
|
||||||
go renewer.Renew()
|
time.Sleep(retryDelay)
|
||||||
defer renewer.Stop()
|
continue
|
||||||
|
}
|
||||||
for {
|
}
|
||||||
select {
|
s, err := v.client.Auth().Token().RenewSelf(int(v.leaseDuration))
|
||||||
case err := <-renewer.DoneCh():
|
if err != nil || s == nil {
|
||||||
|
v.secret = nil
|
||||||
|
time.Sleep(retryDelay)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ok, err := s.TokenIsRenewable(); !ok || err != nil {
|
||||||
|
v.secret = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ttl, err := s.TokenTTL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
v.secret = nil
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
case renew := <-renewer.RenewCh():
|
v.secret = s
|
||||||
if renew.Secret == nil || renew.Secret.Auth == nil {
|
retryDelay = ttl / 2
|
||||||
return nil, ErrKMSAuthLogin
|
time.Sleep(retryDelay)
|
||||||
}
|
|
||||||
return renew.Secret, nil
|
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// login tries to authenticate the minio server to
|
// authenticate logs the app to vault, and starts the auto renewer
|
||||||
// the Vault KMS using the approle ID and secret.
|
// before secret expires
|
||||||
func (v *vaultService) login() (*vault.Secret, error) {
|
func (v *vaultService) authenticate() (err error) {
|
||||||
payload := map[string]interface{}{
|
payload := map[string]interface{}{
|
||||||
"role_id": v.config.Auth.AppRole.ID,
|
"role_id": v.config.Auth.AppRole.ID,
|
||||||
"secret_id": v.config.Auth.AppRole.Secret,
|
"secret_id": v.config.Auth.AppRole.Secret,
|
||||||
}
|
}
|
||||||
secret, err := v.client.Logical().Write("auth/approle/login", payload)
|
var tokenID string
|
||||||
|
var ttl time.Duration
|
||||||
|
var secret *vault.Secret
|
||||||
|
secret, err = v.client.Logical().Write("auth/approle/login", payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if secret == nil || secret.Auth == nil {
|
if secret == nil {
|
||||||
return nil, ErrKMSAuthLogin
|
err = ErrKMSAuthLogin
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return secret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// authenticate tries to authenticate the minio server
|
tokenID, err = secret.TokenID()
|
||||||
// to the Vault KMS and starts a background job to renew
|
|
||||||
// the login.
|
|
||||||
func (v *vaultService) authenticate() error {
|
|
||||||
secret, err := v.login()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
err = ErrKMSAuthLogin
|
||||||
|
return
|
||||||
}
|
}
|
||||||
v.client.SetToken(secret.Auth.ClientToken)
|
ttl, err = secret.TokenTTL()
|
||||||
v.leaseDuration = time.Duration(secret.Auth.LeaseDuration)
|
if err != nil {
|
||||||
|
err = ErrKMSAuthLogin
|
||||||
// Start background job trying to renew the token
|
return
|
||||||
// or (if this fails) try to login again with app-ID and app-Secret.
|
}
|
||||||
go func(secret *vault.Secret) {
|
v.client.SetToken(tokenID)
|
||||||
for {
|
v.secret = secret
|
||||||
newSecret, err := v.renewSecret(secret) // try to renew the secret (blocking)
|
v.leaseDuration = ttl
|
||||||
if err != nil {
|
return
|
||||||
// Try to login again with app-ID and app-Secret
|
|
||||||
if newSecret, err = v.login(); err != nil { // failed -> try again
|
|
||||||
time.Sleep(1 * time.Minute) // retry delay
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
secret = newSecret // Now newSecret contains a valid, non-nil *vault.Secret
|
|
||||||
v.client.SetToken(secret.Auth.ClientToken)
|
|
||||||
v.leaseDuration = time.Duration(secret.Auth.LeaseDuration)
|
|
||||||
}
|
|
||||||
}(secret)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKey returns a new plaintext key, generated by the KMS,
|
// GenerateKey returns a new plaintext key, generated by the KMS,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user