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
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
OR
aws sts assume-role \
--role-arn arn:aws:iam::ACCOUNT_ID:role/target-role \
--role-session-name github-actions-session
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)