Put the apply job in a GitHub environment that has required reviewers. The job pauses until an approver signs off, and environment secrets are released only after that. Add prevent self-review and a branch restriction so the person who triggered the run cannot approve it.
What environments provide
GitHub's documentation on managing environments lists these protection settings:
- Required reviewers: up to 6 people or teams. Only one needs to approve for the job to proceed.
- Prevent self-review: optional. Stops users approving workflow runs they triggered.
- Wait timer: optional minutes to wait before jobs using the environment proceed.
- Deployment branch and tag restrictions: limit which branches and tags can deploy to the environment.
- Environment secrets: available only to jobs that use the environment, and only after its protection rules pass.
Plan availability matters. GitHub states users on the Free plan can only configure environments for public repositories, while Team organizations and Pro users can for private repositories. Check the current docs for each feature on your plan.
Why this suits infrastructure changes
A plan is safe to run in a pull request. An apply is where real change happens. Splitting them lets everyone review the plan while only a small group can release the apply. The environment becomes the approval point, and the secrets or role assumption that apply needs sit behind it.
If the apply credential is an OIDC role, restrict its trust policy to the environment too. See Terraform deploys from GitHub Actions with OIDC.
Setup steps
- Create environments named for your targets, such as
stagingandproduction. - On production, add required reviewers from the team that owns the target account.
- Turn on prevent self-review.
- Restrict deployment to the protected default branch and release tags.
- Put cloud credentials or role identifiers in environment secrets, not repository secrets.
- Reference the environment in the apply job with the
environmentkey. - Make the plan job output a saved plan so the apply runs what was reviewed. See a saved plan as change evidence.
Design choices
| Choice | Trade off |
|---|---|
| One reviewer enough | Fast, but one person is a single point of failure |
| Wait timer | Gives time to cancel, adds delay |
| Branch restriction | Stops deploys from feature branches |
| Separate environments per account | More setup, cleaner separation |
Note GitHub says only one required reviewer needs to approve, even if you list several. If you want two approvals, environments alone will not give you that, so look at pull request review rules for the second check.
What this does not cover
Approving a run is not the same as reading the plan. Train approvers to open the plan output and the diff, and put the plan summary in the job log where it is easy to see. Also remember that admins and bypass permissions may change what is enforced elsewhere. See branch protection and admin bypass.
Where Safeguard fits
Safeguard policies and gates can hold pull requests until required checks pass, and its compliance and evidence automation can keep records of approvals. The environment approval itself lives in GitHub.
Try it yourself
Click through it at your own pace, or open it full screen.
Click through the gate and look at which conditions must pass before a merge is allowed.
Quick check
If I list four reviewers, do all four have to approve?
No. GitHub says only one required reviewer needs to approve for the job to proceed.
Are environment secrets available before approval?
No. GitHub says environment secrets are available only after the environment's protection rules pass.
Sources
Last reviewed: 19 October 2026.