Assumes roles in AWS that have useful role session tags

GitHub Actions has (almost) launched OpenID Connect federation. This
means you can assume a role in AWS without needing to store long-lived credentials
as secrets in your GitHub repository. This is really great, but it could be
even better. The JWT issued by GHA contains lots of useful claims, but STS
AssumeRoleWithWebIdentity can’t use most of them. Hence this project.

This project is two parts: First, an API Gateway with JWT auth (with GHA as the issuer)
and a Lambda function behind it that assumes roles using those claims as role
session tags
. Second, a GHA “action” that acts as the client
of that API and requests credentials to be used in a workflow.


Deploy the API Gateway and Lambda using the api.yml CloudFormation
template. I recommend creating a brand new AWS account solely for this purpose.
The template has some inline documentation. TODO: Include build instructions
and an AWS SAR application once I’m happy I don’t want to make massive changes

Next, create roles that your GHA workflows will be assuming. Look at
example.yml for guidance on a trust policy.

Finally, include the GHA action in your workflows. A “hello world” example
looks like:

name: Example

    runs-on: ubuntu-latest
      id-token: write
      contents: read
      - uses: actions/[email protected]
        # this actions sets AWS_* environment variables for later steps
      - uses: glassechidna/[email protected]
          apiUrl: ${{ secrets.CREDENTIALS_URL }}
          roleArn: arn:aws:iam::0123456789012:role/DeploymentRole
      - run: aws sts get-caller-identity --region us-east-1

There’s also an optional transitiveTags input parameter. It’s worth noting
that you can choose to make the either apiUrl, roleArn, both or neither
values secret. It’s just a tradeoff on usability.


TODO: flesh out explanation.

architecture diagram


TODO: flesh out spiel. Two main reasons: you get highly enriched entries
in CloudTrail and can trace actions back to specific GHA jobs with ease. Also,
you can use the session tags as variables in your IAM policies. This allows you
to parameterise your deployment IAM roles, giving you highly granular and isolated
permissions without needing a 1:1 mapping of repositories to roles.


While building this I learned that AWS STS enforces a limit of approximately
500 bytes on the combined total of role session tag keys and values. Which the
complete GHA OIDC JWT exceeds. You can choose which values to pass through as
tags in the CFN template – I’ve selected what I think are useful defaults.

I hate this

Honestly, kinda the same. I’d prefer it not to exist. I highly recommend filing
a feature request with AWS asking for the ability to map arbitrary claims in
OIDC tokens to role session tags in sts:AssumeRoleWithWebIdentity. If we all
nag enough, maybe they’ll do it.