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.
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 point | What it is meant to enforce | How it is actually bypassed |
|---|---|---|
| Branch protection with required review | No unreviewed code reaches the deployable branch | An admin merges directly, or protection excludes administrators, or a bot account approves |
| Approver is not the author | Two people see every change | A trivial commit is added by the reviewer, making them a co-author with nobody left to review |
| Protected environment with a manual gate | A human decides when production changes | The gate approves a workflow reference, not a commit, and the workflow was edited after review |
| Pipeline identity scoped per environment | A staging job cannot touch production | One long-lived credential in a shared secret store, reachable from any branch's job |
| Immutable artefact | What ran is what was reviewed | Deploy by mutable tag, so the tag is repointed after approval |
| Runner isolation | A job cannot read another job's secrets | A 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
- What does least privilege look like in practice, and what is separation of duties there to prevent?mediumAlso on separation-of-duties6 min
- How do you design a system so an auditor can prove who accessed a record and why?mediumAlso on separation-of-duties8 min
- A planned upgrade window opens and correlation stops working, so operations sees thousands of uncorrelated alarms. What is wrong with your inventory and change data?hardAlso on change-management5 min
- You have been asked to roll agile out across twelve teams. How would you approach it, and why do most transformations disappoint?hardAlso on change-management4 min
- If T+1 was hard, why is same-day or atomic settlement not simply one more day of compression?hardSame kind of round: concept5 min
- Where do you draw the line between a unit test and an integration test, and how do you keep a few thousand of them under ten minutes?hardSame kind of round: concept5 min
- How does your order placement change on a venue that allocates pro rata within a price level instead of first in, first out?hardSame kind of round: concept6 min
- A claim is notified and nobody yet knows what it will cost. Why does the system have to put a number on it immediately, and what happens to that number?hardSame kind of round: concept4 min