Skip to content
GitShowcase Forum

How do I deploy from GitHub Actions to the cloud without long lived secrets?

Staff answerWritten by Maren Castillo · CI/CD and GitHub Actions0 replies

Short answer

Use OpenID Connect (OIDC). Your cloud provider trusts GitHub as an identity provider, each job asks GitHub for a signed token, and the cloud swaps it for credentials that expire with the job. You add id-token: write to the workflow and lock the cloud role to your repository and branch or environment.

Written by Maren Castillo · Forum lead: databases, hosting, CI and production ·
CiteGitShowcase Forum, "How do I deploy from GitHub Actions to the cloud without long lived secrets?", https://gitshowcase.com/forum/discuss/how-do-i-deploy-from-github-actions-to-the-cloud-without-long-lived/, accessed 2026-11-15.
  1. Forum lead: databases, hosting, CI and production ·

    Why this replaces stored keys

    The old pattern is to create an access key in your cloud account, paste it into a GitHub secret, and present it on every run. That key lives until someone rotates it, and anyone who can read the secret can use it from anywhere. According to the GitHub Actions OIDC docs, OIDC removes the duplicated cloud secret: you set up a trust relationship once, and the provider issues a short-lived token that is only valid for a single job and then expires on its own.

    The flow, in four steps:

    1. You tell the cloud that tokens from GitHub's issuer are acceptable, and for which workflows.
    2. Each job can request a JSON web token (JWT) from GitHub. It carries claims such as the repository, the branch or environment, and the workflow.
    3. The workflow presents that token to the cloud.
    4. The cloud checks the claims against the trust rules you wrote and returns temporary credentials.

    Check first

    • Is the job running on a GitHub-hosted or self-hosted runner that can reach both GitHub's token endpoint and your cloud's token service?
    • Is the job triggered by a pull request? Its token claims differ from a push to main, so a trust policy written for main will not match.
    • Which cloud? The steps below use AWS because GitHub documents it step by step. Azure, Google Cloud, HashiCorp Vault and others have their own pages in the same docs section, and the shape is the same.

    Step by step on AWS

    1. Add GitHub as an identity provider in IAM. Per the GitHub guide for AWS, the provider URL is https://token.actions.githubusercontent.com, and the audience is sts.amazonaws.com if you use the official aws-actions/configure-aws-credentials action.

    2. Create a role with a trust policy that names your repo. The docs say you must define at least one condition so that untrusted repositories cannot request tokens for your resources. Match on the sub claim:

    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
          "token.actions.githubusercontent.com:sub": "repo:<OWNER>/<REPO>:environment:prod"
        }
      }
    }
    

    3. Give the role only the permissions the deploy needs. A role that can write one bucket or update one service is far safer than an admin role. The trust policy decides who can get in; the permission policy decides what they can do.

    4. Update the workflow. Two changes: the permissions block and the credentials step.

    name: deploy
    on:
      push:
        branches: [main]
    
    permissions:
      id-token: write   # lets the job request the OIDC token
      contents: read    # lets checkout read the repo
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        environment: prod
        steps:
          - uses: actions/checkout@v6
          - uses: aws-actions/configure-aws-credentials@<PINNED_COMMIT_SHA>
            with:
              role-to-assume: arn:aws:iam::<ACCOUNT_ID>:role/<DEPLOY_ROLE>
              aws-region: <REGION>
          - run: aws s3 sync ./dist s3://<BUCKET_NAME>/
    

    Pin third party actions to a full commit SHA where you can, as GitHub's own example does. id-token: write does not let the workflow write to your repo; the docs say it only allows requesting and using the OIDC token.

    Match the sub claim you actually have

    Most failures are a mismatch between the token's sub and the trust policy. The common shapes, as of the GitHub docs in November 2026:

    Workflow context sub looks like
    Branch push repo:<OWNER>/<REPO>:ref:refs/heads/<BRANCH>
    Job with an environment repo:<OWNER>/<REPO>:environment:<ENV>
    Any branch or environment in one repo StringLike with repo:<OWNER>/<REPO>:*

    The docs also note a newer format: repositories created after July 15, 2026, or that opt in, include immutable owner and repository IDs in sub, written like repo:<OWNER>@<ID>/<REPO>@<ID>:.... If your role worked for old repos and fails for a new one, print the claim and compare. Also remember that when a job uses an environment, sub names the environment, not the branch.

    Add protection on the environment

    When you key trust to an environment, add protection rules on that environment in GitHub, such as restricting which branches can deploy to it. GitHub's AWS page recommends this for extra security. Without it, anyone who can push a workflow that targets the environment can request the same token.

    Common errors

    • "Credentials could not be loaded" or "Not authorized to perform sts:AssumeRoleWithWebIdentity": the sub or aud in the trust policy does not match the token. Check both.
    • "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL": the job is missing id-token: write. Set it at the workflow or job level.
    • Works on main, fails on a pull request: your trust policy names a branch or environment the PR job does not have.

    If your cache step is also misbehaving in the same workflow, see why a GitHub Actions cache never restores. For platform comparisons, the CI/CD guide covers the options.

    0
    ReplyLink

Plain text or simple Markdown. Links are nofollow. Your email is never shown.

GitShowcase Forum. Questions and answers on shipping developer projects: dev tools, APIs, infrastructure and portfolios.