The default AWS OIDC trust policy scopes access by repository, meaning any GitHub Actions workflow in that repository can mint an OIDC token and assume the role — not just the Terrateam workflow. A malicious pull request that adds a new workflow file or modifies the existing one could assume the same role and exfiltrate credentials.
This guide walks through progressively stronger controls to ensure only Terrateam-originated workflow runs can assume your AWS IAM role.
Use GitHub’s job_workflow_ref claim to ensure only the Terrateam workflow file can assume the role. Any other workflow file in the repository will be denied at the AWS level.
The GitHub OIDC token includes an actor claim — the user or app that triggered the workflow. When the Terrateam server dispatches your workflow, the actor is your Terrateam GitHub App bot (e.g. terrateam-action[bot]).
Add the actor condition to your trust policy so only workflows dispatched by the Terrateam app can assume the role:
Even with the trust policy locked down, someone could open a PR modifying terrateam.yml to add malicious steps. Enterprise ci_config_update prevents Terrateam from operating on any PR that modifies the workflow file unless the author is explicitly authorized:
access_control:
enabled: true
ci_config_update: ['team:infra-admins']
terrateam_config_update: ['team:infra-admins']
Setting
Protects
Effect
ci_config_update
.github/workflows/terrateam.yml
Blocks Terrateam operations on PRs that modify the workflow file unless the author matches the ruleset
terrateam_config_update
.terrateam/config.yml
Blocks Terrateam operations on PRs that modify the Terrateam config unless the author matches the ruleset
AWS only supports a subset of JWT claims in IAM trust policy conditions. Claims like event_name, runner_environment, and repository_visibility exist in the GitHub OIDC token but are not directly usable as IAM condition keys. See the AWS documentation for the full list of supported keys.
As a workaround, GitHub allows you to customize the sub claim to include additional values. This lets you enforce these claims through the sub condition in your trust policy.
Runs from non-dispatch events, public repos, or GitHub-hosted runners
For maximum security, combine all four layers. Layers 1 and 2 are available to all users. Layer 3 requires Enterprise. Layer 4 is available to all users and provides the strongest trust policy enforcement.