DevOps & Cloud Topic

Secure CI with GitHub Actions, OIDC and Software Supply-Chain Checks

A build job runs code and may have permission to publish or deploy it. That makes CI part of your security boundary. This guide starts with a useful check and then explains a safer way to connect a trusted job to AWS.

Use the shared Python lab. You need a GitHub repository to run the workflow. The local tests and Docker build can be tried before connecting a cloud account. The identity example requires separate AWS setup and does not deploy infrastructure.

Start with a job that needs no secret

Put this in .github/workflows/check.yml. It tests the app and builds an image. It does not push the image or deploy anything.

name: Check demo
on:
  pull_request:
  push:
    branches: [main]
permissions:
  contents: read
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
        with:
          python-version: '3.13'
      - run: python -m unittest -v test_app
      - run: docker build -t lecturre-web:ci .

The action references are full commit SHAs, checked against their official releases on 25 October 2026. A SHA fixes which action code runs. Review updates and keep dependencies maintained; pinning alone does not make code safe.

The job has read access to repository contents. Do not give every workflow write permission by default. A public pull request contains untrusted code. Keep its checks separate from jobs that can publish or deploy. Be especially careful with workflows that run privileged jobs on pull-request events or interpolate untrusted text into shell commands.

Why avoid permanent cloud keys?

A long-lived key can remain useful after a leak. With OIDC federation, a trusted job can request a short-lived identity token. AWS checks a trust policy before allowing it to assume a role. The role's permission policy then decides what that role can do.

There are two different questions: Who may become this role? and What may the role do? A narrow answer to one does not fix a wide answer to the other.

Set the trust boundary

Before using the workflow, configure GitHub's OIDC provider in the correct AWS account. Create a role with a trust policy restricted to your repository and production environment. Here is a policy shape; replace every account and repository placeholder.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::YOUR_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:YOUR_ORG/YOUR_REPO:environment:production"
        }
      }
    }
  ]
}

The subject uses the environment form because the job below declares environment: production. A branch-based subject has a different format. Keep the audience sts.amazonaws.com and the subject matched to your actual setup. Do not use a broad repository wildcard just to get a test passing.

Configure that GitHub environment separately with the available review and branch protection rules that fit your repository and plan. Naming an environment in YAML does not create an approval policy. Attach only the AWS permissions needed for the intended operation.

Test identity before adding deployment

Save this as a separate workflow after replacing the role variable and configuring the environment. The only AWS command asks which identity is active.

name: Check cloud identity
on:
  workflow_dispatch:
permissions:
  contents: read
jobs:
  identity:
    runs-on: ubuntu-latest
    environment: production
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
        with:
          role-to-assume: ${{ vars.AWS_ROLE_ARN }}
          aws-region: eu-central-1
      - run: aws sts get-caller-identity

The id-token: write permission allows the job to request an OIDC token. It does not give AWS resource-write permission. Repository variable AWS_ROLE_ARN identifies the role; it is not a secret access key. Avoid printing credentials or enabling debug output that reveals private data.

If access is denied, compare the actual repository, environment, audience and trust policy. Do not respond by adding AdministratorAccess. Once identity works, design a separate reviewed deployment with a recovery plan and narrowly scoped permissions.

Know what went into the image

An SBOM is a software bill of materials: a list of software components. Build provenance records information about how an artifact was produced. They help trace a problem and support policy checks. Neither proves that a build is free of malicious code or vulnerabilities.

With a current Docker Buildx setup, this local export requests an SBOM. Run it in the lab folder. It does not publish an image:

docker buildx build --sbom=true --output type=local,dest=sbom-out .

The export includes the build's filesystem and an SBOM file, so keep sbom-out outside the next build context or add it to .dockerignore. For a real release, check how your builder, image store and registry preserve attestations. Some image-load paths do not retain them. Use an appropriate supported vulnerability scanner and a process to review and fix findings; do not rely on the retired docker scan command.

Practice a review

  • Can the check job write to the repository? It should not need to.
  • Can an untrusted pull request reach production credentials? Keep that path closed.
  • Does the trust policy match one intended repository and environment?
  • Are deployment permissions narrower than account administration?
  • Can you identify the source commit and image used for a release?

Save the answers with your project. Good CI security comes from clear boundaries, maintained dependencies and review, not one large workflow file.

Official references and further reading

Reviewed on 25 October 2026. Tools change, so check the official documentation for the version you use.

DevOps learning roadmap · All DevOps & Cloud tutorials

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?