Using IAM Roles Anywhere

Relying on Private Key Infrastructure to Authenticate to AWS

Posted by Steven Tan on 1st August 2022

What is Roles Anywhere?

Roles Anywhere is a newly released AWS service that allows you to use your private key infrastructure (PKI) to generate temporary credentials for accessing IAM roles from outside of AWS.

You can use AWS Identity and Access Management Roles Anywhere to obtain temporary security credentials in IAM for workloads such as servers, containers, and applications that run outside of AWS. Your workloads can use the same IAM policies and IAM roles that you use with AWS applications to access AWS resources. Using IAM Roles Anywhere means you don't need to manage long-term credentials for workloads running outside of AWS.

By relying on your private Certificate Authority (CA), you can generate and revoke certificates for your workloads without having to use long-lived IAM keys. To get started, you can either choose to use the ACM Private Certificate Authority service offered to you by AWS (a fully managed certificate authority that provides PKI functionality) or generate your own CA.

Requirements

Your own Private Key Infrastructure

For the purposes of this post, I will be using cfssl, a tool created by CloudFlare to manage my private CA. Another alternative you can use for a more scalable solution is Vault PKI.

# Linux
$ go install github.com/cloudflare/cfssl/cmd/cfssl@latest
$ go install github.com/cloudflare/cfssl/cmd/cfssljson@latest
# Mac
$ brew install cfssl

And to use the certificates generated by your private CA, you will need to use the credential helper tool that IAM Roles Anywhere provides.

Using ACM Private CA

Incase you would prefer to use the ACM Private CA service, you can follow the ACM Private Certificate Authority documentation to provision a private CA and generate and export your certificates.

This will mean you can skip the "Getting Started" section and head straight for the "Configuring Roles Anywhere" section. The only difference would be selecting the "AWS Certificate Manager Private CA" option for the Certificate authority source when prompted.

Creating a Trust Anchor (ACM)

Make sure to enable the Certificate Revocation List (CRL) distribution feature, and specify an s3 bucket to place the CRL files.

If you are only looking to trial the service, please be mindful of your bill as creating a Private CA will give you a free 30 day trial and then cost $400/month afterwards per CA.

Getting Started

Once we have the cfssl tooling installed, we can look at creating our certificate authority.

To do this, you will need to create a directory to hold your private CA and inside, a ca-csr.json file to generate the certificate signing request. This is the example I am using for my certificate authority.

ca-csr.json

{
    "hosts": [
        "sktan.cloud"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C":  "AU",
            "L":  "Sydney",
            "O":  "Sktan Cloud",
            "OU": "AWS Roles Anywhere"
        }
    ]
}

Using the contents JSON file shown above, we can now generate our CA:

steven.tan ➜ ~/Downloads/cfssl/ca $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
steven.tan ➜ ~/Downloads/cfssl/ca $ ls -lh 
-rw-r--r--  1 steven.tan  staff   334B  8 Jul 02:42 ca-csr.json
-rw-------  1 steven.tan  staff   1.6K  8 Jul 11:35 ca-key.pem
-rw-r--r--  1 steven.tan  staff   1.0K  8 Jul 11:35 ca.csr
-rw-r--r--  1 steven.tan  staff   1.2K  8 Jul 11:35 ca.pem

Configuring Roles Anywhere

Once you have your CA files, we can start using this to configure our IAM Roles Anywhere trust anchor. The trust anchor establishes a trust between the IAM Roles Anywhere service and the CA that is used to sign the certificates.

Roles Anywhere UI

Creating a Trust Anchor

By browsing to the Roles Anywhere Page in the AWS Console, you can start to configure the trust anchor.

Creating a Trust Anchor

In the "Create a trust anchor" page, you can paste in the contents of your ca.pem file and click "Create trust anchor" and if the trust anchor is created successfully, you will see a message that says "Trust anchor created successfully".

Created the Trust Anchor

Creating your Profile

Prior to creating your profile, a role with a trust relationship with the IAM Roles Anywhere Service will need to be configured:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "rolesanywhere.amazonaws.com"
                ]
            },
            "Action": [
              "sts:AssumeRole",
              "sts:TagSession",
              "sts:SetSourceIdentity"
            ]
        }
    ]
}

Once the trust anchor has been created and a role has been setup, you can create a profile for your workload. This will provide permissions to AWS services when using the temporary credentials generated by Roles Anywhere.

Creating a Profile

Roles Anywhere Configuration Completed

If all steps have been performed successfully, you should see this page pop up.

Created a Profile

Creating a Workload Certificate (Own PKI)

Once the Roles Anywhere has been configured you will then be able to generate certificates for authentication.

Let's use the cfssl tool to sign a certificate for my role:

steven.tan ➜ ~/Downloads/cfssl $ cat csr.json
{
    "CN": "myworkload.sktan.cloud",
    "names": [
        {
            "C":  "AU",
            "L":  "Sydney",
            "O":  "Sktan Cloud",
            "OU": "AWS Roles Anywhere"
        }
    ]
}
steven.tan ➜ ~/Downloads/cfssl/client $ cfssl gencert -ca ../ca/ca.pem -ca-key ../ca/ca-key.pem client/csr.json | cfssljson -bare
2022/07/08 02:08:23 [INFO] generate received request
2022/07/08 02:08:23 [INFO] received CSR
2022/07/08 02:08:23 [INFO] generating key: ecdsa-256
2022/07/08 02:08:23 [INFO] encoded CSR
2022/07/08 02:08:23 [INFO] signed certificate with serial number 139205722987823629411099142929734817719202654388
2022/07/08 02:08:23 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
steven.tan ➜ ~/Downloads/cfssl/client $ ls -lah
total 32
drwxr-xr-x  6 steven.tan  staff   192B  8 Jul 12:09 .
drwxr-xr-x  6 steven.tan  staff   192B  8 Jul 12:09 ..
-rw-------  1 steven.tan  staff   227B  8 Jul 12:08 cert-key.pem
-rw-r--r--  1 steven.tan  staff   485B  8 Jul 12:08 cert.csr
-rw-r--r--  1 steven.tan  staff   1.1K  8 Jul 12:08 cert.pem
-rw-r--r--  1 steven.tan  staff   205B  8 Jul 12:04 csr.json

Validating the Solution

To validate that this has all worked successfully, you can quickly by using the aws_signing_helper to generate temporary credentials. For this, you will need 3 ARNs and the paths to your workload certificate and private key:

  1. The ARN of your Roles Anywhere trust anchor arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl
  2. The ARN of your Roles Anywhere profile arn:aws:rolesanywhere:ap-southeast-2:01234567890:profile/abcd-efghi-jkl
  3. The role ARN that you would like to use arn:aws:iam::01234567890:role/sktan-rolesanywhere-testrole
steven.tan ➜ ~/Downloads/cfssl $ ./aws_signing_helper credential-process \
    --certificate /Users/steven.tan/Downloads/cfssl/client/cert.pem \
    --private-key /Users/steven.tan/Downloads/cfssl/client/cert-key.pem \
    --trust-anchor-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl \
    --profile-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:profile/abcd-efghi-jkl \
    --role-arn arn:aws:iam::01234567890:role/sktan-rolesanywhere-testrole
{"Version":1,"AccessKeyId":"**********","SecretAccessKey":"**********","SessionToken":"**********","Expiration":"2022-07-08T03:12:48Z"}

If you successfully receive a response with the credentials, you can configure an AWS profile on the workload machine and run awscli commands to test the solution.:

steven.tan ➜ ~/Downloads/cfssl $ cat ~/.aws/config
[profile sktan-rolesanywhere-testprofile]
credential_process = ./aws_signing_helper credential-process --certificate /Users/steven.tan/Downloads/cfssl/client/cert.pem --private-key /Users/steven.tan/Downloads/cfssl/client/cert-key.pem --trust-anchor-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl  --profile-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:profile/abcd-efghi-jkl --role-arn arn:aws:iam::01234567890:role/sktan-rolesanywhere-testrole
steven.tan ➜ ~/Downloads/cfssl $ aws s3 ls --profile sktan-rolesanywhere-testprofile s3://sktan-rolesanywhere-testbucket
2022-07-08 11:04:39         12 test.txt

Revoking a Certificate

If you find yourself needing to revoke a certificate for any reason, IAM Role Anywhere supports the revocation of certificates by importing a CRL file in x509 format to the Roles Anywhere service. Though this means that the OCSP or CRL URLs provided in the certificate x509 extensions will not be checked automatically.

All generated CRL files must be imported into the Roles Anywhere service to be used, and then enabled.

ACM Private CA

To revoke a certificate, you will need to do it via the AWS CLI. Grab the Certificate Authority ARN and the certificate serial you wish to revoke, and run the following command:

$ aws acm-pca revoke-certificate \
     --certificate-authority-arn arn:aws:acm-pca:region:account:certificate-authority/CA_ID \
     --certificate-serial serial_number \
     --revocation-reason "KEY_COMPROMISE" 

Once this you have revoked the certificate, you will be able to find the revoked certificates in the S3 bucket you specified as part of the ACM Private CA configuration:

steven.tan ➜ ~/Downloads/cfssl $ aws s3 ls s3://sktan-rolesanywhere-crl-acmpca/crl/
2022-08-01 23:44:50        510 edd884f6-a913-45f3-8872-f74aceceed9d.crl

Your own PKI

If you want to revoke a certificate, then you will need to use the gencrl command to create the CRL file:

steven.tan ➜ ~/Downloads/cfssl $ cfssl certinfo -cert client/cert.pem | jq -r ".serial_number"
139205722987823629411099142929734817719202654388
steven.tan ➜ ~/Downloads/cfssl $ echo "139205722987823629411099142929734817719202654388" >> serials.txt
steven.tan ➜ ~/Downloads/cfssl $ cfssl gencrl serials.txt ca/ca.pem ca/ca-key.pem | base64 -D > roles-anywhere.crl
steven.tan ➜ ~/Downloads/cfssl $ openssl crl -inform DR -in roles-anywhere.crl -outform PEM -out crl.pem 
steven.tan ➜ ~/Downloads/cfssl $ cat ca/ca.pem crl.pem > crl_chain.pem                                 
steven.tan ➜ ~/Downloads/cfssl $ openssl verify -crl_check -CAfile crl_chain.pem client/cert.pem                 
client/cert.pem: C = AU, L = Sydney, O = Sktan Cloud, OU = AWS Roles Anywhere, CN = myworkload.sktan.cloud
error 23 at 0 depth lookup:certificate revoked

Using the output above, we have verified that the certificate has been revoked both locally and using the remote CRL file.

Importing the CRL to Roles Anywhere

Once you have generated your CRL file, you can then import this into AWS. At the moment, this can only be done either programatically or via the CLI.

The CRL file must be in the x509 format which looks like this:

-----BEGIN X509 CRL-----
MIIB+jCB4wIBATANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQKDAtTa3RhbiBDbG91
ZBcNMjIwNzA4MDcyOTQ4WhcNMjIwNzA5MDgyOTQ4WjBjMDACEQD1NyZku3t+/UoF
CEH0lLDFFw0yMjA3MDgwNjU0MTdaMAwwCgYDVR0VBAMKAQEwLwIQBaTwb/aRKkUs
OlSjDgwsUxcNMjIwNzA4MDgyNTA3WjAMMAoGA1UdFQQDCgEBoDQwMjAPBgNVHRQE
CAIGAYHc7es4MB8GA1UdIwQYMBaAFM53CYqWoYdw4PZavgnUFiQQhS5sMA0GCSqG
SIb3DQEBCwUAA4IBAQAUarvuxO9PPcyWN4svpdNmX+ADFGG+sVM0rt0NOnm12oZJ
hedNcBaHLlUDUDEpH/bxdqdNsS3fkNxBQVgUvpxpnSs50T3rgY52BPK6/RWTWtJF
44Uv6OLCJt3WHfg6dExbh82ddW2f4XIraKQyeKMXPZxX8HJSXrbdwLEzqnLAJmY1
JlqgdC+v3u6l1KqHklGthEQ21dMhMM+EUtokoz2+UzSldhF9X1VLwPNZuIgXXFJg
yyaWC3PojW9DjDNCshjmy7jyRkXGSOur6jPZqUuOSkDzsyCNP4cPhRV8yGABSxQb
8v/9x+pWY9GCimgRN6vahxZna3M+bTm+OQd55QZb
-----END X509 CRL-----

When downloading or generating a CRL file, you may notice that you get a binary file. This will need to be converted into the x509 format by base64 encoding the contents of the file and wrapping it with the "BEGIN" and "END" CRL lines:

steven.tan ➜ ~/Downloads/cfssl $ echo "-----BEGIN X509 CRL-----" > edd884f6-a913-45f3-8872-f74aceceed9d.crl.pem              
steven.tan ➜ ~/Downloads/cfssl $ base64 edd884f6-a913-45f3-8872-f74aceceed9d.crl >> edd884f6-a913-45f3-8872-f74aceceed9d.crl.pem
steven.tan ➜ ~/Downloads/cfssl $ echo "-----END X509 CRL-----" >> edd884f6-a913-45f3-8872-f74aceceed9d.crl.pem

Once you have a x509 format CRL file, it can be imported using the following commands:

# Import a CRL file
steven.tan ➜ ~/Downloads/cfssl $ aws rolesanywhere import-crl --crl-data "$(base64 edd884f6-a913-45f3-8872-f74aceceed9d.crl.pem)" --name roles-anywhere --trust-anchor-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl 
{
    "crl": {
        "createdAt": "2022-08-01T13:41:37.874039+00:00",
        "crlArn": "arn:aws:rolesanywhere:ap-southeast-2:01234567890:crl/aa5cb381-0bbe-4cfc-89df-cf61f15c0752",
        "crlData": "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUIrakNCNHdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBV01SUXdFZ1lEVlFRS0RBdFRhM1JoYmlCRGJHOTFaQmNOTWpJd056QTRNRGN5T1RRNFdoY05Nakl3TnpBNU1EZ3lPVFE0V2pCak1EQUNFUUQxTnlaa3UzdCsvVW9GQ0VIMGxMREZGdzB5TWpBM01EZ3dOalUwTVRkYU1Bd3dDZ1lEVlIwVkJBTUtBUUV3THdJUUJhVHdiL2FSS2tVc09sU2pEZ3dzVXhjTk1qSXdOekE0TURneU5UQTNXakFNTUFvR0ExVWRGUVFEQ2dFQm9EUXdNakFQQmdOVkhSUUVDQUlHQVlIYzdlczRNQjhHQTFVZEl3UVlNQmFBRk01M0NZcVdvWWR3NFBaYXZnblVGaVFRaFM1c01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQVVhcnZ1eE85UFBjeVdONHN2cGRObVgrQURGR0crc1ZNMHJ0ME5Pbm0xMm9aSmhlZE5jQmFITGxVRFVERXBIL2J4ZHFkTnNTM2ZrTnhCUVZnVXZweHBuU3M1MFQzcmdZNTJCUEs2L1JXVFd0SkY0NFV2Nk9MQ0p0M1dIZmc2ZEV4Ymg4MmRkVzJmNFhJcmFLUXllS01YUFp4WDhISlNYcmJkd0xFenFuTEFKbVkxSmxxZ2RDK3YzdTZsMUtxSGtsR3RoRVEyMWRNaE1NK0VVdG9rb3oyK1V6U2xkaEY5WDFWTHdQTlp1SWdYWEZKZ3l5YVdDM1Bvalc5RGpETkNzaGpteTdqeVJrWEdTT3VyNmpQWnFVdU9Ta0R6c3lDTlA0Y1BoUlY4eUdBQlN4UWI4di85eCtwV1k5R0NpbWdSTjZ2YWh4Wm5hM00rYlRtK09RZDU1UVpiCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K",
        "crlId": "aa5cb381-0bbe-4cfc-89df-cf61f15c0752",
        "enabled": false,
        "name": "roles-anywhere",
        "trustAnchorArn": "arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl",
        "updatedAt": "2022-08-01T13:41:37.874039+00:00"
    }
}
# Use the crlId output from the previous command
steven.tan ➜ ~/Downloads/cfssl/acm-revok $ aws rolesanywhere enable-crl --crl-id aa5cb381-0bbe-4cfc-89df-cf61f15c0752
{
    "crl": {
        "createdAt": "2022-08-01T13:41:37.874039+00:00",
        "crlArn": "arn:aws:rolesanywhere:ap-southeast-2:01234567890:crl/aa5cb381-0bbe-4cfc-89df-cf61f15c0752",
        "crlData": "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUIrakNCNHdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBV01SUXdFZ1lEVlFRS0RBdFRhM1JoYmlCRGJHOTFaQmNOTWpJd056QTRNRGN5T1RRNFdoY05Nakl3TnpBNU1EZ3lPVFE0V2pCak1EQUNFUUQxTnlaa3UzdCsvVW9GQ0VIMGxMREZGdzB5TWpBM01EZ3dOalUwTVRkYU1Bd3dDZ1lEVlIwVkJBTUtBUUV3THdJUUJhVHdiL2FSS2tVc09sU2pEZ3dzVXhjTk1qSXdOekE0TURneU5UQTNXakFNTUFvR0ExVWRGUVFEQ2dFQm9EUXdNakFQQmdOVkhSUUVDQUlHQVlIYzdlczRNQjhHQTFVZEl3UVlNQmFBRk01M0NZcVdvWWR3NFBaYXZnblVGaVFRaFM1c01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQVVhcnZ1eE85UFBjeVdONHN2cGRObVgrQURGR0crc1ZNMHJ0ME5Pbm0xMm9aSmhlZE5jQmFITGxVRFVERXBIL2J4ZHFkTnNTM2ZrTnhCUVZnVXZweHBuU3M1MFQzcmdZNTJCUEs2L1JXVFd0SkY0NFV2Nk9MQ0p0M1dIZmc2ZEV4Ymg4MmRkVzJmNFhJcmFLUXllS01YUFp4WDhISlNYcmJkd0xFenFuTEFKbVkxSmxxZ2RDK3YzdTZsMUtxSGtsR3RoRVEyMWRNaE1NK0VVdG9rb3oyK1V6U2xkaEY5WDFWTHdQTlp1SWdYWEZKZ3l5YVdDM1Bvalc5RGpETkNzaGpteTdqeVJrWEdTT3VyNmpQWnFVdU9Ta0R6c3lDTlA0Y1BoUlY4eUdBQlN4UWI4di85eCtwV1k5R0NpbWdSTjZ2YWh4Wm5hM00rYlRtK09RZDU1UVpiCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K",
        "crlId": "aa5cb381-0bbe-4cfc-89df-cf61f15c0752",
        "enabled": true,
        "name": "roles-anywhere",
        "trustAnchorArn": "arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl",
        "updatedAt": "2022-08-01T13:45:45.547992+00:00"
    }
}

Once your CRL has been imported and enabled, you will find that attempting to authenticate via these certificates will no longer work.

steven.tan ➜ ~/Downloads/cfssl $ aws_signing_helper credential-process --certificate cert.pem --private-key key.pem --trust-anchor-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:trust-anchor/abcd-efghi-jkl --profile-arn arn:aws:rolesanywhere:ap-southeast-2:01234567890:profile/abcd-efghi-jkl --role-arn arn:aws:iam::01234567890:role/sktan-rolesanywhere-testrole
2022/08/01 23:45:48 AccessDeniedException: Certificate revoked