Bash scripts to configure AWS IAM for GitHub Actions OIDC authentication — no long-lived access keys needed.
| Resource | Description |
|---|---|
| OIDC Identity Provider | token.actions.githubusercontent.com in your AWS account |
| IAM Role | Assumable by GitHub Actions via OIDC federation |
| IAM Policy | Permissions granted to the role (S3, ECR, ECS, CloudFormation, CloudWatch Logs by default) |
- AWS CLI v2 installed
- Sufficient IAM permissions to create OIDC providers, roles, and policies
bash4+
-
Setup Environment:
cp .env.example .env nano .env
Fill in your AWS credentials, account ID, and GitHub org. Set
GITHUB_REPOto control access scope:GITHUB_REPOTrust policy subject "*"repo:ORG/*— any repo in the org can assume the role"my-app"repo:ORG/my-app:*— single repo, all refs"my-app:{dev,main}"Branch-locked — only devandmainbranches"my-app:{dev,main},backend:{dev,main}"Multiple repos, each with specific branches -
Run Setup:
./setup.sh
The script will confirm your settings before creating the OIDC provider, IAM role, and attaching policies.
-
Use in GitHub Actions:
Add the following to your
.github/workflows/deploy.yml:permissions: id-token: write # Required for requesting the JWT contents: read # Required for actions/checkout jobs: deploy: runs-on: ubuntu-latest steps: - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::<ACCOUNT_ID>:role/github-actions-oidc-role aws-region: us-east-1 - name: Test AWS Access run: aws sts get-caller-identity
For ECS deployments, you can extend the workflow:
- name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v2 - name: Build, tag, and push image to ECR env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: my-app IMAGE_TAG: ${{ github.sha }} run: | docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - name: Download task definition run: | aws ecs describe-task-definition --task-definition my-app \ --query taskDefinition > task-definition.json - name: Update ECS task definition id: task-def uses: aws-actions/amazon-ecs-render-task-definition@v1 with: task-definition: task-definition.json container-name: my-app image: ${{ steps.login-ecr.outputs.registry }}/my-app:${{ github.sha }} - name: Deploy to ECS uses: aws-actions/amazon-ecs-deploy-task-definition@v2 with: task-definition: ${{ steps.task-def.outputs.task-definition }} service: my-app-service cluster: my-cluster wait-for-service-stability: true
├── .env # Your private configuration (git-ignored)
├── .env.example # Template for configuration
├── .gitignore # Prevents committing secrets
├── README.md # This file
├── setup.sh # Main entry point (runs scripts 01-03)
├── scripts/
│ ├── 01-create-oidc-provider.sh # Create/Update OIDC identity provider
│ ├── 02-create-iam-role.sh # Create IAM role with trust policy
│ ├── 03-attach-policies.sh # Attach permission policies
│ └── 99-cleanup.sh # Tear down all resources
└── policies/
├── trust-policy.json # Who can assume the role
└── permissions-policy.json # What the role can do
The default policies/permissions-policy.json grants the following:
| Statement | Actions | Purpose |
|---|---|---|
| AllowS3Access | s3:GetObject, PutObject, ListBucket |
Upload/download artifacts to S3 |
| AllowECRAccess | ecr:GetAuthorizationToken, BatchCheckLayerAvailability, GetDownloadUrlForLayer, BatchGetImage, PutImage, InitiateLayerUpload, UploadLayerPart, CompleteLayerUpload |
Push/pull container images |
| AllowCloudFormationDescribe | cloudformation:DescribeStacks, ListStacks |
Read CloudFormation stack info |
| AllowECSTaskDefinitions | ecs:RegisterTaskDefinition, DescribeTaskDefinition, DeregisterTaskDefinition, ListTaskDefinitions |
Manage ECS task definitions |
| AllowECSServiceManagement | ecs:UpdateService, DescribeServices, ListServices |
Deploy to ECS services |
| AllowECSTaskManagement | ecs:DescribeTasks, ListTasks, RunTask, StopTask |
Run and monitor ECS tasks |
| AllowECSClusterRead | ecs:DescribeClusters, ListClusters |
Read ECS cluster info |
| AllowPassRoleForECS | iam:PassRole (conditioned to ecs-tasks.amazonaws.com) |
Pass execution/task roles to ECS |
| AllowCloudWatchLogsForECS | logs:CreateLogGroup, CreateLogStream, PutLogEvents, DescribeLogGroups, DescribeLogStreams |
ECS container logging |
This project uses multiple thumbprints (OIDC_THUMBPRINTS) for the GitHub OIDC provider. This prevents your workflows from breaking when GitHub rotates its certificates.
Edit policies/permissions-policy.json to grant only the specific permissions your workflow needs (e.g., only specific S3 buckets, ECR repositories, or ECS clusters/services).
The GITHUB_REPO variable in .env controls how broadly the role can be assumed:
# All repos in the org
GITHUB_REPO="*"
# Single repo, all refs
GITHUB_REPO="my-app"
# Only specific branches from one repo
GITHUB_REPO="my-app:{dev,main}"
# Multiple repos, each with specific branches
GITHUB_REPO="my-app:{dev,main},backend:{staging,main}"The generated trust policy sub condition patterns:
GITHUB_REPO |
Generated pattern |
|---|---|
"*" |
repo:org/* |
"my-app" |
repo:org/my-app:* |
"my-app:{dev,main}" |
repo:org/my-app:ref:refs/heads/dev, repo:org/my-app:ref:refs/heads/main |
To remove all created resources from your AWS account:
./scripts/99-cleanup.sh