Skip to content

Instantly share code, notes, and snippets.

@lautarodragan
Last active June 8, 2023 19:18
Show Gist options
  • Save lautarodragan/2627838f87c96b7db6ce3e8ee6062eb8 to your computer and use it in GitHub Desktop.
Save lautarodragan/2627838f87c96b7db6ce3e8ee6062eb8 to your computer and use it in GitHub Desktop.
AWS CLI + Yubikey

Install YubiKey Manager

Yubico docs: https://developers.yubico.com/yubikey-manager/

Right now, Yubico distributes yubikey-manager under the official ppa yubico/stable for apt. Double-check this is still the case when you're reading this guide — you don't want to trust a non-official distribution of yubikey-manager.

sudo apt-add-repository ppa:yubico/stable
sudo apt update
sudo apt install yubikey-manager

The apt package is named yubikey-manager, but the cli it exposes is named ykman.

Create OTP MFA Account in AWS and your YubiKey

  1. Log into https://aws.amazon.com/
  2. Go to Security Credentials
  3. Under the Multi-factor authentication (MFA), click Assign MFA Device
  4. Give it whatever device name you wish.
  5. Under Select MFA device you need to choose Authenticator app. This is unintuitive UI, but it really means "OATH device". If you choose Hardware Device here, you'll only be able to use it when you log into aws in the browser, not in the terminal.
  6. Next screen will show you a QR which you can normally scan with your phone. You should also see a Show secret key button (visually rendered as a link). Click it, copy it and save it somewhere safe. You'll need this in the next step.
  7. Do not close this screen just yet.
  8. Set up an OATH account in your YubiKey device with the Secret Key you just obtained: ykman oath accounts add -t aws-otp <AWS_MFA_CODE>. aws-otp is the name of the account stored inside the YubiKey. We'll use aws-otp for this example, but it can be anything you want.
  9. Now the AWS UI will request that you type two consecutive MFA codes. Use ykman oath accounts code aws-otp once to get the first, then use the same command again several times until you get a new OTP.
  10. Hit Assign MFA and you're done!

Using the YubiKey

To get an OTP from your YubiKey you need to run ykman oath accounts code aws-otp.

You then need to run aws sts get-session-token --serial-number arn:aws:iam::000000000000:mfa/2fa-device-name --token-code $otp, where $otp is the OTP returned by ykman oath accounts code aws-otp and the value of --serial-number is the ARN of the OTP device you set up in aws.amazon.com.

aws sts get-session-token returns a new AccessKeyId, SecretAccessKey and SessionToken which you'll need to place into your ~/.aws/credentials file. Doing this by hand each time would make no sense, so here are two functions that do this for you :)

# This function will request you to touch your YubiKey and return the OTP created by it.
yubiotp() {
  ykman oath accounts code aws-otp | tee | tr -s " " | cut -d" " -f2
}

# This function will request you to touch your YubiKey 
# and then add a [mfa] section to ~/.aws/credentials and [profile mfa] to ~/.aws/config
# It needs an existing [default] profile with aws_access_key_id and aws_secret_access_key set
# that has access to the MFA device set up in AWS.
# Warning: if there's a [mfa] aws profile in your ~/.aws/credentials and/or .config, it'll be replaced.
awsotp() {
  echo "Logging-in to aws cli with Yubikey"

  local otp=$(yubiotp)
  echo "OTP: $otp"

  echo "Getting new settion token from AWS..."
  local json=$(aws sts get-session-token --serial-number arn:aws:iam::000000000000:mfa/2fa-device-name --token-code $otp)
  local AccessKeyId=$(echo $json | jq .Credentials.AccessKeyId | tr -d '"')
  local SecretAccessKey=$(echo $json | jq .Credentials.SecretAccessKey | tr -d '"')
  local SessionToken=$(echo $json | jq .Credentials.SessionToken | tr -d '"')

  echo "Configuring mfa profile..."
  aws configure set aws_access_key_id $AccessKeyId --profile mfa
  aws configure set aws_secret_access_key $SecretAccessKey --profile mfa
  aws configure set aws_session_token $SessionToken --profile mfa
  aws configure set region us-east-1 --profile mfa
  aws configure set output json --profile mfa

  echo "Success!"
}

You can copy-paste these two functions to your /.bashrc and just call awsotp from the terminal whenever you need a new AWS OTP.

Then just use the aws cli app normally, always passing --profile mfa like so:

aws ec2 describe-instances --region us-east-1 --profile mfa

Troubleshooting

If you get a PC/SC error like the following, the pcscd.socket is probably not running.

WARNING: PC/SC not available. Smart card (CCID) protocols will not function.
ERROR: Unable to list devices for connection
ERROR: Failed to connect to YubiKey.

Let's check it status:

$ systemctl status pcscd.socket
○ pcscd.socket - PC/SC Smart Card Daemon Activation Socket
     Loaded: loaded (/lib/systemd/system/pcscd.socket; enabled; vendor preset: enabled)
     Active: inactive (dead)
   Triggers: ● pcscd.service
     Listen: /run/pcscd/pcscd.comm (Stream)

Start it like so:

sudo systemctl start pcscd.socket

If the service is always inactive after rebooting, you may need to enable it:

sudo systemctl enable pcscd.socket

See this bug report for more info on this topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment