DEV Community

Cover image for GitHub Actions + AWS Role Chaining: A Security Upgrade Worth Making

GitHub Actions + AWS Role Chaining: A Security Upgrade Worth Making

As the year is coming to an end, I’ve been spending some time reflecting and intentionally improving my security knowledge.

Since joining Muzz, I’ve been exposed to systems that operate at scale, multiple AWS accounts, production-critical pipelines, and infrastructure that really cannot afford loose security practices. One of the most valuable things I learned during this journey is AWS role chaining in GitHub Actions.

It’s one of those setups that looks complex at first, but once it clicks, you realise:

Yeah… this is how CI/CD should work.

So I thought I’d share what we did, why we did it, and why you should probably do it too.

The Problem with “Simple” AWS Credentials in CI/CD

Traditionally, CI/CD pipelines access AWS by storing credentials like:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

as GitHub Secrets.

This works but it comes with problems:

  • Long-lived credentials sitting in GitHub

  • Hard to rotate safely

  • Over-permissioned “just in case”

  • No clear trust boundaries between environments

  • Risk increases as the organisation scales

As teams grow and environments multiply (shared, dev, staging, prod), this approach doesn’t scale securely.

The Modern Answer: GitHub OIDC + IAM Roles

Instead of static secrets, we moved to:

  • GitHub Actions OpenID Connect (OIDC) (I have already discussed that in my other blog)

  • IAM Roles with trust policies

  • Short-lived AWS credentials

  • Role chaining for environment isolation

This means:

  • No AWS secrets stored in GitHub

  • Credentials are issued only when a job runs

  • Access is tightly scoped and time-limited

What Is AWS Role Chaining?

Role chaining means:

GitHub Actions first assumes a base role (usually in a shared AWS account)
From there, it assumes a target role in another account (dev/prod).
Each hop has explicit trust and permissions.

Think of it like airport security:

  • GitHub gets through the main gate (shared role)
  • Then gets escorted to the correct terminal (dev/prod role)
  • No free roaming, no shortcuts

High Level Diagram

Diagram showing the permission flow

NOTE

Make sure you’re using the official AWS configure-aws-credentials GitHub Action with role chaining enabled (role-chaining: true).

If that approach doesn’t work for your setup, you can always fall back to the good old aws sts assume-role command as a manual alternative.

- uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::ACCOUNT_ID:role/target-role
    role-chaining: true
    aws-region: eu-west-2
Enter fullscreen mode Exit fullscreen mode

OR

aws sts assume-role \
  --role-arn arn:aws:iam::ACCOUNT_ID:role/target-role \
  --role-session-name github-actions-session
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Security isn’t something you “add later,” it’s something you design into your workflows from day one.

Working with GitHub Actions and AWS role chaining this year changed how I think about CI/CD security. It showed me that you don’t need to slow teams down to be secure you need better defaults.

As the year wraps up, I’ve been consciously investing more time in understanding why certain security patterns exist, not just how to implement them. AWS role chaining is one of those patterns that quietly improves everything around it, from auditability to confidence in production deployments.

If you’re still using long-lived AWS keys in CI/CD, this is one of the cleanest upgrades you can make.

Hopefully, this helps a few fellow builders ship with a bit more confidence and a lot less risk, and if you have any issues, please comment.

Happy building

Top comments (0)