A machine identity can pass every least privilege review and still be able to complete a sensitive process end to end on its own. Least privilege asks whether each permission is needed; segregation of duties (SoD) asks whether any single identity holds a combination of permissions that should never sit together. The two controls overlap, and frameworks often cite them in the same breath, but they fail in different ways, and for service accounts, CI/CD pipelines and AI agents the gap between them is where the dangerous access hides. This guide compares the two for non-human identities: what each protects against, how each fails, the toxic combinations that survive a perfectly right-sized policy, and how to test both. It is for identity governance, cloud security and platform teams. Platform examples are listed alphabetically and are illustrations, not recommendations.
Key takeaways
- Different questions, different tests. Least privilege is tested per identity against its task; SoD is tested across permissions, identities and processes against a conflict ruleset.
- Toxic combinations survive right-sizing. A CI identity that needs to write code and needs to approve deployments can be minimal for its task and still be an SoD conflict.
- Indirect permissions defeat both. Passing a role, attaching a service account, creating a pod or minting a token lets an identity act with permissions it does not hold, so tests must use effective, not granted, access.
- Agents need SoD more than people do. An agent that drafts and approves its own change, or holds production and development credentials in one workflow, breaks SoD at machine speed and without collusion.
- Enforce outside the identity. Approvals, self-review prevention and incompatible-access rules belong in the platform, not in the identity's own code or instructions.
The short answer
Least privilege shrinks what any one identity can do. SoD makes sure no one identity can do the whole of something sensitive. You need both: least privilege without SoD leaves small identities that can still create and approve the same change; SoD without least privilege leaves well-separated identities that each hold far more than they need, so compromising any one of them is still severe. NIST CSF 2.0 PR.AA-05 names both in one outcome, and NIST SP 800-53 Rev. 5 splits them into AC-5 Separation of Duties and AC-6 Least Privilege. The Segregation of Duties Guide and the Least Privilege Techniques Guide cover each control in depth; this page covers where they diverge for machines.
Different goals, different questions
| Dimension | Least privilege | Segregation of duties |
|---|---|---|
| Core question | Does this identity need this permission for its task? | Can any one identity complete this sensitive process alone? |
| Unit of analysis | One identity and its permissions | Pairs or sets of permissions, across identities and systems |
| Threat addressed | Blast radius when an identity is compromised or misused | Abuse without collusion: fraud, unreviewed change, self-approval |
| NIST SP 800-53 Rev. 5 | AC-6 and enhancements, for example AC-6(1), AC-6(5), AC-6(7), AC-6(9) | AC-5; AC-5 discussion also separates access administration from audit administration |
| Typical evidence | Unused permission reports, policy diffs, usage-based policy generation | Conflict ruleset, violations report, approved exceptions with compensating controls |
| Who owns the rule | Workload owner and platform team | Process owner, risk and audit |
| How it fails silently | Unused or indirect permissions accumulate | Conflicts form across two systems or through indirect paths that no rule covers |
| Natural enforcement point | Policy authoring, permission guardrails, unused access removal | Access request workflow, deployment gates, review rules that block self-approval |
The AC-5 discussion states the aim plainly: separation of duties "addresses the potential for abuse of authorized privileges and helps to reduce the risk of malevolent activity without collusion." AC-6 applies least privilege not only to users but to "processes acting on behalf of users" and system processes, which is the NHI case.
How each fails: four outcomes
| Least privilege | SoD | What it looks like for an NHI | Consequence |
|---|---|---|---|
| Passes | Passes | Build identity can push artefacts only; separate deploy identity gated by a human approval | Compromise of either is contained and cannot complete a release alone |
| Passes | Fails | Pipeline identity scoped to one repository can both merge pull requests and approve them, because both are genuinely used | Unreviewed code reaches production; every review shows "minimal" |
| Fails | Passes | Separate build and deploy identities, but each holds account-wide admin "to be safe" | Separation is on paper only; either identity can grant itself the other's rights |
| Fails | Fails | One shared service account with owner rights used by build, deploy and an agent | Any compromise or agent error is total |
The second row is the one least privilege reviews never catch, because each permission is justified by usage. The third row is the one SoD reviews miss when they check role names rather than effective permissions.
Toxic combinations at minimal privilege
A toxic combination is a set of permissions that is harmless alone and dangerous together. For machines, the most common combinations come from indirect permissions: rights that let an identity act through another identity or resource. The examples below are from each platform's own documentation.
| Platform | Combination or permission | Why it is toxic | Control |
|---|---|---|---|
| AWS | iam:PassRole on a broad resource plus permission to create compute (a function or instance) | AWS documents that a user who can pass a role to a service gains that role's permissions indirectly; PassRole itself generates no CloudTrail event | Restrict the Resource to approved roles and use the iam:PassedToService condition; AWS warns against controlling PassRole with ResourceTag |
| GitHub | A workflow token that can create and approve pull requests, in a repository where one approval allows merge | The automation can author and approve the same change | Leave "Allow GitHub Actions to create and approve pull requests" off; require approval of the most recent reviewable push by someone other than the pusher |
| GitHub | Deployment environment without reviewers, or with reviewers who triggered the run | The person or automation that starts a deployment also approves it | Required reviewers with Prevent self-review; environment secrets are released only after the rules pass |
| Google Cloud | iam.serviceAccounts.actAs (Service Account User) on a privileged service account plus permission to deploy a resource | Code on the resource runs as the attached service account; Google notes that default service accounts are automatically granted the Editor role on the project | Grant actAs per service account, not per project; avoid default service accounts |
| Google Cloud | Token Creator, signBlob or implicitDelegation on another service account | Mints credentials for that account; delegation chains let A reach C through B | Treat these as privileged; audit delegation chains, not single grants |
| Kubernetes | create on pods or workload resources in a namespace | The Kubernetes docs state this implicitly grants the API access of any service account in that namespace, and the Secrets and volumes pods can mount | Separate trust levels by namespace; enforce Baseline or Restricted Pod Security Standards |
| Kubernetes | escalate, bind or impersonate; create on serviceaccounts/token; CSR create plus approval; get on nodes/proxy | Each bypasses normal escalation checks; get on nodes/proxy is not read-only and bypasses audit and admission | Reserve for a very small set of administrators; review periodically |
| Microsoft Entra | Two access packages that must not be held together, configured in one direction only | Incompatibility rules are one-directional, so the reverse request is still allowed | Configure incompatibility on both packages; review the Additional access column for existing overlaps |
Two lessons follow. First, an identity's minimal policy can still contain one of these grants, because the task genuinely uses it; least privilege does not flag it. Second, the conflict is often between a permission and a capability it unlocks, not between two business functions, so SoD rulesets written for ERP roles do not cover it. For cloud path analysis see How to Find IAM Privilege Escalation Paths in AWS.
NHI and agent cases: threat model by identity type
Service accounts and integration users
- Threat: credential theft (ATT&CK T1078.004 Cloud Accounts) and misuse by the people who can read the credential.
- Architecture in words: one application identity reads and writes to a system of record, often through an integration user created years ago.
- Least privilege failure: broad grants never trimmed because nobody owns the account.
- SoD failure: the integration user can create a vendor and release a payment, because the integration does both. Apply the same conflict rules you apply to people; see the Segregation of Duties Matrix Template.
CI/CD pipelines
- Threat: a poisoned dependency or malicious pull request running with the pipeline's identity.
- Architecture in words: the pipeline builds, tests, signs and deploys, often under one token or role.
- Least privilege failure: write access to all repositories or all environments.
- SoD failure: one identity can change code, approve it and deploy it. Split build, sign and deploy into separate identities and put a human or policy gate between them. See the CI/CD Pipeline Identity Security Guide.
AI agents
- Threat: prompt injection, tool misuse or plain error, with the agent acting faster than any reviewer.
- Architecture in words: an agent plans and calls tools under an identity that may be its own, a service account, or a delegated user token.
- Least privilege failure: the agent inherits a developer's or an account-wide token. In the PocketOS database deletion, a token created to manage custom domains was account-scoped; a coding agent found it and deleted a production volume and its backups in one API call.
- SoD failure: the agent can both propose and execute a destructive change, or works across development and production in one workflow. In the Replit agent database deletion, the agent had production write access from the same workflow it used for development. Separate the proposing identity from the executing one and keep approval outside the agent; see the AI Agent Action Approvals and Spending Limits Guide.
How to test least privilege
- Compare granted with used. Use the platform's last-accessed and unused-access data. AWS IAM Access Analyzer, for example, reports unused roles, access keys, passwords and unused services and actions on active roles; it does not analyse service-linked roles.
- Generate a candidate policy from activity. Access Analyzer can generate a policy from CloudTrail activity over a date range. Treat it as a starting point: activity windows miss rare tasks such as quarterly jobs.
- Block regressions in pipelines. Custom policy checks can flag a policy that grants new access compared with the existing version, or that allows specific critical actions. Run them on every infrastructure change.
- Look for wildcards and future scope. The Kubernetes documentation notes that wildcard rules grant rights to object types created in future, not only those that exist today.
- Retest after trimming. Remove in stages, watch for authorisation failures, and keep a rollback path (reapply the previous policy version) for the first days.
How to test segregation of duties
- Write conflicts as capabilities, not role names. "Can merge to main" and "can approve a pull request to main" are the conflict; the roles that grant them vary by system.
- Resolve effective access. Expand groups, role assignments and indirect grants (PassRole, actAs, workload creation, impersonation, token minting) before testing rules. A conflict reachable through an indirect path is a conflict.
- Test across identities that one party controls. If the same team owns the identity that writes and the identity that approves, and can use both, the separation is nominal. Map identities to owners and test owner-level combinations too.
- Check the platform guardrails directly. For example: whether automation may create and approve pull requests, whether the most recent push needs another approver, whether deployment environments prevent self-review, whether incompatible access rules are configured in both directions.
- Report existing violations, not only blocked requests. Entra incompatible-access rules block new requests and conflicting admin assignments but do not remove existing overlaps; the Additional access column shows users who already hold both.
- Exercise it. In a non-production environment, attempt the end-to-end sensitive process with a single NHI and record where it is stopped. A rule nobody has tried to break is a rule nobody knows works.
For review cadence and evidence see How to Run an Access Review for Service Accounts.
Decision guidance
- Start with least privilege where the main risk is blast radius: internet-facing workloads, identities with long-lived keys, anything an agent can reach. Trimming is mostly automatable.
- Start with SoD where the main risk is an unreviewed outcome: payments, production deployment, signing, access administration, audit log configuration (AC-5 separates access control administration from audit administration).
- Accept an SoD exception only with a named risk owner, a compensating detective control that someone performs (for example, review of every self-approved deployment), and an expiry date.
- Small organisations often cannot staff a second human for every approval. Use platform enforcement (required reviewers drawn from a small rota, wait timers, policy checks) and detective review rather than abandoning separation.
- Large organisations need an SoD ruleset that spans cloud, CI/CD and SaaS, not only the ERP, and an effective-permission graph to evaluate it. Without the graph, rules only see direct grants.
Worked scenario: the minimal release bot
A platform team builds a release bot. Least privilege review: it can open pull requests to the release branch, approve pull requests, and trigger the production environment, and usage shows it does all three. Every permission is used, so the review passes. SoD review using capabilities: "author change", "approve change" and "deploy change" are mutually exclusive for one identity. The bot holds all three. The fix is not fewer permissions but different identities and an external gate: the bot keeps "author change"; repository rules require approval of the most recent push by someone other than the pusher; the workflow token cannot approve pull requests; the production environment requires a reviewer with Prevent self-review on, and its deployment credential is an environment secret released only after approval. After the change the bot is still minimal, and it can no longer ship code that no second party has seen.
Detection and measurement
- Log use of privileged and indirect functions: AC-6(9) asks for logging of privileged functions; for PassRole, AWS notes you must look at the event that created or modified the resource, because PassRole itself is not logged.
- Alert on guardrail changes: changes to branch rules, environment reviewers, incompatible-access rules and workflow token settings.
- Alert on self-approval: any deployment or merge where the approver identity and the initiator identity share an owner.
Metrics:
- Percentage of NHIs with unused permissions older than 90 days.
- Number of open SoD conflicts involving NHIs, and median age.
- Percentage of SoD exceptions with a compensating control performed in the last period.
- Count of indirect-permission grants (PassRole on broad resources, project-level actAs, workload creation in sensitive namespaces) on non-admin identities.
- Percentage of production deployments with an approver distinct from the initiator.
Common failure patterns
- Using least privilege reviews as SoD evidence. "Every permission is used" proves nothing about combinations.
- SoD rulesets that stop at the ERP. The conflicts that matter for machines live in cloud IAM, CI/CD and code hosting.
- Checking direct grants only. PassRole, actAs, pod creation and impersonation turn small identities into large ones.
- One-way incompatibility rules. Entra rules apply in one direction, so a rule on package A does nothing when someone requests A while holding B unless B also lists A.
- Agents with environment-spanning credentials. As the Replit and PocketOS incidents show, instructions are not permissions; separation must be enforced in the identity and the platform.
- Shared ownership of "separate" identities. Two service accounts controlled by the same person or pipeline are one party.
Framework mapping
| Framework | Least privilege | Segregation of duties |
|---|---|---|
| NIST SP 800-53 Rev. 5 | AC-6, AC-6(1), AC-6(5), AC-6(7), AC-6(9) | AC-5; CM-5 Access Restrictions for Change for deployment gates |
| NIST CSF 2.0 | PR.AA-05: permissions managed and reviewed incorporating least privilege and separation of duties | |
| ISO/IEC 27001:2022 Annex A | 5.15 Access control; 8.2 Privileged access rights | 5.3 Segregation of duties |
| MITRE ATT&CK | T1078.004 Cloud Accounts (blast radius of a stolen identity) | T1098 Account Manipulation (an identity granting itself the other half of a conflict) |
Practitioner checklist
- Write SoD conflicts as capabilities that apply to people and NHIs alike.
- Resolve effective permissions, including indirect grants, before evaluating either control.
- Split build, sign and deploy into separate identities with an external approval between them.
- Turn off automation self-approval in code hosting and require a distinct approver for the latest push.
- Require reviewers with self-review prevention on production deployment environments.
- Give agents their own narrow identity per environment and keep approval outside the agent.
- Configure incompatible-access rules in both directions and report existing overlaps.
- Run unused-access and new-access checks in the pipeline for every policy change.
- Give every SoD exception an owner, a compensating control and an expiry.
- Exercise the end-to-end sensitive process with a single NHI in test and record where it is stopped.
Standards and references
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls (AC-5, AC-6)
- NIST: Cybersecurity Framework 2.0
- Kubernetes: Role Based Access Control Good Practices
- AWS: Grant a user permissions to pass a role to an AWS service
- AWS: IAM Access Analyzer
- GitHub: Managing environments for deployment
- Google Cloud: Roles for service account authentication
- Microsoft Learn: Configure separation of duties checks for an access package
Related NHI Mgmt Group resources: Segregation of Duties Guide · Least Privilege Techniques Guide · OWASP NHI Top 10 NHI5 Overprivileged NHI Guide · AI Agent Authorisation Guide · Access Reviews vs Continuous Access Monitoring