In the second post of this series, I described how I set up my development environment using aws-google-auth. If it wasn’t for the tool, I would not be able to leverage the federation I set up between my GSuite and AWS accounts for use through the AWS CLI.

In this post, I’ll provide details on how I configured the relationships between the accounts, so that I can use them at ease without having to change any configuration files to switch from one to the other.

With SSO configured between GSuite, and my AWS Gate account, I can now perform role assumption to any role in any account that I have permission to, through either the web console, or the CLI.

In the screenshot below, note that AWS identifies the loggeed in user as the role that was assumed through the federation, and the active user as the role assumed. In this case, the role assumed happened to be in the same account.

In this screenshot, note that the account is different, while maintaining that my original authentication identity was the role assumed through the federation.

In terms of auditing, and non-repudiation, it’s imperative that the original authentication be maintained. I will dive deeper into the association between the original authenticated account, and subsequent assumed roles as they relate to Cloudtrail events in a future post.

At the end of the last post in this series, we used the aws command line by passing a profile alias, issuing the get-caller-identity subcommand to STS. We’ll expand upon that now to make calls in other accounts, with alternate assumed roles.

To leverage role dependency from the CLI, you will need to configure the relationships in your ~/.aws/config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[profile sso]
region = us-east-1
google_config.ask_role = False
google_config.duration = 14400
google_config.google_idp_id = redacted
google_config.role_arn = arn:aws:iam::account-1:role/saml-sts
google_config.google_sp_id = redacted
google_config.u2f_disabled = False
google_config.google_username = armen@kriation.com

[profile security-admin]
region = us-east-1
role_arn = arn:aws:iam::account-1:role/security/security-admin
source_profile = sso

[profile central-poweruser]
region = us-east-1
role_arn = arn:aws:iam::account-2:role/account/account-poweruser
source_profile = sso

Lines 1-9 are the same as those that were in the last post. The name-value pairs in that section provide both aws-google-auth and the awscli with the necessary parameters to handle authentication through the command line. When I pass –profile sso to the awscli, it references the definition in the config, as well as the values set in ~/.aws/credentials for the profile. This design provides a convenience to the developer by handling the overhead of credential management.

To enable action against other accounts and/or with alternate privilege, the required dependency is on lines 14 and 19 for each profile. source_profile1 directs the awscli to leverage the credential of the profile value provided to facilitate role assumption of the role_arn identified in the target profile.

Since the role assumption is occuring with the original authenticating identity, you’ll need to make sure that the trust relationship of the role is configured correctly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "Path": "/account/",
  "RoleName": "account-poweruser",
  "Arn": "arn:aws:iam::account-2:role/account/account-poweruser",
  "AssumeRolePolicyDocument": {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "AWS": "arn:aws:iam::account-1:role/saml-sts"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  },
}

Line 11 is the focus of the above block, as it is the source principal that can assume this role. The chain of trust contines upward to the trust relationship discussed in part 1 of this series, which is the federation. The single point of entry to any AWS account that adopts this structure is the account that you configure the federation in.

With the trust relationship configured in each account, and the roles defined so that they chain to the federated role, gaining access to any of the accounts from the CLI is now possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[~]$ aws --profile sso sts get-caller-identity
{
    "UserId":"redacted:armen@kriation.com",
    "Account": "account-1",
    "Arn": "arn:aws:sts::account-1:assumed-role/saml-sts/armen@kriation.com"
}
[~]$ aws --profile security-admin sts get-caller-identity
{
    "UserId": "redacted:botocore-session-redacted",
    "Account": "account-1",
    "Arn": "arn:aws:sts::account-1:assumed-role/security-admin/botocore-session-redacted"
}
[~]$ aws --profile central-poweruser sts get-caller-identity
{
    "UserId": "redacted:botocore-session-redacted",
    "Account": "account-2",
    "Arn": "arn:aws:sts::account-2:assumed-role/account-poweruser/botocore-session-redacted"
}
[~]$

The first output block is straight forward, as it indicates the caller as we already know. The second and third are more interesting because they are the result of a role assuming another role. The caller identity in both cases is botocore2 because it’s the one assuming the role with the credentials in ~/.aws/credentials from the initial role assumption of the federation.

In addition, you’ll notice when you view the credentials file after making the above calls, that the only credentials listed are those produced from the role assumption as a result of the federation. The credentials used for the other two calls are generated at runtime by botocore.

This design not only prevents credential sprawl, but it also ensures that the credentials written to disk in the credentials file have a short lifetime in case of a hardware compromise.

In this three part series, we set up a federation between GSuite and AWS, ensuring a single point of entry for single sign-on to the environment. Once configured, we were able to leverage the federation through the web console, as well as the AWS CLI, by using aws-google-auth, without which, this wouldn’t be possible.