Yes. You can let a GitHub Actions workflow get temporary AWS credentials through OpenID Connect (OIDC) instead of saving an AWS access key and secret in repository secrets. Create an AWS OIDC identity provider, make an IAM role that trusts only the intended GitHub repository and branch or environment, allow only the deployment actions that role needs, then give the workflow id-token: write and use AWS’s official credentials action. Test it outside production first. The important security decision is the role’s trust policy: it should be specific enough that another repository or branch cannot assume it.
Why OIDC is a better fit than a stored access key
A conventional deployment setup puts an AWS access key ID and secret access key in GitHub repository or environment secrets. That can work, but the credential is long-lived until you rotate or revoke it. It also creates an extra secret to protect, audit, and replace when people or systems change.
With OIDC, GitHub issues a short-lived identity token while an approved workflow is running. AWS checks that token against the trust policy on an IAM role and, if it matches, returns temporary role credentials. The workflow still needs permission to deploy, but it does not need a permanent AWS key stored in GitHub.
This reduces one kind of risk; it is not automatic security. A workflow that can deploy remains sensitive code. Protect the branch or environment that can run it, review workflow changes, and keep the AWS permissions as small as the real deployment allows. GitHub’s official OIDC in AWS guide is the source of truth for the current console labels and claim syntax.
Decide exactly what may deploy before creating the role
Write down four values before opening AWS:
- The GitHub organization and repository that owns the workflow.
- The deployment boundary: one protected branch, such as
main, or one GitHub Environment, such asproduction. - The AWS account and Region receiving the deployment.
- The smallest AWS actions and resources needed by that deployment command.
An environment is often a clean boundary for production because GitHub Environments can require reviewers and can hold environment-specific settings. A branch is simpler for a small project with a protected release branch. Choose one and encode it in the trust policy; do not write a broad policy that accepts every repository, branch, or subject.
Also separate who may assume the role from what the role may do. The trust policy controls the first question. The permissions policy attached to the role controls the second. A precise trust policy paired with an administrator-level permissions policy is still more power than most deployments need.
Create the AWS OIDC provider and a narrowly scoped role
In IAM, add the GitHub Actions OIDC provider using the provider URL and audience documented by GitHub. AWS may already have an OIDC provider for GitHub in the account; inspect it rather than creating a duplicate. Then create a role for web identity and attach a permissions policy tailored to the target service—for example, only the specific S3 bucket, CloudFront distribution, ECS service, or infrastructure stack that the deployment actually changes.
The role’s trust policy should identify GitHub Actions as the federated principal and limit the token’s sub claim to your release boundary. For a branch deployment, GitHub documents a subject pattern like repo:OWNER/REPOSITORY:ref:refs/heads/BRANCH. For an environment deployment, it documents repo:OWNER/REPOSITORY:environment:ENVIRONMENT-NAME. Use your literal values, not a wildcard repository pattern.
GitHub has introduced immutable-subject-claim behavior for newly created repositories, so do not copy an old trust-policy example blindly. Check the current GitHub OIDC documentation and the claims emitted by your repository before saving the policy. Keep the role ARN handy, but do not put account IDs, role names, or policy JSON in a public issue just to troubleshoot a deployment.
Add the minimum workflow permissions and configure AWS credentials
The job needs permission to request an OIDC token. That is the purpose of id-token: write; it does not grant write access to your repository. contents: read is commonly enough when the job also checks out code. Here is a compact starting point:
name: Deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
aws-region: us-east-1
- run: ./scripts/deploy.sh
Replace the branch, Region, role reference, and deployment command with your own. Storing the role ARN as a secret is optional; the ARN is an identifier rather than a credential, but keeping configuration in an environment or repository variable can make account-specific workflows easier to manage. Do not add AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY as a fallback. That defeats the point of moving to temporary credentials.
Use the official aws-actions/configure-aws-credentials repository for supported inputs, version guidance, and troubleshooting. Pin actions according to your organization’s supply-chain policy and review upstream updates as part of normal maintenance.
Test the authentication boundary before a production deploy
Start with a non-production role and a harmless command such as aws sts get-caller-identity. The run should show that AWS issued credentials for the expected role without printing credentials themselves. Then test the smallest real deployment in a staging account or environment.
If AWS returns an access-denied error while assuming the role, compare the workflow’s repository and ref or environment to the trust-policy conditions. If it assumes the role but the deployment command fails, examine the role’s permissions policy and the specific resource ARN. Do not solve either problem by changing the trust condition to repo:* or attaching AdministratorAccess; that trades a useful error for a much larger blast radius.
Keep deployment work separate from routine pull-request checks. Our guide to running Node.js tests on every GitHub pull request is a good baseline for validating changes before they reach a deploy branch. For another security layer, see how to enable GitHub code scanning. And if a team release needs human review, require pull-request approval before merging complements the same protected-branch workflow.
Keep the setup reviewable over time
Document the intended repository, release boundary, AWS account, and role owner near the workflow or in your team’s deployment notes. When a new environment, repository, or AWS service is added, make a deliberate change to both the trust policy and permissions policy rather than broadening an existing role “temporarily.” Remove unused roles and provider entries during normal access reviews.
OIDC is most valuable when its boundaries stay readable: one known workflow, one known identity condition, and only the AWS powers it needs. That gives you temporary deployment credentials without leaving a long-lived AWS secret waiting in a repository setting.
Official sources
- GitHub Docs: Configuring OpenID Connect in Amazon Web Services
- GitHub: aws-actions/configure-aws-credentials
- AWS IAM: Creating OpenID Connect identity providers
