It is a good practice to use temporary credentials in AWS instead of permanent IAM generated credentials that are long term and potentially leaked. AWS has different services that issue temporary credentials with given permission policies such as IAM Instance Profiles for EC2 instances, Lambda Execution Roles, ECS Task Roles, and IAM Roles Anywhere for those cases that require providing trusted access permissions to a process running outside of AWS.
One such way is to use the GenerateSessionToken
API
action in AWS Security Token Service to generate a pair of temporary
credentials with an expiry date. Doing so allows using AWS credentials without
having to hardcode long lived IAM credentials and worry about the
credentials getting leaked.
However, there’s a caveat when it comes to using credentials generated from
GenerateSessionToken
action. Unless the API action is executed with the MFA
token (for MFA enabled users), the generated credentials cannot be used to
invoke any IAM API calls. This would put a blocker for any use case you had for
running (ex:) IaC scripts with the temporary credentials.
I came across this scenario when using the popular aws-vault
tool generate
sessions with temporary credentials. aws-vault
also uses
GenerateSessionToken
, but it depends on the AWS configuration file
($HOME/.aws/config
) to provide the MFA configuraiton to it. Without the MFA
device serial and the token generation process defined in the config, it was generating
credentials that couldn’t perform any of the IAM API operations I needed.
One of the best ways to enable strong second factor authentication in AWS is to use a Yubikey device. However, the second factor authentication protocols supported by the AWS web console isn’t the same as the one supported by the AWS CLI and the SDKs. AWS web console supports FIDO-U2F, while the CLI and SDKs, based on the configuration, supports OATH-TOTP.
To get this working on the AWS CLI (and other tools that use the standard AWS SDKs), couple of steps need to be executed.
- Setup the CLI tool to generate the OATH-TOTP from the Yubikey
- Configure AWS configuration to point the MFA generation process to the OATH-TOTP generation tool
Prerequisites
- Supported Yubikey device
- AWS CLI or SDK based script
- AWS credentials with proper permissions to invoke
GetSessionToken
The following assumes an Ubuntu Linux environment, however other Linux distributions will also have the dependencies required for the Yubikey CLI tool.
Installing ykman
ykman
is the Yubico provided
CLI key management tool. Installing this on Ubuntu is straightforward.
# Install the dependencies needed
sudo apt update && \
sudo apt install pcscd libpcsclite-dev swig
# Install ykman
pip3 install yubikey-manager
Configuring MFA with OATH-TOTP
This step involves the following.
- Registering a new Virtual MFA device in AWS IAM
- Usig the Secret Key used in the process to register a new
oath
account inykman
- Configuring AWS config to use
ykman
as the command to generate the OATH-TOTP MFA
Navigate to the AWS IAM console and select the user that needs to register the
MFA device for CLI authentication. Select the Security Credentials tab and
then on Assign MFA Device button. Select Authenticator App as the
device and input a device name. Note down this name as we’ll be using it to
register the device on the ykman
end.
Proceed to the next step. AWS provides a QR code for an authenticator app to use, however for this use case, what’s useful is the secret key. Copy the secret key for the next step.
Open the terminal and execute the following command using the appropriate
values for account_id
and the device_name
(ex: ykman_test
).
ykman oath accounts add -t arn:aws:iam::account_id:mfa/device_id
ykman
will ask to input the (base32 encoded) secret key. Note that the value
copied from the AWS console is already base32 encoded so just directly paste
the value. This also specifies that the Yubikey should be touched to generate the key
by using the -t
flag.
Now two consecurtive OATH-TOTP codes should be generated and added to the console to finalise the device registration. However, instead of doing this immediately, I’ve experienced success by waiting a while (~5 minutes) for some unknown reason. I’m guessing this is related to the time window being populated someway, however whenever I’d immediately generate tokens, AWS would report them as invalid.
To generate a OATH-TOTP code, run the following command, again replacing
account_id
and device_id
with proper values. Wait 30 seconds before the
next token is generated since the time slice configuration is usually set to 30
seconds.
ykman oath accounts code --single arn:aws:iam::account_id:mfa/device_id
Now that the device is registered in ykman
and AWS, it can be directly used
when invoking GetSessionToken
action.
For the CLI command get-session-token
to use MFA in the process (in an AWS context with
proper permissions) the flags --serial-number
and --token-code
have to be
used, which will trigger the touch request. Not providing these two flags will
generate credentials without MFA.
The MFA device serial can be copied from the AWS IAM console.
aws sts get-session-token --serial-number arn:aws:iam::account_id:mfa/device_id \
--token-code $(ykman oath accounts code --single arn:aws:iam::account_id:mfa/device_id)
Additionally, for AssumeRole
operation, the MFA device and the code
generation command to use can be provided through the AWS config file. To do
this add mfa_serial
and mfa_process
directives
under the proper profile in $HOME/.aws/config
file (replacing
account_id
and device_id
with proper values).
[profile ccl-test]
region=ap-southeast-2
mfa_serial=arn:aws:iam::account_id:mfa/device_id
mfa_process=ykman oath accounts code --single arn:aws:iam::account_id:mfa/device_id
That’s it! That’s the entire process.
Now whenever temporary credentials are generated through AssumeRole
, the AWS
SDK credentials provider will use ykman
with the above command to trigger a
Yubikey touch to generate an OATH-TOTP
token, ensuring the temporary credentials are generated with MFA involved.