OIDC Provider Module

Reference documentation for the GitHub Actions OIDC provider module.


Overview

The OIDC provider module (modules/oidc-provider/) creates a GitHub Actions OpenID Connect provider and IAM role, enabling keyless authentication from GitHub workflows to AWS.

Benefits:

  • No AWS credentials stored in GitHub Secrets
  • Temporary credentials with automatic expiration
  • Repository-scoped access control
  • Full audit trail via CloudTrail

Module structure

modules/oidc-provider/
├── main.tf           # OIDC provider and IAM role
├── variables.tf      # Input variables
├── outputs.tf        # Module outputs
└── versions.tf       # Provider requirements

Usage examples

Basic usage

module "oidc_provider" {
  source = "../../modules/oidc-provider"

  github_repo = "your-org/your-repo"
}

With managed policies

module "oidc_provider" {
  source = "../../modules/oidc-provider"

  github_repo = "your-org/your-repo"
  role_name   = "GitHubActionsServiceRole-Terraform-staging"

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/PowerUserAccess"
  ]
}

With inline policies

module "oidc_provider" {
  source = "../../modules/oidc-provider"

  github_repo = "your-org/your-repo"

  inline_policies = {
    "S3Access" = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Action   = ["s3:GetObject", "s3:PutObject"]
          Resource = "arn:aws:s3:::my-bucket/*"
        }
      ]
    })
  }
}

Reusing existing OIDC provider

When deploying multiple environments to the same AWS account:

module "oidc_provider" {
  source = "../../modules/oidc-provider"

  github_repo                = "your-org/your-repo"
  use_existing_oidc_provider = true
  role_name                  = "GitHubActionsServiceRole-Terraform-staging"
}

Input variables

NameTypeDefaultRequiredDescription
github_repostring-YesGitHub repository (owner/repo)
use_existing_oidc_providerboolfalseNoUse existing OIDC provider
github_thumbprintstring6938fd4d...NoGitHub OIDC thumbprint
audience_listlist(string)["sts.amazonaws.com"]NoAllowed audiences
role_namestringGitHubActionsServiceRole-TerraformNoIAM role name
pathstring/NoIAM path for the role
managed_policy_arnslist(string)[]NoManaged policy ARNs
inline_policiesmap(string){}NoInline policy documents
max_session_durationnumber3600NoMax session duration (3600-43200)
tagsmap(string){}NoResource tags

Outputs

NameTypeDescription
oidc_provider_arnstringARN of the OIDC provider
oidc_provider_urlstringURL of the OIDC provider
role_arnstringARN of the IAM role
role_namestringName of the IAM role
role_idstringID of the IAM role
role_unique_idstringUnique ID of the IAM role

How it works

OIDC provider management

The module automatically detects and reuses existing OIDC providers:

data "aws_iam_openid_connect_provider" "github_actions" {
  count = var.use_existing_oidc_provider ? 1 : 0
  url   = "https://token.actions.githubusercontent.com"
}

resource "aws_iam_openid_connect_provider" "github_actions" {
  count = var.use_existing_oidc_provider ? 0 : 1
  url   = "https://token.actions.githubusercontent.com"

  client_id_list  = var.audience_list
  thumbprint_list = [var.github_thumbprint]
}

Why this matters:

  • AWS allows only one OIDC provider per issuer URL per account
  • Setting use_existing_oidc_provider = true prevents errors when deploying multiple environments

Trust policy

The IAM role trusts GitHub Actions for your specific repository:

assume_role_policy = jsonencode({
  Version = "2012-10-17"
  Statement = [
    {
      Effect = "Allow"
      Principal = {
        Federated = local.oidc_provider_arn
      }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringLike = {
          "token.actions.githubusercontent.com:sub" = "repo:${var.github_repo}:*"
        }
        StringEquals = {
          "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
        }
      }
    }
  ]
})

Security features:

  • Repository-scoped: Only your repository can assume the role
  • Audience validation: Token must be intended for AWS STS
  • Wildcard subject: Allows all branches and environments

Requirements

terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0"
    }
  }
}

Next steps