Using the AWS STS CLI to assume a role on the terminal
TLDR
The best solution in my opinion is to let the AWS CLI handle the STS AssumeRole call for you. How to set this up is detailed below.
Introduction
The AWS CLI is a very useful tool to have when working on AWS resources. The AWS CLI is very powerful and has commands for working with the various services in AWS.
Also a quick note: This information assumes you have set up your AWS CLI with credentials for a user in your AWS account.
AWS CLI Configuration
Relevant to this topic is how the AWS CLI stores its configuration. The documentation on the aws configure CLI tells us a good bit about how the AWS CLI stores configuration on disk.
Configuration data is stored by default in ~/.aws directory. Specifically:
~/.aws/credentials- Stores sensitive information like:
aws_access_key_idaws_secret_access_keyaws_session_token
- Stores sensitive information like:
~/.aws/config- Stores general settings not considered to be credentials like:
regionoutput- etc…
- Stores general settings not considered to be credentials like:
The best way to populate these files is to use the aws configure command to manipulate the configuration files. Specifically the set command abd the get command
An example of the set command would be:
# will set the aws_access_key_id to "my_aws_access_key_id" on the
# profile dev in the ~/.aws/credentials file
aws configure set aws_access_key_id "my_aws_access_key_id" --profile dev
You can also set things like region but the setting will be saved in the ~/.aws/config file because it is not a credentials setting.
Then using the get command will return the value to stdout:
# will get the aws_access_key_id from the
# profile dev in the ~/.aws/credentials file
aws configure set aws_access_key_id --profile dev
# outputs: "my_aws_access_key_id"
Using the AWS STS CLI to get assumed role credentials
The AWS STS AssumeRole command can be used like this:
aws sts assume-role \
--role-arn arn:aws:iam::AWS_ACCOUNT_NUMBER:role/ROLE-NAME \
--role-session-name "A-MEANINGFUL-SESSION-NAME"
Or if you are need to provide MFA credentials for the command
aws sts assume-role \
--role-arn arn:aws:iam::AWS_ACCOUNT_NUMBER:role/ROLE-NAME \
--role-session-name "A-MEANINGFUL-SESSION-NAME" \
--serial-number arn:aws:iam::AWS_ACCOUNT_NUMBER:mfa/user \
--token-code 01234
Here are descriptions of the command parameters:
--role-arn- The ARN of the role you are attempting to assume.
--role-session-name- An arbitrary session name that will show in logs. I like to do a username-date format personally.
--serial-number- This is either the serial number of your MFA device, or the ARN or an MFA device registered in IAM.
--token-code- The current MFA code from your device.
More details can be found in the documentation.
If the command is successful you will get output that looks like this:
{
"Credentials": {
"AccessKeyId": "SENSITIVE_VALUE",
"SecretAccessKey": "SENSITIVE_VALUE",
"SessionToken": "LONG_SENSITIVE_VALUE",
"Expiration": "2023-08-06T20:06:29+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "A_UNIQUE_ID_GENERATED_BY_AWS",
"Arn": "ARN_OF_THE_ASSUMED_ROLE_USER"
}
}
With the values in the Credentials object we can use these credentials several ways to perform actions under our newly assumed role!
Do note that the credentials do expire. When they will expire is shows in the Credentials.Expiration field in the output of the STS AssumeRole command output. The duration of a assumed role can be changed via the --duration-seconds argument to the STS AssumeRole Command
Additionally there are other useful arguments that can be passed into the STS AssumeRole command like --policy-arns or --policy which each allow you to only allow the intersection of permissions between the assumed role. So only permissions that are assigned to the assumed role and the policy you pass in or specify.
See the documentation for more detailed descriptions of these and other arguments that the STS AssumeRole command can take.
Using the assumed role credentials
Now that we have our credentials we can assume our role a few different ways.
export ENV vars
We can export the AWS CLI ENV variables necessary to make any commands run from from our current terminal use our assumed role credentials.
These environment variables are:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKEN
Exporting these environment variables with the corresponding values from the output of the STS AssumeRole command will set your credentials for the specific terminal session you are using.
export AWS_ACCESS_KEY_ID=VALUE_FROM_ASSUMEROLE_OUTPUT
export AWS_SECRET_ACCESS_KEY=VALUE_FROM_ASSUMEROLE_OUTPUT
export AWS_SESSION_TOKEN=VALUE_FROM_ASSUMEROLE_OUTPUT
And viola you are now using the assumed role in your current terminal for AWS cli calls.
Add profile to AWS config files
Alternatively we can store the credentials from our STS AssumeRole command output we can put our credentials into our AWS config files using the aws configure set command while specifying the profile we want the credentials saved under
for example if we specify a profile named site-deployer:
aws configure set aws_access_key_id AWS_ACCESS_KEY_ID_FROM_OUTPUT --profile site-deployer
aws configure set aws_secret_access_key AWS_SECRET_ACCESS_KEY_FROM_OUTPUT --profile site-deployer
aws configure set aws_session_token AWS_SESSION_TOKEN_FROM_OUTPUT --profile site-deployer
This will allow you to use the --profile argument to specify the profile you wish to use for cli commands to use the profile you saved the assumed roles credentials to.
for example:
aws s3 ls SPECIFIC_BUCKET --profile site-deployer
will list all files in an S3 bucket with the name specified assuming the role assumed has permissions to list the contents of the bucket
Letting the AWS CLI seamlessly assume roles
It turns out all of the STS Assume role functionality can be transparently used by the AWS CLI if you have the proper configuration in you AWS CLI configuration files.
There are a few AWS documentation pages that are useful here:
- CLI Configuration Files documentation has details on various common properties in the AWS config files.
- CLI Configuring Roles documentation has specific details for how to configure roles to use seamless STS AssumeRole commands.
To quickly go over the details you need to set the following profile configuration values using the aws configure set command and the name of the profile you want to use from your AWS CLI Configuration files:
role_arn- Set to the ARN of the IAM role you wish to assume.
source_profile- Set to the profile name of the profile to use when assuming the role. This will often be
default.
- Set to the profile name of the profile to use when assuming the role. This will often be
mfa_serial- If you require MFA to assume the role.- The serial number of your physical MFA device or ARN of your virtual MFA device registered in IAM
- If this configuration value is set, the AWS CLI will automatically prompt you for your MFA code when a CLI command is trying to assume the role. The assumed credentials are cached, so you should not be prompted again until the current assumed credentials expire.
external_id- If you want to secure cross account role assuming. for more info see here.- An arbitrary secret shared with you by the owner of the account you are attempting to assume a role in. Only needed (for additional security) for cross account AssumeRole calls.
So for example:
# This sets the source_profile property in your ~/.aws/config file to default for the profile dev_admin
aws configure set source_profile default --profile dev_admin
There are other properties you may want to add like duration_seconds to try and specify a duration the role would be valid for. Other properties can be found in the documentation here.
With this configuration in place if you specify the profile to use AWS CLI command will automatically assume the role for that profile when commands are run.
Two ways you can set the profile when running AWS CLI commands are:
Assuming we are using the profile name dev_admin
- To use the
--profileargument for the AWS CLI Command you are using.
aws s3 ls --profile dev_admin
- Setting the
AWS_PROFILEenvironment variable with the name of the profile you which to use. Once this is set this is the profile that all AWS CLI commands will use in that terminal context.
export AWS_PROFILE=dev_admin
This is a seamless and robust way to assume roles with the AWS CLI and is my preferred method by far, especially if you are setting up tools for less technically adept users.
Verify you assumed the role
You can verify that you have properly assumed a role by calling the STS get-caller-identity command.
aws sts get-caller-identity
or if you did not set the appropriate environment variables you can manually specify the profile:
aws sts get-caller-identity --profile YOUR_PROFILE
and the output will look like this:
{
"UserId": "AIDASAMPLEUSERID",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/DevAdmin"
}
Where the values should correlate to the output from the STS AssumeRole command, specifically the AssumedRoleUser fields.
Other thoughts
I think the best method to use here is to let the AWS CLI handle the AssumeRole calls, but it is important for developers and cloud engineers to understand how the STS API works. Its worth trying the CLI manually just for the sake of learning.
When writing code its best to use the AWS SDK for your specific language. The STS AssumeRole command can be useful in applications as well, but I would use the SDK and not the CLI for these use cases.