Revert PR #7241 to fix vault renewal (#7259)

- 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.
master
poornas 6 years ago committed by kannappanr
parent 1e82c4a7c4
commit e098852a80
  1. 116
      cmd/crypto/vault.go

@ -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 {
if err != nil { v.secret = nil
return nil, err time.Sleep(retryDelay)
continue
} }
case renew := <-renewer.RenewCh(): if ok, err := s.TokenIsRenewable(); !ok || err != nil {
if renew.Secret == nil || renew.Secret.Auth == nil { v.secret = nil
return nil, ErrKMSAuthLogin continue
} }
return renew.Secret, nil ttl, err := s.TokenTTL()
if err != nil {
v.secret = nil
continue
}
v.secret = s
retryDelay = ttl / 2
time.Sleep(retryDelay)
} }
} }()
} }
// 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…
Cancel
Save