Posted on 15 July 2020, updated on 21 December 2023.
Software that interacts with the AWS API needs to perform authentication before sending any meaningful requests. On larger projects that have strong security requirements or that use multiple AWS accounts, handling intricate mechanisms like multi-factor authentication or chained role assumptions can make your code complex and harder to maintain.
Basic use of AWS profiles
AWS profiles exist in the ~/.aws/credentials
on your machine. The simplest use-case is to write your AWS credentials like this:
This defines a profile called padok
that you can use everywhere. In a bash script…
In a Go program…
In your Terraform code, to configure a state backend…
Or to configure a Terraform resource provider…
Or even multiple Terraform resource providers at once…
The whole point is that all your code ever needs is the name of your AWS profile. From there, AWS libraries automatically get all the information required to authenticate from the ~/.aws/credentials
file.
Assuming AWS IAM roles
AWS IAM roles are often used to gain certain privileges on other AWS accounts. You can assume a role in many ways, but most involve doing it explicitly every time you need to use a certain role. This is absolutely feasible but AWS profiles allow you to configure authentication with role assumptions once and then forget about it.
Building on the padok
profile from earlier, I can create two new profiles — padok_staging
and padok_production
— that each uses a different role in a different AWS account.
Before you can assume a role, you need to be authenticated as a user. The source_profile
field tells the AWS library which profile provides my user’s credentials. Once authenticated, the library assumes the role specified in the role_arn
field.
I can use the padok_production
profile in my code just as I used the padok
profile in the examples above, and all my requests to the AWS API will seamlessly be made using the role specified in the ~/.aws/credentials
file.
Did you know that once you have assumed an AWS IAM role, you can use that role to assume another one? This is called role chaining, and can be very useful in larger organisations where people require different sets of permissions on multiple projects.
With AWS profiles, role chaining is simple to set up. The source_profile
and role_arn
fields are all you need.
With this setup, my AWS IAM user has permission to assume a role in account 000011112222
. I can then use this role to assume roles in accounts 333344445555
or 666677778888
. I can use padok_production_alpha
and padok_production_bravo
interchangeably whenever I need to access different production environments.
Despite the complexity of the authentication method used, my code remains clean and simple: all I need to specify is the name of the profile to use.
Multi-factor authentication
When users have access to production environments, it is often best to set up multi-factor authentication — or MFA, for short — as an extra layer of security. However, when a developer wishes to run code that uses the AWS API, MFA can be an obstacle and slow the developer down.
To perform MFA, you need two things: your MFA device serial number and the seed used to generate one-time passwords. These parameters should have been provided to you by your system administrator when you were setting up your AWS user.
Useful tip: if you scanned a QR code to set up one-time passwords on an app, that QR code contained the seed to use.
You can add these parameters to your ~/.aws/credentials
file in the same profile that contains the usual AWS credentials for your user.
Notice that we also added an empty profile called padok_mfa
. This is important, so be sure to add it.
For one of our client’s projects, we wrote a simple shell script that reads the MFA serial number and seed from the padok
profile, performs multi-factor authentication, and writes usable credentials in the padok_mfa
profile. Feel free to use it by writing it to ~/.aws/update-credentials.sh. Remember to make the file executable.
For this script to work, you will need to have the aws
, jq
, and oathtool
commands available. On OS X, you can install them by running brew install awscli jq oath-toolkit
.
Once you have run this script, you should see that the padok_mfa
profile has been updated in your ~/.aws/credentials
file.
You can now use the padok_mfa
profile as you would any other AWS profile. Whether or not you use multi-factor authentication will have no impact on your code beyond the name of the profile you use.
One drawback is that the credentials obtained when performing MFA expire after an hour. In order to avoid having to run the script manually over and over, you can add the following entry to your crontab so that it runs automatically every 30 minutes.
Now you never have to worry about MFA again.
Everything at once
What if you need to perform multi-factor authentication and then assume a role, or even chain roles? Can that be expressed inside your ~/.aws/credentials
file? Absolutely.
You can use padok_mfa
as the source_profile
of another profile, and then chain role assumptions exactly like before.
While your ~/.aws/credentials
file does have some added complexity, it provides a simple and powerful abstraction so that your software does not need to manage complex authentication mechanisms. All your code will ever need is the name of the AWS profile to use.
At Padok, we use abstractions like this one every day to make sure the code we write is maintainable and that our SREs are as productive as possible.