How to Enforce Separation of Duties in CI/CD
GitHub already blocks self-approval; the deploy side needs an environment gate so the person who merged cannot also release unreviewed.
Separation of duties (often "four eyes") means one person cannot both create and release a change. GitHub disallows approving your own pull request, and you add a protected environment with required reviewers to enforce it on the deploy side. This is educational guidance, not a legal control mapping.
Steps
- Require at least one approval and enable Code Owner review on the default branch.
- Create a protected environment (for example production) with required reviewers.
- Set the reviewer list to a group that excludes typical change authors where possible.
- Optionally add a job-level guard that fails if the actor equals the PR author.
Deploy job gated by environment
.github/workflows/deploy.yml
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # required reviewers approve the release
steps:
- uses: actions/checkout@v4
- run: ./deploy.shOptional actor guard
.github/workflows/deploy.yml
- name: Block self-release
run: |
if [ "${{ github.actor }}" = "${{ github.event.pull_request.user.login }}" ]; then
echo "Author cannot approve their own release"; exit 1
fiNotes
- The environment approval is recorded and exportable as evidence of the second signer.
- GitHub refuses self-approval on the PR, so the merge side is already covered.
Related guides
How to Enforce Required Reviewers for CI Change ManagementEnforce required pull request reviewers and approvals in GitHub as a SOC 2 change management control, so no c…
How to Add Approval Gates With EnvironmentsAdd human approval gates to GitHub Actions deploys with protected environments, required reviewers, and a wai…
How to Segregate Production Credentials in CIKeep production credentials out of build and test jobs in GitHub Actions by binding them to a protected envir…