Skip to main content
INS // Insights

Segregation of Duties Access Review

Updated September 2026 · 10 min read
Segregation of Duties Access Review

A policy PDF that says “no one shall both approve and pay” does not fail an access review. A living person who can do both in the billing system does. Rutagon builds segregation of duties access review as a recertification job that evaluates toxic combinations against current entitlements, then opens a revoke or compensating-control ticket before the reviewer clicks approve. The PDF stays in the policy binder. The finding lives in the review.

Mid-market SaaS teams often inherit SoD language from the first audit cycle and never connect it to group membership. Reviewers see a role name, not the pair of permissions that matter. We ingest effective access from the systems in scope, expand groups and permission sets, and test named pairs. A reviewer who tries to rubber-stamp a toxic pair gets a block, not a footnote.

This is not a GRC configuration tutorial and not a catalog of every industry pair. It is the engineering we deliver so the review itself is where SoD is proven.

Segregation of Duties Access Review in the Recertification Pass

Segregation of duties access review runs inside the same campaign that already certifies who should keep access. We do not add a second annual workshop. Each review item carries the worker, the system, the effective permissions, and any SoD hits against a pair table you own. The pair table is short on purpose: pay-and-approve, deploy-and-approve-prod, identity-admin-and-payroll, and the few pairs your auditors already care about.

Hits are computed, not guessed. If the billing app expresses “approve” as a permission set and “pay” as a group, we expand both. Nested IdP groups are expanded too. A user who only looks harmless at the role-name layer still fails when the pair is present.

The reviewer action is constrained. Approve is disabled on a hit until the pair is broken or a compensating control is recorded with an owner and an expiry. “Accepted” without those fields is not a close. That is the same discipline we use when access reviews are automated instead of mailed as a spreadsheet.

Toxic Combinations, Not Role Folklore

Toxic combinations are pairs (or small sets) of effective permissions that violate a duty split. They are not vibes about “too much access.” A platform admin who cannot touch payroll is not a hit. A support engineer who can both refund and change bank details is.

We store each pair as data: left permission query, right permission query, systems, and severity. Queries are testable. When a vendor renames a permission, the query fails closed and the pair shows “unevaluable” instead of a clean pass. Unevaluable items are findings. Silent skip is how PDFs survive and reviews lie.

Custom apps without SCIM still participate. We read their admin export or database grant table the same way we do for custom application access reviews. If the app cannot emit effective permissions, it cannot claim an SoD pass. That gap is the work.

What the Reviewer Sees and What We Write Back

The reviewer UI we ship is a packet, not a philosophy. They see the person, the two permissions, the last time each was used if the system tells us, and the recommended break: remove left, remove right, or split into two people. They pick one. The mutate job runs or a ticket opens if the mutate needs a change window.

Compensating controls are first-class. A dual-control in the payment processor can hold if we can show the control is on and sampled. A “manager watches Slack” note cannot. Expiry is required. When the expiry lands, the pair is re-tested. If the pair is still live, the review item reopens.

review_id: recert-q-sample
subject: emp-2201
system: billing
sod_hit:
  pair: approve-and-pay
  left: payments.approve
  right: payments.execute
decision: remove_right
compensation: none

Write-back goes to the IdP group or the SaaS permission set. Security automation owns that connector. The GRC campaign stores the packet.

Evidence That Is Not the Policy Binder

Auditors who ask about SoD should receive the pair table version, the campaign run, every hit, and every decision. They should be able to pick a user from the billing export and see whether a pair fired. A policy acknowledgement from onboarding does not answer that question.

We also keep the unevaluable list. If a system could not expand permissions that week, we say so. That honesty is better than a green campaign that never saw the grants. Freshness of the entitlement extract follows the same TTL thinking as evidence freshness tracking.

On AWS, unused or overly broad IAM can inform a pair, but cloud IAM last-accessed data is not SoD by itself. AWS describes Access Analyzer for policy findings. We use those signals as inputs. The duty pair still has to be defined in your business systems.

Pair tables that survive a vendor rename

The pair table is a product we maintain with you, not a one-time workshop artifact. Vendors rename permission sets. IdP groups get cloned for a project and never deleted. If the left query still points at a retired permission name, the pair goes unevaluable and the campaign must show that. We add a contract test per pair: a fixture user who should hit, a fixture user who should miss, and a fixture that proves the query still binds to a live permission ID.

Those fixtures live next to the review job. When a SaaS export schema changes, the test fails before reviewers see a clean pass. That is the difference between a PDF policy and a review that finds toxic combinations. The PDF does not notice the rename.

We also version the pair table. A pair added mid-window does not silently rewrite last month’s campaign. Each campaign pins a pair-table version. Auditors who ask “what did you test?” get that version plus the hits. Changing the table is a change record, not a quiet edit.

Compensation is versioned the same way. A dual-control that existed in the payment processor in month one and was turned off in month three must not still justify a hit in month three. We re-read the compensating control on each campaign, or we mark it expired. A screenshot of a vendor setting from onboarding is not a living control.

If two systems implement the same duty split—billing in-app and a separate treasury tool—we do not assume one pair covers both. Each system gets queries. A person who can approve in one and pay in the other is still a combination if your table says so. Cross-system pairs are harder extracts and they are the ones a policy PDF never operationalizes.

Privileged cloud IAM can appear in a pair when the duty is “change identity and change payroll.” That is not every IAM admin. We only add the cloud side when you can name the permission that fulfills a duty. Analyzer-style policy findings can prompt a pair; they do not auto-create one.

Frequently Asked Questions

Can we just ban the admin role and skip SoD pairs?

Banning a named admin role misses people who assembled the same pair from three smaller groups. Pairs test effective access. Role bans are still useful as a coarse guard, and they are not a substitute for the combination check during review.

What if the only two accountants both need approve and pay?

Then you have a staffing constraint, not a software mystery. We record a compensating control you can actually operate, with an owner and an expiry, and we re-test when headcount changes. We do not hide the pair behind a renamed role.

Do toxic combinations include production deploy plus production approve?

They can, if that pair is in your table. We do not invent a universal engineering SoD list. Your auditors and your change-management policy decide the pair. We make the pair computable in the review.

Does a clean SoD review replace joiner checks?

No. A joiner can be minted into a toxic pair on day one if provisioning ignores the table. The pair table should gate grants, not only recertify them later. Review is the backstop, not the only control.

See what an Access & Credential Governance Diagnostic finds in your environment. Call 907-841-8407, email contact@rutagon.com, or use rutagon.com/contact.