How to use ACME to authenticate to AWS
Carl Tashian
AWS's new service IAM Roles Anywhere, launched in July, lets your servers authenticate to AWS using X.509 certificates. I'm a certificate nerd, so for me this is very exciting news!
Finally, AWS has given us the ability to delegate authentication to a Certificate Authority (CA).
Finally, we can stop managing long-lived IAM credentials,
and automate AWS authentication using ACME instead. (ACME is the widely supported certificate automation protocol used by Let's Encrypt.)
What this unlocks is very powerful--especially for multi-cloud or on-prem deployments, where you need to access AWS APIs from beyond the walled garden. A workload can non-interactively get a certificate from a local ACME Certificate Authority (CA), keep it renewed, and use the cert to get temporary IAM credentials from AWS on demand.
Certificates have a few special properties that make them useful for identity management. They can be renewed and revoked. They expire, sometimes very quickly. They are tied to a private key (which can be generated and stored non-exportably in a hardware security device!). And they contain CA-signed metadata like a hostname or email address that can be used for identity and independently verified by a third-party.
And, one certificate can be used to access multiple AWS accounts!
In this post, I want to show you how to create a CA and how to set up and configure IAM Roles Anywhere.
To access AWS with certificates instead of IAM credentials, I'll help you configure credential sourcing that will work with the aws
command and with any program that uses AWS's official SDK.
Finally, I'll show you how to add ACME server support and help you automate the certificate management side of things.
Getting started
You'll need a CA for this project.
That's where we come in.
You can run our open-source step-ca
server or, for easy mode, jump over to Certificate Manager and create a free hosted CA in a few minutes.
Run your own step-ca
server...
-
Follow our Getting Started guide to initialize your PKI and start a CA.
-
Install our open-source
step
CA client, so you can get certificates. -
Bootstrap your client to your CA server. To do this, you'll need the CA URL and the root certificate fingerprint that the server prints when it starts up. Now run the following, substituting these values for your own:
step ca bootstrap --ca-url https://ca.example.com:9000 --fingerprint 702a094e239c9eec6fEXAMPLE012825c5fe3d1ae1b2fd6ee
...or create a Certificate Manager CA
-
Create a team here. Once you've signed up, create an Authority.
-
Install our open-source
step
CA client, so you can get certificates. -
To bootstrap your client to your CA server, you'll need the Authority's CA URL and root fingerprint, which appear on the Authority detail page. Run the following, substituting these values for your own:
step ca bootstrap --ca-url https://example.team.ca.smallstep.com --fingerprint 702a094e239c9eec6fEXAMPLE012825c5fe3d1ae1b2fd6ee
Now you're ready to move on to configuring AWS.
Configuring IAM Roles Anywhere
This section is a quickstart. See the IAM Roles Anywhere documentation for a deeper dive into the AWS side of the configuration. First, we'll configure a trust anchor in the IAM management console, so that AWS trusts our CA.
In the management console, create a trust anchor for IAM Roles Anywhere.
Give it a name, and choose "External certificate bundle" as the CA source.
Then, paste in the contents of your root CA certificate PEM, which you can obtain by running step ca root
in your terminal.
Choose "Create a trust anchor" to save it.
Next, we'll create an IAM Roles Anywhere profile. A profile is a set of IAM Roles and additional policies that will be allowed by the IAM credentials issued by Roles Anywhere. You can only add Roles to a policy if they have an established trust relationship with IAM Roles Anywhere.
- Go to your IAM Roles and create or choose a role that you want to associate with IAM Roles Anywhere.
- Follow AWS's instructions for configuring the role's trust policy. Note that each Role also has a configurable Maximum Session Duration of between 1-12 hours.
- Repeat steps 1 and 2 for any other roles you want to use in IAM Roles Anywhere.
- Now create a Profile in Roles Anywhere, give it a name, and attach one or more of your Roles to the Profile. Note that a given Role can only be attached to a single Profile.
When you establish these policies, you can use the certificate Subject
or Issuer
fields in your policy conditions.
So, for example, you might establish an Organizational Unit (OU)
within your PKI and constrain AWS access by that field.
Or you could simply constrain access by user, using the Common Name (CN)
certificate field.
Once you've added a trust anchor and a policy, you're ready to test out your configuration on the client side.
Getting your first certificate
We'll start by getting a certificate with step
.
Run:
step ca certificate carl.step.lan step.crt step.key
Replace my hostname with your own. For now, you'll be asked to enter your CA password to get the certificate. Later, you can configure ACME for this step.
Output:
✔ Certificate: step.crt
✔ Private Key: step.key
Finally, let's extract the intermediate certificate, which AWS needs in a separate file. Run:
cat step.crt | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN CERTIFICATE/){a++}; if(a==2){out="intermediate_ca.crt"; print >out}}'
You should have a file called intermediate_ca.crt
that contains your Intermediate CA certificate:
step certificate inspect intermediate_ca.crt --short
Output:
X.509v3 Intermediate CA Certificate (ECDSA P-256) [Serial: 5123...6024]
Subject: Smallstep Intermediate CA
Issuer: Smallstep Root CA
Valid from: 2022-07-10T23:44:53Z
to: 2032-07-08T23:44:53Z
Now you're ready to put the pieces together.
Using your certificate to get IAM Credentials
Now it's time to configure AWS authentication.
For this step, you'll need to install the aws
CLI tool.
For this piece, AWS provides a credential helper program that takes the cert and key as input, and outputs the temporary IAM credentials.
-
Download the credential helper for your platform
-
Test it out with the following command:
./aws_signing_helper credential-process \ --intermediates intermediate_ca.crt \ --certificate step.crt \ --private-key step.key \ --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID \ --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID \ --role-arn arn:aws:iam::account:role/role-name-with-path
Substitute the ARNs here for your trust anchor, profile, and desired role that you established earlier.
-
If it works, you'll see some IAM credentials output to the terminal.
-
Now create an
~/.aws/config
config file for AWS, to use the credential helper. Add the following:[default] credential_process = ./aws_signing_helper credential-process --certificate /path/to/step.crt --private-key /path/to/step.key --intermediates /path/to/intermediate_ca.crt --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID --role-arn arn:aws:iam::account:role/role-name-with-path
Note: If you want to use the credential helper to access multiple roles or AWS accounts, you'll just need to add additional profiles to this config file.
-
Try running an
aws
CLI command. If your role supports it, the command should run successfully.
Your setup is complete. Most software that uses the AWS SDK will follow the credential flow we just set up, without any additional configuration.
Automating it for non-interactive workloads
At this point, you have the basic setup. When you automate this flow, you'll need to tailor the automation to your workload's environment. But, the general steps are the same for any environment:
-
Add an ACME provisioner to your CA. See ACME Basics for details on how ACME works, and how to set it up on your CA.
-
Configure your workload so that it gets a certificate via ACME when it is deployed/started, via
step ca certificate
or using any ACME-compatible client.It's worth noting here that you could, with a few lines of Bash, wrap certificate automation around the
aws_signing_helper
. You could check if the current cert is missing or expired, and get a new one on demand:#!/bin/bash ACME_HOSTNAME=carl.step.lan CERT_LOCATION=/path/to/step.crt KEY_LOCATION=/path/to/step.key INTERMEDIATE_CA_PEM_LOCATION=/path/to/intermediate_ca.crt PROVISIONER_NAME=acme TRUST_ANCHOR_ARN=arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID PROFILE_ARN=arn:aws:rolesanywhere:region:account:profile/PROFILE_ID ROLE_ARN=arn:aws:iam::account:role/role-name-with-path if ! [[ -f $CERT_LOCATION || -f $KEY_LOCATION ]]; then issue_cert=true else set +e step certificate needs-renewal $CERT_LOCATION --expires-in 0m 2> /dev/null retVal=$? if [[ "$retVal" = 0 || "$retVal" = 255 ]]; then issue_cert=true fi set -e fi if [ "$issue_cert" = true ]; then step ca certificate $ACME_HOSTNAME $CERT_LOCATION $KEY_LOCATION \ --provisioner $PROVISIONER_NAME \ --force fi /path/to/aws_signing_helper credential-process \ --intermediates $INTERMEDIATE_CA_PEM_LOCATION \ --certificate $CERT_LOCATION \ --private-key $KEY_LOCATION \ --trust-anchor-arn $TRUST_ANCHOR_ARN \ --profile-arn $PROFILE_ARN \ --role-arn $ROLE_ARN
Just run this script as your credential process, instead of running
aws_signing_helper
directly. -
Or, if it doesn't make sense in your case to wrap the credential process in a script, you can configure automated certificate renewal so that your cert is always valid when AWS needs it. We have several options for automated renewal in our documentation; which one you choose will depend on your environment.
-
Of course, you could roll this all out with an IT automation tool.
Carl Tashian (Website, LinkedIn) is an engineer, writer, exec coach, and startup all-rounder. He's currently an Offroad Engineer at Smallstep. He co-founded and built the engineering team at Trove, and he wrote the code that opens your Zipcar. He lives in San Francisco with his wife Siobhan and he loves to play the modular synthesizer 🎛️🎚️