You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This module allows you to create roles for lists of repos(subjects) and policies in the AWS account.
9
-
Curently it only supports policies in the same account as the role being created.
10
-
This is helpful for non-mono repo style groups as well as for large organizations where teams have separate repo ownership for the same AWS account.
11
-
12
-
## Debugging features
13
-
The `assume_role_names` input allows you to assume the OIDC role and act as if you were the GitHub Actions pipeline.
14
-
This is very useful for debugging while you're getting things setup.
15
-
Note: we recommend removing this once your production ready so that all further changes are only applied via the pipeline.
16
-
17
-
## Example GitHub Action
1
+
# terraform-aws-oidc-github
2
+
3
+
Provision GitHub Actions → AWS authentication via OpenID Connect, with no long-lived AWS keys.
4
+
5
+
This module creates the GitHub OIDC identity provider in your AWS account and one IAM role per entry in `role_subject-repos_policies`. Each role trusts a configurable set of GitHub subject claims (specific repos, branches, tags, environments, or pull requests) and attaches the IAM policies you specify. Based on the [official GitHub OIDC for AWS guide](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services).
The trust policy on each role pins the GitHub `sub` claim to the patterns in `subject_repos`, so a workflow running on the wrong repo, branch, environment, or tag cannot assume the role.
| One specific branch |`repo:ORG/REPO:ref:refs/heads/main`|
77
+
| Any branch |`repo:ORG/REPO:ref:refs/heads/*`|
78
+
| A tag pattern (e.g. release tags) |`repo:ORG/REPO:ref:refs/tags/v*`|
79
+
| A GitHub Environment (recommended) |`repo:ORG/REPO:environment:production`|
80
+
| Any pull request |`repo:ORG/REPO:pull_request`|
81
+
| Any workflow in any repo of an org |`repo:ORG/*`|
82
+
83
+
GitHub's full claim reference: <https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims>.
84
+
85
+
> **Tip:** Prefer GitHub Environments over branch matching when you can — environments give you reviewer gates, secrets scoping, and protection rules on the GitHub side.
role-duration-seconds: 1200#can be up to the max set in the terraform module, defaults to 15 min
102
+
role-duration-seconds: 3600# max is var.max_session_duration on the role
103
+
- run: aws sts get-caller-identity
33
104
```
34
105
106
+
The `role-to-assume` value is the full ARN of one of the roles this module created — `module.aws_oidc_github.iam_role_arns[<key>]`.
107
+
108
+
## Debugging with `assume_role_names`
109
+
110
+
Each entry in `role_subject-repos_policies` accepts an `assume_role_names` list. Any IAM role in the same AWS account named in that list is also allowed to assume the OIDC role via plain `sts:AssumeRole` — useful while you're iterating, because you can run `aws sts assume-role --role-arn ...` from your laptop and act as the workflow.
111
+
112
+
> Remove `assume_role_names` (or set it to `[]`) before going to production. Once the workflow is stable, the only path to the role should be the OIDC trust.
113
+
114
+
## Troubleshooting
115
+
116
+
**`Not authorized to perform sts:AssumeRoleWithWebIdentity`**
117
+
Almost always a `sub` claim mismatch. Add `--debug` to `aws-actions/configure-aws-credentials` (or look at the OIDC step output) to see the exact `sub` GitHub sent, then compare it character-for-character to your `subject_repos` patterns. Watch out for branch vs. tag vs. environment vs. pull_request differences.
118
+
119
+
**`MalformedPolicyDocument: Invalid principal in policy`**
120
+
Usually means the OIDC provider hasn't finished creating yet, or the ARN passed into the role's trust policy is wrong. Re-run `terraform apply`.
121
+
122
+
**`role_path` rejected**
123
+
IAM paths must start and end with `/` (e.g. `"/"`, `"/github/"`, `"/teams/platform/"`).
124
+
125
+
**Wrong AWS account**
126
+
The role lives in the account where you applied this module. The `role-to-assume` ARN in the workflow must reference *that* account ID.
127
+
128
+
**Custom audience**
129
+
If you set `audience:` on `aws-actions/configure-aws-credentials`, set the matching `aud_value` here. The default (`sts.amazonaws.com`) matches the action's default.
130
+
131
+
## Wrappers
132
+
133
+
The [`wrappers/`](./wrappers) directory contains thin wrapper modules pre-configured to call this module. They're useful if you'd rather declare your roles in `terraform.tfvars`-friendly shapes than write a `module` block. Most users won't need them.
134
+
135
+
## Contributing & releases
136
+
137
+
- This repo uses [Conventional Commits](https://www.conventionalcommits.org/) and `release-please` to drive versioning. Use `feat:`, `fix:`, `chore:`, etc. so the changelog and version bumps are correct.
138
+
- `pre-commit run --all-files`should pass before pushing — it runs `terraform fmt`, `terraform_tflint`, `yamllint`, and friends.
| <a name="input_github_tls_url"></a> [github\_tls\_url](#input\_github\_tls\_url) | GitHub URL to perform TLS verification against. | `string` | `"https://token.actions.githubusercontent.com"` | no |
69
-
| <a name="input_max_session_duration"></a> [max\_session\_duration](#input\_max\_session\_duration) | Maximum session duration in seconds. - by default assume role will be 15 minutes - when calling from actions you'll need to increase up to the maximum allowed hwere | `number` | `3600` | no |
70
-
| <a name="input_role_subject-repos_policies"></a> [role\_subject-repos\_policies](#input\_role\_subject-repos\_policies) | role name to repos and policies mapping. role name as the key and object value for repo subjects ie "repo:organization/infrastructure:ref:refs/heads/main" as well as a list of policy arns ie ["Administrator"] and list of roles that can assume the new role for debugging | <pre>map(object({<br> role_path = optional(string)<br> subject_repos = list(string)<br> policy_arns = list(string)<br> assume_role_names = optional(list(string))<br> }))</pre> | n/a | yes |
174
+
| <a name="input_aud_value"></a> [aud\_value](#input\_aud\_value) | Audience claim required in the OIDC token. Defaults to the value the official aws-actions/configure-aws-credentials action sends. | `string` | `"sts.amazonaws.com"` | no |
175
+
| <a name="input_github_tls_url"></a> [github\_tls\_url](#input\_github\_tls\_url) | GitHub OIDC issuer URL. Override only for GitHub Enterprise Server. | `string` | `"https://token.actions.githubusercontent.com"` | no |
176
+
| <a name="input_max_session_duration"></a> [max\_session\_duration](#input\_max\_session\_duration) | Maximum session duration in seconds for every role created. Defaults to 1 hour. Increase up to 43200 (12h) if your workflows need longer sessions. | `number` | `3600` | no |
177
+
| <a name="input_role_subject-repos_policies"></a> [role\_subject-repos\_policies](#input\_role\_subject-repos\_policies) | Map of IAM roles to create. The map key is the role name. Each value defines:<br/> - `subject_repos` : OIDC subject claims allowed to assume this role (e.g. "repo:my-org/my-repo:ref:refs/heads/main").<br/> - `policy_arns` : IAM policy ARNs to attach to the role.<br/> - `role_path` : (optional) IAM path for the role. Defaults to "/".<br/> - `assume_role_names` : (optional) IAM role names in the same account that may also assume this role (useful for local debugging). | <pre>map(object({<br/> role_path = optional(string)<br/> subject_repos = list(string)<br/> policy_arns = list(string)<br/> assume_role_names = optional(list(string))<br/> }))</pre> | n/a | yes |
- A GitHub OIDC identity provider in your AWS account.
6
+
- Two IAM roles trusted by that provider:
7
+
-`org-infra-main` — full Administrator access, only assumable from the `main` branch of `organization/infrastructure`. Also assumable by an SSO role for local debugging.
8
+
-`org-infra-all-branches` — `AmazonS3ReadOnlyAccess`, assumable from any branch of the same repo.
9
+
10
+
## Prerequisites
11
+
12
+
- Terraform `>= 1.5.7`
13
+
- AWS credentials with permission to manage IAM and OIDC providers (e.g. via `aws-sso-cli` or `AWS_PROFILE`)
14
+
- Update `provider "aws"` in `main.tf` with the region you want the roles created in.
15
+
- Replace `organization/infrastructure` with your own `org/repo` and the placeholder SSO role with one from your account.
16
+
17
+
## Run it
18
+
19
+
```sh
20
+
terraform init
21
+
terraform plan
22
+
terraform apply
23
+
```
24
+
25
+
## Clean up
26
+
27
+
```sh
28
+
terraform destroy
29
+
```
30
+
31
+
## Next steps
32
+
33
+
See the [root README](../README.md) for the full input reference, the GitHub Actions workflow snippet, the subject-string cheat sheet, and troubleshooting.
0 commit comments