Skip to content

Commit

Permalink
Merge pull request #498 from 99designs/fix-no-session
Browse files Browse the repository at this point in the history
Fix --no-session
  • Loading branch information
mtibben committed Jan 16, 2020
2 parents 7daf3aa + 59019c9 commit 62d5b2a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 159 deletions.
26 changes: 8 additions & 18 deletions cli/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/99designs/aws-vault/server"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
"github.com/aws/aws-sdk-go/aws/credentials"
"gopkg.in/alecthomas/kingpin.v2"
)

Expand Down Expand Up @@ -50,7 +49,7 @@ func ConfigureExecCommand(app *kingpin.Application) {
Short('d').
DurationVar(&input.SessionDuration)

cmd.Flag("no-session", "Use master credentials, no session created").
cmd.Flag("no-session", "Don't create a session with GetSessionToken").
Short('n').
BoolVar(&input.NoSession)

Expand Down Expand Up @@ -93,28 +92,20 @@ func ExecCommand(input ExecCommandInput) error {
return fmt.Errorf("aws-vault sessions should be nested with care, unset $AWS_VAULT to force")
}

var setEnv = true

if input.NoSession && input.StartServer {
return fmt.Errorf("Can't start a credential server without a session")
}
vault.UseSession = !input.NoSession
setEnv := true

configLoader.BaseConfig = input.Config
configLoader.ProfileNameForEnv = input.ProfileName
configLoader.ActiveProfile = input.ProfileName
config, err := configLoader.LoadFromProfile(input.ProfileName)
if err != nil {
return err
}

credKeyring := &vault.CredentialKeyring{Keyring: input.Keyring}
var creds *credentials.Credentials
if input.NoSession {
creds = vault.NewMasterCredentials(credKeyring, config.ProfileName)
} else {
creds, err = vault.NewTempCredentials(input.ProfileName, credKeyring, configLoader)
if err != nil {
return fmt.Errorf("Error getting temporary credentials: %w", err)
}
creds, err := vault.NewTempCredentials(config, credKeyring)
if err != nil {
return fmt.Errorf("Error getting temporary credentials: %w", err)
}

val, err := creds.Get()
Expand All @@ -125,9 +116,8 @@ func ExecCommand(input ExecCommandInput) error {
if input.StartServer {
if err := server.StartCredentialsServer(creds); err != nil {
return fmt.Errorf("Failed to start credential server: %w", err)
} else {
setEnv = false
}
setEnv = false
}

if input.CredentialHelper {
Expand Down
6 changes: 3 additions & 3 deletions cli/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func ConfigureLoginCommand(app *kingpin.Application) {

func LoginCommand(input LoginCommandInput) error {
configLoader.BaseConfig = input.Config
configLoader.ProfileNameForEnv = input.ProfileName
configLoader.ActiveProfile = input.ProfileName
config, err := configLoader.LoadFromProfile(input.ProfileName)
if err != nil {
return err
Expand All @@ -74,9 +74,9 @@ func LoginCommand(input LoginCommandInput) error {

// if AssumeRole isn't used, GetFederationToken has to be used for IAM credentials
if config.RoleARN == "" {
creds, err = vault.NewFederationTokenCredentials(input.ProfileName, input.Keyring, configLoader)
creds, err = vault.NewFederationTokenCredentials(input.ProfileName, input.Keyring, config)
} else {
creds, err = vault.NewTempCredentials(input.ProfileName, input.Keyring, configLoader)
creds, err = vault.NewTempCredentials(config, input.Keyring)
}
if err != nil {
return err
Expand Down
15 changes: 8 additions & 7 deletions cli/rotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func ConfigureRotateCommand(app *kingpin.Application) {

cmd := app.Command("rotate", "Rotates credentials")

cmd.Flag("no-session", "Use master credentials, no session created").
cmd.Flag("no-session", "Use master credentials, no session or role used").
Short('n').
BoolVar(&input.NoSession)

Expand All @@ -42,16 +42,17 @@ func ConfigureRotateCommand(app *kingpin.Application) {
}

func RotateCommand(input RotateCommandInput) error {
vault.UseSession = !input.NoSession
vault.UseSessionCache = false

configLoader.BaseConfig = input.Config
configLoader.ProfileNameForEnv = input.ProfileName
configLoader.ActiveProfile = input.ProfileName
config, err := configLoader.LoadFromProfile(input.ProfileName)
if err != nil {
return err
}

masterCredentialsName, err := vault.MasterCredentialsFor(input.ProfileName, input.Keyring, configLoader)
masterCredentialsName, err := vault.MasterCredentialsFor(input.ProfileName, input.Keyring, config)
if err != nil {
return err
}
Expand All @@ -77,7 +78,7 @@ func RotateCommand(input RotateCommandInput) error {
if input.NoSession {
sessCreds = vault.NewMasterCredentials(input.Keyring, config.ProfileName)
} else {
sessCreds, err = vault.NewTempCredentials(input.ProfileName, input.Keyring, configLoader)
sessCreds, err = vault.NewTempCredentials(config, input.Keyring)
if err != nil {
return fmt.Errorf("Error getting temporary credentials: %w", err)
}
Expand Down Expand Up @@ -165,7 +166,7 @@ func retry(maxTime time.Duration, sleep time.Duration, f func() error) (err erro
}
}

func getUsernameIfAssumingRole(sess *session.Session, config vault.Config) (*string, error) {
func getUsernameIfAssumingRole(sess *session.Session, config *vault.Config) (*string, error) {
if config.RoleARN != "" {
n, err := vault.GetUsernameFromSession(sess)
if err != nil {
Expand All @@ -185,8 +186,8 @@ func getProfilesInChain(profileName string, configLoader *vault.ConfigLoader) (p
return profileNames, err
}

if config.SourceProfile != "" {
newProfileNames, err := getProfilesInChain(config.SourceProfile, configLoader)
if config.SourceProfile != nil {
newProfileNames, err := getProfilesInChain(config.SourceProfileName, configLoader)
if err != nil {
return profileNames, err
}
Expand Down
96 changes: 45 additions & 51 deletions vault/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,6 @@ import (
)

const (
// MinGetSessionTokenDuration is the AWS minumum duration for GetSessionToken
MinGetSessionTokenDuration = time.Minute * 15
// MaxGetSessionTokenDuration is the AWS maximum duration for GetSessionToken
MaxGetSessionTokenDuration = time.Hour * 36

// MinAssumeRoleDuration is the AWS minumum duration for AssumeRole
MinAssumeRoleDuration = time.Minute * 15
// MaxAssumeRoleDuration is the AWS maximum duration for AssumeRole
MaxAssumeRoleDuration = time.Hour * 12

// MinGetFederationTokenDuration is the AWS minumum duration for GetFederationToke
MinGetFederationTokenDuration = time.Minute * 15
// MaxGetFederationTokenDuration is the AWS maximum duration for GetFederationToke
MaxGetFederationTokenDuration = time.Hour * 36

// DefaultSessionDuration is the default duration for GetSessionToken or AssumeRole sessions
DefaultSessionDuration = time.Hour * 1

Expand Down Expand Up @@ -240,12 +225,9 @@ func (c *ConfigFile) ProfileNames() []string {

// ConfigLoader loads config from configfile and environment variables
type ConfigLoader struct {
BaseConfig Config
File *ConfigFile

// profile env should be applied to
ProfileNameForEnv string

BaseConfig Config
File *ConfigFile
ActiveProfile string
visitedProfiles []string
}

Expand Down Expand Up @@ -307,8 +289,8 @@ func (cl *ConfigLoader) populateFromConfigFile(config *Config, profileName strin
if config.AssumeRoleDuration == 0 {
config.AssumeRoleDuration = time.Duration(psection.DurationSeconds) * time.Second
}
if config.SourceProfile == "" {
config.SourceProfile = psection.SourceProfile
if config.SourceProfileName == "" {
config.SourceProfileName = psection.SourceProfile
}

if psection.ParentProfile != "" {
Expand Down Expand Up @@ -372,7 +354,7 @@ func (cl *ConfigLoader) populateFromEnv(profile *Config) {
}

// AWS_ROLE_ARN and AWS_ROLE_SESSION_NAME only apply to the target profile
if profile.ProfileName == cl.ProfileNameForEnv {
if profile.ProfileName == cl.ActiveProfile {
if roleARN := os.Getenv("AWS_ROLE_ARN"); roleARN != "" && profile.RoleARN == "" {
log.Printf("Using role_arn %q from AWS_ROLE_ARN", roleARN)
profile.RoleARN = roleARN
Expand All @@ -385,26 +367,38 @@ func (cl *ConfigLoader) populateFromEnv(profile *Config) {
}
}

func (cl *ConfigLoader) hydrateSourceConfig(config *Config) error {
if config.SourceProfileName != "" {
sc, err := cl.LoadFromProfile(config.SourceProfileName)
if err != nil {
return err
}
sc.ChainedFromProfile = config
config.SourceProfile = sc
}
return nil
}

// LoadFromProfile loads the profile from the config file and environment variables into config
func (cl *ConfigLoader) LoadFromProfile(profileName string) (Config, error) {
func (cl *ConfigLoader) LoadFromProfile(profileName string) (*Config, error) {
config := cl.BaseConfig
config.ProfileName = profileName
cl.populateFromEnv(&config)

cl.resetLoopDetection()
err := cl.populateFromConfigFile(&config, profileName)
if err != nil {
return Config{}, err
return nil, err
}

cl.populateFromDefaults(&config)

err = config.Validate()
err = cl.hydrateSourceConfig(&config)
if err != nil {
return Config{}, err
return nil, err
}

return config, nil
return &config, nil
}

// Config is a collection of configuration options for creating temporary credentials
Expand All @@ -413,7 +407,13 @@ type Config struct {
ProfileName string

// SourceProfile is the profile where credentials come from
SourceProfile string
SourceProfileName string

// SourceProfile is the profile where credentials come from
SourceProfile *Config

// ChainedFromProfile is the profile that used this profile as it's source profile
ChainedFromProfile *Config

// Region is the AWS region
Region string
Expand Down Expand Up @@ -441,26 +441,20 @@ type Config struct {
GetFederationTokenDuration time.Duration
}

// Validate checks that the Config is valid
func (cl *Config) Validate() error {
if cl.GetSessionTokenDuration < MinGetSessionTokenDuration {
return fmt.Errorf("Minimum GetSessionToken duration is %s", MinGetSessionTokenDuration)
}
if cl.GetSessionTokenDuration > MaxGetSessionTokenDuration {
return fmt.Errorf("Maximum GetSessionToken duration is %s", MaxGetSessionTokenDuration)
}
if cl.AssumeRoleDuration < MinAssumeRoleDuration {
return fmt.Errorf("Minimum AssumeRole duration is %s", MinAssumeRoleDuration)
}
if cl.AssumeRoleDuration > MaxAssumeRoleDuration {
return fmt.Errorf("Maximum AssumeRole duration is %s", MaxAssumeRoleDuration)
}
if cl.GetFederationTokenDuration < MinGetFederationTokenDuration {
return fmt.Errorf("Minimum GetFederationToken duration is %s", MinAssumeRoleDuration)
}
if cl.GetFederationTokenDuration > MaxGetFederationTokenDuration {
return fmt.Errorf("Maximum GetFederationToken duration is %s", MaxAssumeRoleDuration)
}
func (c *Config) IsChained() bool {
return c.ChainedFromProfile != nil
}

return nil
func (c *Config) HasSourceProfile() bool {
return c.SourceProfile != nil
}

func (c *Config) HasMfaSerial() bool {
return c.MfaSerial != ""
}

func (c *Config) MfaAlreadyUsedInSourceProfile() bool {
return c.HasSourceProfile() &&
c.MfaSerial != "" &&
c.SourceProfile.MfaSerial == c.MfaSerial
}
Loading

0 comments on commit 62d5b2a

Please sign in to comment.