diff --git a/README.md b/README.md index 4e5b2b696..13e42bc2c 100644 --- a/README.md +++ b/README.md @@ -203,20 +203,24 @@ or until there are only resources with errors left. ### AWS Credentials -There are two ways to authenticate *aws-nuke*. There are static credentials and -profiles. The later one can be configured in the shared credentials file (ie +There are three ways to authenticate *aws-nuke*. There are static credentials, +assuming roles and profiles. The first two methods are passed in at the +command line. The third can be configured in the shared credentials file (ie `~/.aws/credentials`) or the shared config file (ie `~/.aws/config`). To use *static credentials* the command line flags `--access-key-id` and `--secret-access-key` are required. The flag `--session-token` is only required for temporary sessions. +To use *assumed roles* the command line flag `--assume-role-arn` is required. +If you rely on a secret +[external ID](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) +field for your role assumption, you can supply it with the command line flag `--external-id`. + To use *shared profiles* the command line flag `--profile` is required. The -profile must be either defined with static credentials in the [shared -credential -file](https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html) -or in [shared config -file](https://docs.aws.amazon.com/cli/latest/userguide/cli-roles.html) with an +profile must be either defined with static credentials in the +[shared credential file](https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html) +or in [shared config file](https://docs.aws.amazon.com/cli/latest/userguide/cli-roles.html) with an assuming role. ### Using custom AWS endpoint diff --git a/cmd/root.go b/cmd/root.go index 627722ac3..8d846cae9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -122,6 +122,11 @@ func NewRootCommand() *cobra.Command { "AWS IAM role arn to assume. "+ "The credentials provided via --access-key-id or --profile must "+ "be allowed to assume this role. ") + command.PersistentFlags().StringVar( + &creds.ExternalId, "external-id", "", + "AWS STS External ID parameter. "+ + "If your assumed role is secured with an External ID string, "+ + "pass this parameter. ") command.PersistentFlags().StringVar( &defaultRegion, "default-region", "", "Custom default region name.") diff --git a/pkg/awsutil/session.go b/pkg/awsutil/session.go index b2bfd2dc8..d414f1032 100644 --- a/pkg/awsutil/session.go +++ b/pkg/awsutil/session.go @@ -37,6 +37,7 @@ type Credentials struct { SecretAccessKey string SessionToken string AssumeRoleArn string + ExternalId string Credentials *credentials.Credentials @@ -52,6 +53,10 @@ func (c *Credentials) HasAwsCredentials() bool { return c.Credentials != nil } +func (c *Credentials) HasExternalId() bool { + return strings.TrimSpace(c.ExternalId) != "" +} + func (c *Credentials) HasKeys() bool { return strings.TrimSpace(c.AccessKeyID) != "" || strings.TrimSpace(c.SecretAccessKey) != "" || @@ -114,7 +119,15 @@ func (c *Credentials) rootSession() (*session.Session, error) { // if given a role to assume, overwrite the session credentials with assume role credentials if c.AssumeRoleArn != "" { - sess.Config.Credentials = stscreds.NewCredentials(sess, c.AssumeRoleArn) + if c.HasExternalId() { + log.Debugf("assuming role %s, externalID found", c.AssumeRoleArn) + sess.Config.Credentials = stscreds.NewCredentials(sess, c.AssumeRoleArn, func(p *stscreds.AssumeRoleProvider) { + p.ExternalID = &c.ExternalId + }) + } else { + log.Debugf("assuming role %s with no externalID", c.AssumeRoleArn) + sess.Config.Credentials = stscreds.NewCredentials(sess, c.AssumeRoleArn) + } } c.session = sess