Skip to content

GitHub Actions OIDC

GitHub Actions workflows authenticate with AWS using OpenID Connect (OIDC). Instead of storing long-lived AWS credentials as GitHub secrets, each workflow run receives a short-lived token that AWS exchanges for temporary credentials.

Before your pipeline can deploy to AWS, Team Cloud must provision an IAM role that trusts your specific GitHub repository.

How it works

Authentication follows a two-step chain:

  1. GitHub exchanges its OIDC token for temporary credentials in the Central-IAM-User AWS account.
  2. Those credentials assume a second IAM role in your application's AWS account. This role is scoped to your repository only—no other repository can assume it.

The BYM composite actions perform both steps automatically. If you write custom AWS steps, you add both steps yourself.

Step 1: Request access from Team Cloud

Contact Team Cloud on the #cloud-infrastructure Slack channel and provide:

  • The full name of your GitHub repository, for example BYM-IKT/KatteApp
  • The AWS account names that need access, for example BYM-DP-Katteapp-Test and BYM-DP-Katteapp-Prod

Tip

Where to find the AWS account names? Open Terraform file, go to account-defaults.tf and look for

   variable "aws_profile" {
      default = "BYM-DTI-Sandbox"
    }
If it doesn't exist, log in to the AWS Access Portal to find the account name.

Step 2: Add the OIDC permission to your workflow job

The BYM composite actions handle OIDC automatically when you provide the required inputs and add the permissions shown below to the job. To assume the role yourself instead of using a composite action, follow the "Custom workflow" example.

.github/workflows/deploy-to-test.yml
env:
  AWS_ACCOUNT_ID: "<<AWS_ACCOUNT_ID>>"
  ECR_REPOSITORY_NAME: kattehotell-api
  DOCKER_CONTEXT_PATH: "."
  DOCKERFILE_PATH: "Kattehotell.Api/Dockerfile"

jobs:
  build_push_image_to_shared:
  name: Build image and publish to ECR
  runs-on: ubuntu-latest
  permissions:
    id-token: write
    contents: read
  steps:
    - name: Build and push image to ECR
      uses: BYM-IKT/github-actions/build-and-push-image-to-ecr@master
      with:
        aws-account-id:      ${{ env.AWS_ACCOUNT_ID }}        
        ecr-name:            ${{ env.ECR_REPOSITORY_NAME }}
        docker-context-path: ${{ env.DOCKER_CONTEXT_PATH }}
        dockerfile-path:     ${{ env.DOCKERFILE_PATH }}

  # ... build steps ...
.github/workflows/deploy-to-test.yml
env:
  AWS_ACCOUNT_ID: "<<AWS_ACCOUNT_ID>>"
  APP_URL: https://kattehotell.test.bymoslo.net
  S3_BUCKET_NAME: test-kattehotell-cf
  PROJECT_DIRECTORY: "."
  BUILD_PATH: "build/client"

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Check out repository
        uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

      # ... build steps ...

      - name: Upload to S3 and invalidate CloudFront cache
        uses: BYM-IKT/github-actions/upload-to-s3-and-invalidate-cloudfront@master
        with:
          aws-account-id:                      ${{ env.AWS_ACCOUNT_ID }}
          s3-bucket-name:                      ${{ env.S3_BUCKET_NAME }}
          build-directory:                     ${{ env.PROJECT_DIRECTORY }}/${{ env.BUILD_PATH }}
          cloudfront-distribution-domain-name: ${{ env.APP_URL }}
.github/workflows/deploy-to-test.yml
env:
  AWS_ACCOUNT_ID: "<<AWS_ACCOUNT_ID>>"
  ECR_REPOSITORY_NAME: kattehotell-api
  ECS_CLUSTER_NAME: test-kattehotell
  ECS_SERVICE_NAME: kattehotell-api

jobs:
  deploy_images_to_ecs_service_test:
    name: "Deploy to TEST"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-ecs.yml@master
    with:
      environment:           testing
      aws-account-id-target: ${{ env.AWS_ACCOUNT_ID }}
      ecr-name:              ${{ env.ECR_REPOSITORY_NAME }}
      image-tag-target:      latest
      image-tag-new:         test
      ecs-cluster-name:      ${{ env.ECS_CLUSTER_NAME }}
      ecs-service-name:      ${{ env.ECS_SERVICE_NAME }}

  # ... build steps ...
.github/workflows/deploy-to-test.yml
env:
  AWS_ACCOUNT_ID: "<<AWS_ACCOUNT_ID>>"
  ECR_REPOSITORY_NAME: kattehotell-worker
  LAMBDA_FUNCTION_NAME: kattehotell-worker

jobs:
  deploy_image_to_lambda_function_test:
    name: "Deploy to TEST"
    uses: BYM-IKT/github-actions/.github/workflows/deploy-image-to-lambda.yml@master
    with:
      environment:           testing
      aws-account-id-target: ${{ env.AWS_ACCOUNT_ID }}
      ecr-name:              ${{ env.ECR_REPOSITORY_NAME }}
      image-tag-target:      latest
      image-tag-new:         test
      lambda-name:           ${{ env.LAMBDA_FUNCTION_NAME }}

  # ... build steps ...
.github/workflows/deploy-to-test.yml
env:
  AWS_ACCOUNT_ID: "<<AWS_ACCOUNT_ID>>"

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Check out repository
        uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

      - name: Assume parent role in AWS
        id: creds
        uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
        with:
          aws-region:         eu-west-1
          role-to-assume:     arn:aws:iam::924598342799:role/github-oidc
          role-session-name:  Github-Action-${{ github.event.repository.name }}
          output-credentials: true

      - name: Assume execution role in AWS
        uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
        with:
          aws-access-key-id:     ${{ steps.creds.outputs.aws-access-key-id }}
          aws-secret-access-key: ${{ steps.creds.outputs.aws-secret-access-key }}
          aws-session-token:     ${{ steps.creds.outputs.aws-session-token }}
          aws-region:            eu-west-1
          role-duration-seconds: 3500
          role-to-assume:        arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/github-actions-${{ github.repository_id }}
          role-session-name:     Github-Action-${{ github.event.repository.name }}

      # ... build steps ...

Tip

Not sure about the AWS account ID? Look for the default-account.tf file in your product's Terraform Infrastruktur-repo. The AWS account ID is the 12-digit number used for the account_id variable.

You can also log in to the AWS Access Portal to find the account ID.