openrolesanywhere is an open-source client for AWS IAM Roles Anywhere. Consider this project to be a proof-of-concept. It’s unlikely something that you would actually use in production, even if it technically works. It was more for my own education.

What and why?

The official client works, but has a few short-comings IMO. It’s not open source and it requires you to store private keys in plaintext on the filesystem. This project lets you use private keys stored in an SSH agent. This is more flexible – and more secure if you use something like Secretive which stores unexportable keys in the macOS Secure Enclave hardware.


First, we’re going to use an AWS KMS asymmetric key as the private key for our certificate authority[1]. Look at key.yml for an example KMS key to create.

Once you have the key ARN, we run the following command. It will create a new self-signed certificate (using the private key stored in KMS) and register it in Roles Anywhere as a trust anchor. The certificate will be stored in ~/.config/openrolesanywhere/ca.pem.

openrolesanywhere admin create-ca \
  --name NameOfYourChoiceForTrustAnchorInRolesAnywhere \ 
  --kms-key-id fecbd22d-c110-beef-cafe-7986a49ee7f0 \
  --validity-duration 8760h \
  --serial-number 12345 \
  --common-name whateverYouWant \
  [--organization org] \
  [--organization-unit unit] \
  [--country country] \
  [--locality locality] \
  [--province province] \
  [--street-address addr] \
  [--postal-code 1234]

Next, we create a profile. As best I can tell, this is a mapping from trust anchors to IAM roles. Run this:

openrolesanywhere admin create-profile \
  --name SomeProfileName \
  --session-duration 3600s \
  --role-arn arn:aws:iam::012345678912:role/SomeRoleName \
  --role-arn arn:aws:iam::012345678912:role/AnotherRoleName

Now we can start requesting certificates. First run ssh-add -l to get a list of fingerprints for the keys stored in your SSH agent. Mine looks like this:

256 SHA256:KBsk40KWP/UDoYoiFnpFk+z5JnMInwsrAFONMLrlryc ecdsa-sha2-nistp256 (ECDSA)
256 SHA256:z/A9nNwdk1ZTmwtdrAlF2JQnGS8C7V3ozOPMt5lgqBk ecdsa-sha2-nistp256 (ECDSA)

I want to use that second key, so I’ll run the following command:

openrolesanywhere request-certificate \
  --ssh-fingerprint SHA256:z/A9nNwdk1ZTmwtdrAlF2JQnGS8C7V3ozOPMt5lgqBk

That prints out the following:

-----END PUBLIC KEY-----

Now we can send that to our administrator (which is probably us) and they will run:

openrolesanywhere admin accept-request \
  --request-file path/to/above/publickey.pem \ 
  --validity-duration 8760h \
  --serial-number 67890 \
  --common-name nameOfTheEnduser \
  [--organization org] \
  [--organization-unit unit] \
  [--country country] \
  [--locality locality] \
  [--province province] \
  [--street-address addr] \
  [--postal-code 1234]

That will print out a certificate to the terminal, like this one:


We tell the end-user (again, probably ourselves) to store that file in ~/.config/openrolesanywhere/mycert.pem. Once they’ve done that, they can now configure the AWS CLI and SDKs to use it to retrieve AWS credentials.

To do that, the end-user adds this to their ~/.aws/config:

[profile example]
credential_process = openrolesanywhere credential-process --name mycert --role-arn arn:aws:iam::012345678912:role/SomeRoleName
region = ap-southeast-2

Now running aws sts get-caller-identity --profile example will work! Likewise, the AWS SDK in most programs should work out of the box by setting an environment variable like AWS_PROFILE=example.


In an ideal world, there’s all sorts of features you might expect to see in a fully-featured production version of this:

  • Support for PKCS#11 to support smart cards
  • Support for keys stored in TPMs
  • Yubikeys (are probably covered by one of the above?)
  • A SigV4 implementation that isn’t copy-pasted and edited from the AWS SDK
  • Documentation for rolesanywhere:CreateSession
  • Separation into a long-lived daemon (ideally socket-activated) that caches AWS credentials in memory and a client for it, so that CreateSession rate limits aren’t reached.

[1]: I wanted to use an SSH agent for the certificate authority, but this wasn’t possible out of the box with the Go stdlib – and I didn’t want to sink too much time into a PoC.


View Github