Identity and access Recommended
Separate the roles for plan and apply
Give pull requests a read-only role that can only plan. Give the write role only to the main branch in a protected environment. Give the app its own runtime role.
How to do it
Pull request code may come from anyone with push rights, so its role must not change anything. Bind each role's trust to the event, branch or environment in the OIDC token, as in OIDC for CI. An environment claim proves only the environment, so limit the production environment's deployment branches to main in the code host. The apply role may not change its own trust policy or the audit trail. The app's runtime role has no rights over infrastructure.
Example
# Plan role: pull request jobs only
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:example/shop:pull_request"]
}
# Apply role: only jobs in the production environment, which allows only the main branch
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:example/shop:environment:production"]
}
How to check
A pull request job that tries to assume the apply role gets AccessDenied. The plan role's policy holds only read actions.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/identity-and-access/separate-plan-and-apply-roles.