diff --git a/vault/config.go b/vault/config.go index 079b550b2..28620b9f9 100644 --- a/vault/config.go +++ b/vault/config.go @@ -83,5 +83,5 @@ func FormatCredentialError(profileKey string, from Profiles, err error) string { sourceDescr, source) } - return fmt.Sprintf("Failed to get credentials for %s: %v", err, sourceDescr) + return fmt.Sprintf("Failed to get credentials for %s: %v", sourceDescr, err) } diff --git a/vault/provider.go b/vault/provider.go index 5c3417d56..5c1d65cae 100644 --- a/vault/provider.go +++ b/vault/provider.go @@ -87,42 +87,12 @@ func NewVaultProvider(k keyring.Keyring, profile string, opts VaultOptions) (*Va }, nil } +// Retrieve returns credentials protected by a GetSessionToken. If there is an associated +// role in the profile then AssumeRole is applied. The benefit of a session is that it doesn't +// require MFA or a user prompt to access the keychain item, much like sudo. func (p *VaultProvider) Retrieve() (credentials.Value, error) { - creds, err := p.getMasterCreds() - if err != nil { - return credentials.Value{}, err - } - - window := p.ExpiryWindow - if window == 0 { - window = time.Minute * 5 - } - if p.NoSession { - if role, ok := p.profiles[p.profile]["role_arn"]; ok { - session, err := p.assumeRole(creds, role) - if err != nil { - return credentials.Value{}, err - } - - log.Printf("Using role ****************%s, expires in %s", - (*session.AccessKeyId)[len(*session.AccessKeyId)-4:], - session.Expiration.Sub(time.Now()).String()) - - p.SetExpiration(*session.Expiration, window) - p.expires = *session.Expiration - - value := credentials.Value{ - AccessKeyID: *session.AccessKeyId, - SecretAccessKey: *session.SecretAccessKey, - SessionToken: *session.SessionToken, - } - - return value, nil - } - - // no role, exposes master credentials which don't expire - return creds, nil + return p.RetrieveWithoutSessionToken() } session, err := p.sessions.Retrieve(p.profile, p.SessionDuration) @@ -133,6 +103,12 @@ func (p *VaultProvider) Retrieve() (credentials.Value, error) { log.Println(err) } + // session lookup missed, we need to create a new one + creds, err := p.getMasterCreds() + if err != nil { + return credentials.Value{}, err + } + session, err = p.getSessionToken(&creds) if err != nil { return credentials.Value{}, err @@ -158,6 +134,11 @@ func (p *VaultProvider) Retrieve() (credentials.Value, error) { session.Expiration.Sub(time.Now()).String()) } + window := p.ExpiryWindow + if window == 0 { + window = time.Minute * 5 + } + p.SetExpiration(*session.Expiration, window) p.expires = *session.Expiration @@ -170,6 +151,48 @@ func (p *VaultProvider) Retrieve() (credentials.Value, error) { return value, nil } +// RetrieveWithoutSessionToken returns credentials that are either the master credentials or +// a session created with AssumeRole. This allows for usecases where a token created with AssumeRole +// wouldn't work. +func (p *VaultProvider) RetrieveWithoutSessionToken() (credentials.Value, error) { + log.Println("Skipping session token and using master credentials directly") + + creds, err := p.getMasterCreds() + if err != nil { + return credentials.Value{}, err + } + + if role, ok := p.profiles[p.profile]["role_arn"]; ok { + session, err := p.assumeRole(creds, role) + if err != nil { + return credentials.Value{}, err + } + + log.Printf("Using role ****************%s, expires in %s", + (*session.AccessKeyId)[len(*session.AccessKeyId)-4:], + session.Expiration.Sub(time.Now()).String()) + + window := p.ExpiryWindow + if window == 0 { + window = time.Minute * 5 + } + + p.SetExpiration(*session.Expiration, window) + p.expires = *session.Expiration + + value := credentials.Value{ + AccessKeyID: *session.AccessKeyId, + SecretAccessKey: *session.SecretAccessKey, + SessionToken: *session.SessionToken, + } + + return value, nil + } + + // no role, exposes master credentials which don't expire + return creds, nil +} + func (p *VaultProvider) getMasterCreds() (credentials.Value, error) { if p.MasterCreds != nil { return *p.MasterCreds, nil diff --git a/vault/sessions.go b/vault/sessions.go index 54f02fb0d..5dd351072 100644 --- a/vault/sessions.go +++ b/vault/sessions.go @@ -64,10 +64,11 @@ func (s *KeyringSessions) Store(profile string, session sts.Credentials, duratio log.Printf("Writing session for %s to keyring", profile) s.Keyring.Set(keyring.Item{ - Key: s.key(profile, duration), - Label: "aws-vault session for " + profile, - Data: bytes, - TrustSelf: true, + Key: s.key(profile, duration), + Label: "aws-vault session for " + profile, + Description: "aws-vault session for " + profile, + Data: bytes, + TrustSelf: false, }) return nil