A governance requirement is not inherently preventive or detective. That is an implementation choice, and it has consequences you inherit for years. This page takes one requirement, writes it both ways, and is honest about what each version cannot do.
Somebody at AnyCompany writes a sentence: no S3 bucket in this organisation may be publicly readable. That sentence is the governance requirement. It says nothing about how it will be enforced — and the two available answers behave so differently that choosing between them is the actual design work.
Write it as a service control policy. When someone calls the API that would make a bucket public, the call is evaluated against the policy and denied. Not attempted-then-reverted: denied. The bucket is never public, not even briefly.
Because the decision happens in the authorisation path, there is no interval during which the estate is wrong. The state you are trying to avoid never exists.
Write it as an AWS Config rule. The bucket gets created, Config records what it looks like, and the rule evaluates that recorded state against your condition. If it fails, you get a finding.
The bucket was public for an interval. In exchange, you can evaluate things a policy decision cannot see — the resulting configuration of a resource, rather than the shape of the call that produced it.
The obvious reaction is that preventing is strictly better than detecting, so use preventive controls for everything and skip the rest of this page. It does not work, for a reason worth understanding precisely.
Some properties you care about are not expressible as a condition on an API call. "This bucket has versioning enabled" is a property of the bucket's configuration — it can be reached by several different call sequences, changed later by a different operation, or simply never set because the default applied. A policy that inspects one request has no view of the accumulated state a resource ends up in.
Worse, a preventive control cannot help with anything that already exists. Attach one today and it governs tomorrow's calls. The four hundred buckets already in the estate are entirely outside its reach — those need something that looks at what is there, which is precisely what a detective control does.
"Nobody may delete an object without MFA." The condition key is present on the request. A policy can decide.
"Every bucket has versioning on." Not a property of any single call. Only a rule reading the resource can tell you.
Four hundred existing buckets. A preventive control is blind to all of them; it only sees future requests.
One API call — s3:PutBucketAcl making a bucket publicly readable — traced from the request to the corrected state. Switch the two controls on and off and watch where the story stops. All four combinations tell you something.
| Preventive | Detective | What actually happens |
|---|---|---|
| On | On | The mature answer. The direct path is refused outright, so there is no exposure window on that route. Detective still earns its place: it catches resources that were already non-compliant before the policy was attached, changes arriving through paths the policy does not cover, and anything created in the management account — which an SCP does not restrict. |
| Off | On | The request succeeds and the bucket is genuinely public for a measurable interval. You find out, and if remediation is wired up it gets corrected. Whether that is acceptable depends entirely on what was exposed during the window — and the window is not something you control precisely. |
| On | Off | Better than it looks for new activity, and worse than it looks overall. Tomorrow's calls are refused. But existing non-compliant buckets stay non-compliant indefinitely, and you have no way to know they are there, because nothing is evaluating resource state. |
| Off | Off | Nothing stops it and nothing notices. Worth running in the widget once, because this is the actual state of most requirements that exist only as a sentence in a policy document. |
Both mechanisms are documents you can read, review and put in version control. Worth reading them next to each other, because the difference in shape tells you more than any comparison table.
The example from the Control Tower catalogue: refuse S3 delete operations that arrive without multi-factor authentication.
Deny. And this is the element people misread most: an SCP is a ceiling on what identity policies in the account can grant. An SCP with Effect: Allow still grants nobody anything — it only widens what the ceiling permits. Permission always comes from an identity or resource policy.BoolIfExists on aws:MultiFactorAuthPresent being false means the deny only bites when the request demonstrably arrived without a second factor. Present MFA and the identical call proceeds. Note what is being inspected: a property of the request context. Nothing here can see what the bucket looks like.The same catalogue, the detective half: every S3 bucket should have versioning enabled. Delivered as CloudFormation, because that is how you get it into every account consistently.
ConfigRuleName. Parameterising the name is what lets one template deploy across many OUs and environments without editing it — which matters, because you will deploy this via StackSets to every account.AWS::Config::ConfigRule. The control is a Config rule resource. Nothing bespoke, nothing hidden — which is why you can review it like any other infrastructure.AWS means this is a managed rule: AWS writes and maintains the evaluation logic. Set Owner to a custom value instead and you supply your own Lambda function — more power, and now you own the correctness of the check.Action and Condition — verbs and request context. The Config rule is built from SourceIdentifier and Scope — a check and a set of resource types. Neither vocabulary can express the other's job. That is not an API inconsistency; it is the two mechanisms telling you honestly what they operate on.This is the tab the slides do not have room for, and the one worth arguing about. Both mechanisms are genuinely useful and both have limits that will surprise you in production. Knowing them in advance is the difference between a control that holds and an exception process that quietly eats it.
An SCP defines the maximum available permissions in an account. It does not give anyone access. If an identity policy does not permit the action, an Allow in an SCP changes nothing.
Consequence: "we attached the SCP, so the team has access now" is always wrong. Debugging a denial means checking both layers, and the SCP is the one people forget is even in the path.
Service control policies do not apply to the organisation's management account, regardless of where in the tree you attach them.
Consequence: the account with the most reach is the one your strongest preventive control cannot cover. Run no workloads there, keep the number of people who can reach it very small, and use detective controls plus CloudTrail to watch it — because that is all you have.
The evaluation has the request, the principal and the condition context. It does not have the configuration the resource will end up in, and it cannot reason about accumulated state across several calls.
Consequence: anything phrased as "every resource of this type must have property X" is not expressible preventively. That whole class of requirement belongs to the detective side.
Attaching a policy governs future calls. It performs no scan and takes no action against resources that are already there.
Consequence: a preventive control on a mature estate stops the bleeding and tells you nothing about the wound. You still need a detective sweep to find out how much pre-existing non-compliance you inherited.
This is an organisational failure mode rather than a technical one, and it is the most common way preventive controls die. A deny that blocks legitimate work generates exception requests. Enough exceptions and the policy has holes shaped like every team that complained loudest.
Consequence: narrow beats broad. A control that denies exactly the thing you mean, with a documented and genuinely usable path for the rare legitimate case, survives. One that denies a whole service does not.
Between the change landing and the rule evaluating, the resource is non-compliant and nothing is stopping anyone using it. The interval depends on when the configuration item is recorded and when evaluation is triggered.
Consequence: for a requirement where any exposure at all is unacceptable, detective controls cannot be the answer on their own — no matter how much you tune them.
A detective control produces a verdict. The resource stays exactly as it was unless something else acts. Remediation is a separate thing you have to build and own.
Consequence: a Config dashboard full of red is not a control, it is a report. The control is the loop, and the loop is only closed when a finding reliably causes a change.
Recording configuration items and running rule evaluations both have a unit cost. Recording everything in every Region and evaluating every rule against every resource type adds up faster than teams expect.
Consequence: Scope is not a tidiness setting, it is a budget setting. Scope each rule to the resource types it can actually say something about.
Detective controls only apply in the Regions where the service operates and where you have enabled recording. Preventive controls, by contrast, are evaluated in the authorisation path everywhere.
Consequence: an unmonitored Region is not a low-risk Region — it is the one place an attacker gets no findings raised against them. Pair Region-restriction preventive controls with your detective coverage so the two agree on the footprint.
Also organisational, also the most common cause of death. Findings arriving in a shared mailbox that six people are members of and nobody owns have no state, no ageing and no accountability.
Consequence: route findings into the queue your team already works from, with an owner and an ageing report. "We have Security Hub enabled" and "somebody acts on Security Hub findings" are entirely different claims.
Both mechanisms check conformance to a rule you wrote. Neither has an opinion on whether the rule was the right rule, or whether a perfectly compliant architecture is nonetheless a bad idea for what you are building.
Consequence: a fully green compliance dashboard is a statement about your rules, not about your security. If the rules are wrong, the dashboard is confidently wrong with them.
Both operate on cloud resource configuration. Neither looks at your authorisation logic, your dependency tree, your input handling, or what a trusted insider could do while remaining entirely within policy.
Consequence: governance at scale is the floor. It removes a large category of avoidable misconfiguration so your security effort can go to the problems that are actually specific to your product.
A workable decision framework. Run a requirement through these questions in order and the answer usually falls out — and for most requirements the answer is "both, doing different jobs".
Guidance is advice about where to attach a control, and it is independent of whether the control prevents or detects. A control can be preventive and elective, or detective and mandatory. The consequential column is the last one.
| Tier | What it means | Enabled by default? |
|---|---|---|
| Mandatory | Always enforced. The rules Control Tower treats as non-negotiable for a governed environment — protecting the integrity of the log archive, for instance. | Yes — on automatically, and OUs created through Control Tower get them without being asked. |
| Strongly recommended | Established practice for well-architected multi-account environments. Sensible almost everywhere, but AWS will not assume your circumstances. | No — you turn these on deliberately. |
| Elective | Lets you track or lock down actions enterprises commonly restrict. Genuinely situational — plenty of organisations legitimately want the opposite. | No — opt in per OU. |
Knowing which mechanism to use is the easy half. Attaching a preventive control to a live organisation on a Tuesday afternoon is how you find out which deployment pipelines depended on the thing you just denied. This is the sequence that avoids that.
Deploy the Config rule with no remediation attached, scoped to the resource types that matter, and let it run. You are not governing yet — you are measuring. The output is the number nobody has: how many resources violate this requirement today, and which accounts they live in.
The list will contain surprises, and some of them will be legitimate. A bucket that is public because it serves a static website is not the same finding as a bucket that is public because someone was debugging. Sort them into "must fix", "needs an exception with an owner", and "the rule is wrong". If the third pile is large, go back and narrow the rule — you have learned something before breaking anything.
Clear the existing violations before you attach anything preventive. Do this with a documented change rather than an unattended automation on first run — a bulk automated fix against resources you have not inventoried is its own incident. Once the backlog is at or near zero, you know the estate is in the state the control assumes.
Now add the SCP — to one non-production OU. Watch for a full deployment cycle. What breaks here breaks cheaply. Only when a sandbox or development OU has lived with it without incident do you move it up toward the root.
The temptation is to retire it now that the preventive control is in place. Do not. It is what catches resources arriving through paths the policy does not cover, anything created in the management account (which the SCP cannot restrict), drift from a Region you have not preventively fenced, and the day someone detaches the policy without telling you.
Last step, most often skipped. Add the requirement to the account baseline and to the Service Catalog product template, so accounts and resources created from now on start compliant instead of being corrected into compliance. This is what stops the same violation reappearing every month forever — and it is the subject of the governance lifecycle deep dive.
Step 6 above is where most organisations stop, and it is the step that determines whether you are fixing the same violation forever. This page follows one requirement all the way round the implement, provision, operate loop and shows what closing it is worth.
The full operating model on the detective side: AWS Config as the configuration recorder and rule engine, Systems Manager for grouped action and remediation, GuardDuty for threat detection, Security Hub for aggregation and prioritisation.
Step 4 said "attach it low in the tree first". Which presumes you have a tree worth attaching to. Build one here and see what the OU layout does to where controls can usefully sit.