Skip to content
QSWEQB
hardDesignScenarioConceptSeniorStaffLead

Nobody has write access to production, but the deploy pipeline can change anything. Where does separation of duties live now?

Removing humans from production moves the privilege into the pipeline, so the boundary becomes who can change what it runs and which identity it assumes. Duties are separated by branch protection, environment approvals and deploying by digest, and it fails when one change alters both code and workflow.

5 min readUpdated 2026-07-28

What the interviewer is scoring

  • Does the candidate see that removing human access relocates the privilege rather than reducing it
  • Whether the same-pull-request problem is identified, where code and pipeline definition change together
  • That the pipeline's own identity and its ability to widen its permissions is treated as in scope
  • Can the candidate name what the deployed artefact must be bound to for the approval to mean anything
  • Whether compensating detection is proposed for the duties a small team genuinely cannot separate

Answer

Removing human access relocates the privilege

Locking engineers out of production writes and letting automation deploy is genuinely better, but it is not a reduction in privilege. It is a transfer. The pipeline now holds the union of every permission any deployment might need, it runs unattended, and it acts on behalf of whoever most recently changed the instructions it follows. The control question stops being "who can write to the database" and becomes "who can cause the pipeline to write to the database, and does anyone independent see it happen".

That reframing is most of the answer. Separation of duties in this world is not about roles in an identity provider; it is about the integrity of the path from a proposed change to a running process. Three things must hold: the change was reviewed by someone other than its author, the thing that ran is the thing that was reviewed, and the pipeline could not exceed what that change was permitted to do.

The boundaries and how each is bypassed

Control pointWhat it is meant to enforceHow it is actually bypassed
Branch protection with required reviewNo unreviewed code reaches the deployable branchAn admin merges directly, or protection excludes administrators, or a bot account approves
Approver is not the authorTwo people see every changeA trivial commit is added by the reviewer, making them a co-author with nobody left to review
Protected environment with a manual gateA human decides when production changesThe gate approves a workflow reference, not a commit, and the workflow was edited after review
Pipeline identity scoped per environmentA staging job cannot touch productionOne long-lived credential in a shared secret store, reachable from any branch's job
Immutable artefactWhat ran is what was reviewedDeploy by mutable tag, so the tag is repointed after approval
Runner isolationA job cannot read another job's secretsA self-hosted runner with a cached credential and no clean-up between jobs

The rows that quietly void the whole scheme are the first two, and not by the bypasses listed against them. Both can be satisfied in full — protected branch, required review, an approver who is not the author — while nothing that mattered was reviewed. If your pipeline definition lives in the same repository as the code — which is the norm and is otherwise a good thing — then a single pull request can change both the application and the steps that deploy it. A reviewer approving a feature has approved a new deploy step, and if the reviewer's attention was on the feature, the change of duties happened invisibly. Treat pipeline definitions, IAM policy, and anything that alters the release path as a distinct review population: separate ownership rules, a different set of required reviewers, and ideally a separate repository for the deployment logic so the diff cannot hide inside a feature branch.

Bind the approval to the artefact

An approval that names a branch or a tag approves an intention. An approval that names a content digest approves a fact. Between those two lies the whole class of attacks and accidents where the reviewed commit and the deployed bytes differ: a rebuilt image under the same tag, a dependency that resolved differently on the second build, a release job triggered from a stale ref.

So the release should build once, record the digest, and every downstream promotion should reference that digest. Where the toolchain supports build provenance — an attestation signed by the builder tying the artefact back to the source commit and the workflow that produced it — verify it at admission rather than trusting the registry. This is the same argument as reproducibility, arriving from the compliance side: the evidence chain from change record to running workload only holds if each link names something immutable.

The pipeline's own permissions

A deployment identity that can modify its own role, create new roles, or read the secret store wholesale has no separation of duties in any meaningful sense, because a single reviewed-but-malicious or reviewed-but-careless change can grant itself anything. Two constraints are worth arguing for. First, the deployment identity is scoped per environment and assumable only from a job running on the protected branch, so a pull-request build physically cannot obtain it. Second, changes to the pipeline's own permissions go through a different path with different approvers from ordinary application changes, because that is the change class where the reviewer is deciding how much damage every future change can do.

Non-human identities are also where access reviews fall apart. Humans leave and a joiner-mover-leaver process catches them; a service principal created for a migration two years ago has no leaving date, no owner after a reorganisation, and frequently more privilege than anyone currently employed. If you can only add one recurring control here, make it an inventory of non-human identities with a named human owner and a last-used timestamp, because unused-and-powerful is the combination that ends up in incident reports.

Where a small team has to be honest

With three engineers and an on-call rotation, some separation is unavailable. The failure is not the absence of four eyes; it is pretending otherwise on a questionnaire. What you can do instead is make the unseparated action visible and expensive to hide.

Break-glass exists precisely for this, and it works only if the elevation is short-lived, alerts a channel the actor does not control, and produces a record reviewed by someone else afterwards — the review can be after the fact, which is what makes it possible in a small team. Beyond that, favour detection over prevention: alert on any production change whose digest has no corresponding approved change record, on any direct write to a production datastore by a human identity, and on any modification to branch protection or environment configuration. Reconciling deployed digests against approved change records weekly is a control an auditor will accept and a three-person team can actually run, and it catches the bypass rather than merely discouraging it.

The distinction to draw out loud is between preventive and detective controls. Preventive controls need someone else present; detective controls need only that the evidence is generated somewhere the actor cannot reach and that a second person looks. In a team too small for the first, the second is not a consolation prize — it is the design.

Likely follow-ups

  • Your pipeline needs to run a data fix that no migration covers. How is that authorised and evidenced?
  • How do you stop a self-hosted runner from becoming the standing production credential you removed?
  • What evidence would you hand an auditor to show that no change reached production without an independent approver?
  • Three engineers, one of whom is on call. What separation is real and what is theatre?

Related questions

separation-of-dutiescicdchange-managementnon-human-identitysupply-chain