This project provides a secure, automated setup for AWS OIDC authentication with GitHub Actions.
- Modular Bash script (run.sh) for provisioning AWS IAM roles and trust policies
- Jinja2-based CloudFormation template rendering for IAM role and policies
- Modular policy management via the
policies/directory - GitHub Actions workflows for OIDC verification and code linting
- Documentation and CI/CD best practices
git clone https://github.com/PaulDuvall/gha-aws-oidc-bootstrap.git
cd gha-aws-oidc-bootstrapYou can use the streamlined, fully automated workflow:
# Option 1: With a GitHub Personal Access Token (PAT) to automatically set repo variables
export GITHUB_TOKEN=github_pat_XXXXXXXXXXXX
bash run.sh --github-org <your_org> --github-repo <your_repo> --region us-east-1 --github-token $GITHUB_TOKEN
# Option 2: Without a GitHub token
bash run.sh --github-org <your_org> --github-repo <your_repo> --region us-east-1- The
--github-organd--github-repoarguments are required to target a specific repository. This ensures the IAM trust policy and stack name are unique per repo. - Alternatively, you can use
allowed_repos.txtto grant access to multiple repos at once. Each line should be in the formatowner/repo.
After running the script, you will see clear instructions for using the IAM Role in your GitHub Actions workflow. You can:
-
Option 1: Use a repository variable (recommended for teams)
- Set a GitHub Actions variable in your repository named
GHA_OIDC_ROLE_ARNwith the IAM Role ARN output by the script. - Reference that variable in your workflow YAML:
permissions: id-token: write contents: read jobs: deploy: runs-on: ubuntu-latest steps: - name: Assume OIDC Role uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ vars.GHA_OIDC_ROLE_ARN }} aws-region: us-east-1
- Set a GitHub Actions variable in your repository named
-
Option 2: Reference the IAM Role ARN directly (suitable for solo use or quick setup)
permissions: id-token: write contents: read jobs: deploy: runs-on: ubuntu-latest steps: - name: Assume OIDC Role uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsOIDCRole aws-region: us-east-1
Replace the ARN above with the value output by the script. Both approaches are always available, regardless of whether you use a GitHub token.
- The script uses the file
allowed_repos.txtto determine which repositories will be granted access. List each repository (in the formatowner/repo) on a separate line in that file before running the script. If you use--github-organd--github-repo, only that repo is granted access. - There is no
--reposargument; repository access is controlled via the trust policy and the contents ofallowed_repos.txt.
Stack Naming Convention:
- The CloudFormation stack name is automatically generated to ensure uniqueness and compliance with AWS naming rules.
- Format:
gha-aws-oidc-<org>-<repo>(all lowercase, hyphens only, max 64 chars) - Example: For
PaulDuvall/gha-aws-oidc-bootstrap, the stack name will begha-aws-oidc-paulduvall-gha-aws-oidc-bootstrap - This stack name is used for all AWS resources deployed for this integration.
- Custom Stack Names: You can override the default naming by providing
--stack-name <name>when running the script:bash run.sh --github-org <org> --github-repo <repo> --stack-name my-custom-stack
GitHub Token Requirements:
- Use a GitHub Personal Access Token (PAT) with fine-grained permissions.
- Fine-grained: grant
Actions(Read/Write),Variables(Read/Write), andSecrets(if needed).
- CloudFormation templates for the IAM role and policies are rendered using Jinja2, ensuring robust YAML block indentation and eliminating placeholder injection logic.
- Obsolete scripts and templates (such as
inject_trust_policy.pyandiam_role.base.yaml) have been removed. - Policies are modular and loaded from the
/policiesdirectory; the renderer attaches all found policies to the IAM role. - The trust policy is dynamically generated and injected into the CloudFormation template for least-privilege, multi-repo OIDC integration.
- Deployment workflow and scripts are structured for clarity, maintainability, and security.
This automation sets up secure OIDC authentication between GitHub Actions and AWS, eliminating static AWS credentials and enabling short-lived, tightly-scoped credentials for every workflow run. Here’s what happens automatically (and what you’d otherwise do manually):
- Create the OIDC Identity Provider in AWS IAM
- Adds
token.actions.githubusercontent.comas a provider and sets audience tosts.amazonaws.com.
- Adds
- Create the IAM Role with Trust and Permissions
- Generates a trust policy allowing GitHub Actions from your current repo (and any in
allowed_repos.txt) to assume the role via OIDC. - Attaches a permissions policy granting only the required AWS actions.
- Generates a trust policy allowing GitHub Actions from your current repo (and any in
- Set the GitHub Repository Variable
- Sets the
GHA_OIDC_ROLE_ARNvariable in your GitHub repository, referencing the IAM Role ARN.
- Sets the
- (Optional) Manage Parameter Store/Secrets
- If needed, configures AWS SSM Parameter Store entries using SecureString and grants the IAM Role permission to read them.
- Update Trust Policy for Cross-Repo Access
- To allow another repo, add it to
allowed_repos.txtand rerun the script.
- To allow another repo, add it to
This project automatically generates a flexible IAM trust policy for GitHub Actions OIDC integration based on the repositories listed in allowed_repos.txt.
- Do NOT commit your
allowed_repos.txtfile. It is gitignored by default. Instead, use the providedallowed_repos.txt.exampleas a template for contributors.
The policies/ directory contains example IAM policy files that you can customize for your specific AWS permissions needs.
- Browse the example files in
policies/directory (files ending with-example.json) - Copy an example that matches your use case and remove the
-examplesuffix:cp policies/s3-example.json policies/s3.json
- Customize the policy by updating:
- Resource ARNs (replace placeholders like
myproject-*with your actual resource names) - Actions (only include what your workflows need)
- Conditions (add extra security constraints if needed)
- Resource ARNs (replace placeholders like
- Run the deployment - the script will automatically attach all
.jsonfiles (except-example.json) to your IAM role
You can specify a custom directory containing your policy files:
# Use policies from a custom directory
bash run.sh --github-org myorg --github-repo myrepo --policies-dir /path/to/my/policies
# The custom directory should contain .json files (not ending in -example.json)
# that follow the same IAM policy format as the examplesIf no --policies-dir is specified, the script uses the default policies/ directory in this repository.
s3-example.json: S3 bucket and object management permissionscloudformation-example.json: CloudFormation stack deployment permissionsminimal-example.json: Minimal read-only S3 access example
- The example files are templates - you MUST customize them for your use case
- Only
.jsonfiles (not ending in-example.json) will be attached to the IAM role - Follow the principle of least privilege - only grant permissions that are actually needed
- See
policies/README.mdfor detailed configuration instructions and best practices
- Keep policies minimal and auditable.
- Remove or archive policy files you do not need (principle of least privilege).
- Review
policies/README.mdfor more details and examples.
For questions or improvements, please open an issue or pull request.