The enforced half of who may change what: the service control policy type actually enabled in the organization root, the customer-authored SCPs and the roots, OUs and accounts each one is attached to, and the permissions boundary carried by every principal your own tagging marks as a change authority
The API supplies the facts, but a human judgement against a documented baseline turns them into evidence.
Fetch
$ aws organizations describe-organization$ aws organizations list-roots$ aws organizations list-policies --filter SERVICE_CONTROL_POLICY$ aws organizations describe-policy --policy-id <CUSTOMER_AUTHORED_SCP_ID>$ aws organizations list-targets-for-policy --policy-id <CUSTOMER_AUTHORED_SCP_ID>$ aws iam get-account-authorization-details --filter User RoleExpected output
All six responses are collected unprojected, so every field below is the name AWS returns and the name the assertions address. The first three calls take no argument; calls four and five take a policy id that MUST be one of the AwsManaged false ids returned by call three — a human substitution the assertion grammar cannot make, and the reason the placeholder is named CUSTOMER_AUTHORED_SCP_ID rather than POLICY_ID. Call six must be issued with MANAGEMENT-ACCOUNT credentials: Organizations operations may also be called from a member account designated as a delegated administrator, and a collection run there returns that member account's principals while reading exactly like the management account's. From describe-organization, an Organization object with Id, Arn, MasterAccountId, MasterAccountEmail and FeatureSet, which is ALL or CONSOLIDATED_BILLING; AvailablePolicyTypes is also returned and is DEPRECATED by AWS, which documents that it omits every policy type other than SCPs and directs you to ListRoots instead. From list-roots, Roots[] with Id, Arn, Name and PolicyTypes[], each entry carrying Type and a Status that is ENABLED, PENDING_ENABLE or PENDING_DISABLE — there is no DISABLED value, because a policy type that is off is ABSENT from the list rather than reported as off. From list-policies, Policies[] with Id, Arn, Name, Description, Type and AwsManaged, a boolean that is true for policies you cannot edit; AWS attaches the managed FullAWSAccess policy to every root, OU and account when it is created, so the list is never empty on an organization with SCPs enabled and its length says nothing about whether anyone has authored a restriction. From describe-policy, a Policy object with a PolicySummary carrying the same six fields as a list entry, and Content — the policy document itself, returned as a JSON-formatted STRING that must be parsed before any statement in it can be read. From list-targets-for-policy, Targets[] with TargetId, Arn, Name and a Type of ACCOUNT, ORGANIZATIONAL_UNIT or ROOT. From get-account-authorization-details, UserDetailList[] and RoleDetailList[] with UserName/RoleName, CreateDate, Tags, the attached and inline policy lists, and PermissionsBoundary — an optional AttachedPermissionsBoundary object carrying PermissionsBoundaryType and PermissionsBoundaryArn, absent entirely on a principal that has none.
Assertions — what makes it a pass
| Field | Must be | For | Proves |
|---|---|---|---|
| describe-organization.Organization.FeatureSet | eq "ALL"The organization has all features enabled. SCPs are available only in an organization with all features enabled; on CONSOLIDATED_BILLING every policy this recipe collects is inert. Mandatory, and therefore uninformative, in GovCloud. | every row | CM-05 |
| list-roots.Roots[0].PolicyTypes[?Type=='SERVICE_CONTROL_POLICY'] | [0].Status | existsThe SCP policy type appears in the root at all. A policy type that is off is absent from PolicyTypes[] rather than carrying a DISABLED status — the enum has no such value — so the clause below passes vacuously over an organization where SCPs were never enabled. The pipe is load-bearing: without it the [0] indexes each matched string rather than the filtered list, and the expression is empty whether the entry is present or not. | every row | CM-05 |
| list-roots.Roots[].PolicyTypes[?Type=='SERVICE_CONTROL_POLICY'].Status | eq "ENABLED"The SCP policy type is enabled rather than mid-transition; PENDING_DISABLE is an organization on its way to enforcing nothing. | every row | CM-05 |
| list-policies.Policies[?AwsManaged==`false`] | [0].Id | existsAt least one SCP in the organization was authored by you. AWS attaches the managed FullAWSAccess policy to every root, OU and account at creation, so a non-empty Policies[] is the default state of a working organization and not a restriction anyone wrote. The pipe is load-bearing for the same reason as the root clause above. | every row | CM-05 |
| list-targets-for-policy.Targets[0].TargetId | existsThe customer-authored SCP passed to call five is attached to a root, an OU or an account. This clause proves attachment ONLY because the command is bound to an AwsManaged false id: run against any policy id it is satisfied by FullAWSAccess, which AWS attaches to every root, OU and account at creation. Binding it is a human step — the grammar compares a field to a constant, never one command's output to another's — so a collector that substitutes an arbitrary policy id has produced a green result about the AWS default. | every row | CM-05 |
| get-account-authorization-details.RoleDetailList[?not_null(Tags[?Key=='ChangeAuthority' && Value=='true'] | [0]) && !PermissionsBoundary] | count_eq 0No role your own tagging marks as a change authority is missing a permissions boundary — the per-principal ceiling that applies inside the management account, where SCPs do not reach. Written as an OFFENDER LIST rather than as 'every role has a boundary', because a field projection over a list DROPS the rows that lack the field instead of reporting them false, so the every-row form silently answers about the compliant rows only. Zero on an estate that tags no roles, so read it beside the tag count. The call must be run with management-account credentials or it describes a different account's roles. | every row | CM-05 |
Authored opinion, like the commands. Units live in the operator name — max-age-days is days, and nothing here is converted for you.
Map — what it proves
- recipe1
- recipe— an authored recipe collects evidence for this control
- KSI only— a Key Security Indicator reaches it, but no recipe is authored yet
- orphan— no Key Security Indicator reaches it — a person writes it up instead
What else these families can fetch:CM 14/34 →
GovCloud
AWS Organizations is available in both AWS GovCloud (US) Regions and SCPs are one of the policy types a GovCloud organization may use, alongside RCPs, tag policies and declarative policies for EC2 and S3; backup, chat application and AI services opt-out policies cannot be created there. Organization, root, OU, account, policy and IAM ARNs use partition arn:aws-us-gov. Three GovCloud facts change how this recipe is run rather than what it means. All features are MANDATORY — the consolidated billing feature set is not offered — so FeatureSet reads ALL in every GovCloud organization and the first assertion is satisfied by the Region rather than by a decision anyone made. The SECOND call is the one with a Region constraint: AWS restricts any operation that references the organization root, naming ListRoots as its example, to the AWS GovCloud (US-West) Region, so list-roots must be issued against us-gov-west-1 regardless of where the workload runs. The other five calls carry no such restriction. And a GovCloud organization is INDEPENDENT of the commercial organization its accounts are paired with: SCPs attached in the commercial organization do not restrict the GovCloud accounts, and an assessor handed a commercial organization's policy list has been handed evidence about a different boundary.
Notes & assertions
CM-5 asks for physical AND logical access restrictions associated with changes that are defined, documented, approved and enforced. This recipe reaches one adjective and one verb. The adjective it does not reach is PHYSICAL. No AWS API returns anything about physical access to the hardware a change is made on; under the shared responsibility model that half belongs to the IaaS provider and is inherited — read it from the provider's own authorization package and the FedRAMP customer responsibility matrix, not from this output. A collection that presents these six calls as CM-5 evidence without saying so has answered half a control and labelled it whole. The verb it does reach is ENFORCE, and it reaches it properly: an SCP is not a description of a restriction, it is the restriction, evaluated by AWS on every request from every member account, and list-targets-for-policy is the difference between a policy that exists and a policy that applies to something. Two gaps keep this partial, not one. The first is approval — that the enforced set IS the documented and approved set is a comparison against a change-management record, and no call returns it. The second is subject matter, and it is the easier one to miss: the assertions below show THAT a customer-authored SCP is enforced, never WHAT it restricts. An SCP denying mechanicalturk:* satisfies every clause here exactly as well as one denying ec2:ModifyInstanceAttribute. The fourth call exists to close that by putting the policy document in the evidence — Content is returned as a JSON string and must be parsed — but no assertion can grade a policy document, so the phrase that makes this CM-5 rather than AC-3, 'associated with changes', stays a human read. Both gaps are reconciliations against your own records; the reconciliation is the CM-5 artifact and this output is the column it is reconciled against. Four ways this evidence is vacuous if it is read naively. Three are behaviour AWS documents in as many words; the fourth is an inference from a field being a list, flagged as such rather than dressed up as a citation. A policy type that has never been enabled is ABSENT from Roots[].PolicyTypes rather than present with a Status of DISABLED — the enum has no such value — so a clause of the form 'every SCP policy type entry is ENABLED' is true over an organization where SCPs were never turned on at all, which is why one assertion tests that the entry exists before another reads it. AWS attaches the managed FullAWSAccess policy to EVERY root, OU and account when it is created, so both a non-empty Policies[] and a non-empty Targets[] are the default state of a working organization rather than a restriction anyone wrote — which is why one assertion counts only the AwsManaged false subset, and why calls four and five are bound to a customer-authored policy id instead of any policy id. FeatureSet CONSOLIDATED_BILLING makes SCPs unavailable outright, so on such an organization every policy in the list is inert. And an SCP attached to nothing returns an empty Targets[]: that one AWS does not state, it follows from Targets being a list, and the assertion that rests on it should be read as an inference. The scope edge that matters most to an assessor is that SCPs do not restrict the management account. AWS states this three times on its own page and lists it first among the tasks SCPs cannot restrict: SCPs affect only member accounts, including member accounts designated as delegated administrators, and they have no effect on users or roles in the management account. The account with the broadest reach over the organization is the one account this evidence says nothing about, and its change restrictions have to come from identity-based policy and permission boundaries inside it — which is what the sixth call collects, and why the sixth call has to be run there. SCPs also do not affect service-linked roles at all, and they do not affect principals from accounts outside the organization even when a resource-based policy in your account grants those principals access. Read an SCP for what it is: a ceiling, never a grant. AWS is explicit that no permissions are granted by an SCP and that effective permissions are the intersection of what the SCP allows with what identity-based and resource-based policies allow — a principal with no IAM permissions has no access under the most permissive SCP in the world. Where a permissions boundary is also present, AWS documents that the boundary, the SCP and the identity-based policy must ALL allow the action, which is why the sixth call is collected beside the first five rather than instead of them. One failure mode worth writing into the assessment because it is silent and total: disabling the SCP policy type in a root automatically detaches every SCP from every OU, account and organization in that root, and re-enabling it does not restore the attachments — the root reverts to FullAWSAccess alone and the previous attachments are lost and not automatically recoverable. After such an event list-policies still returns every authored policy, unchanged, while nothing is enforced anywhere. The Roots[].PolicyTypes reading and the Targets[] reading are what separate those two worlds, and a collection that skips them cannot tell them apart. The permissions-boundary assertion is scoped by your own tagging rather than written as a claim over the account, for the same reason as in the AC-02 (02) recipe: no AWS call knows which of your roles are supposed to be the change authorities. It passes without saying anything on an estate that tags none, so treat the tagging standard as a written control with a manual sample rather than as coverage. What actually happened, as opposed to what was permitted, is a different recipe: CloudTrail's non-read-only event history, collected under CM-03 alongside the Config resource timeline and the Systems Manager change-request records. This one is about the restriction; that one is about the change.
References
- AWS Organizations User Guide: service control policies — SCPs require all features enabled, never grant permissions, do not affect the management account or service-linked roles, and disabling the policy type detaches every SCP irrecoverably https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html
- AWS Organizations User Guide: SCP evaluation — AWS attaches the managed FullAWSAccess policy to every root, OU and account when it is created, and SCP evaluation is deny-by-default with allow required at every level https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_evaluation.html
- AWS CLI: organizations list-roots (Roots[].PolicyTypes[] with Type and Status ENABLED | PENDING_ENABLE | PENDING_DISABLE — no DISABLED value) https://docs.aws.amazon.com/cli/latest/reference/organizations/list-roots.html
- AWS CLI: organizations list-policies (--filter SERVICE_CONTROL_POLICY; Policies[] carries AwsManaged, true for policies you can attach but cannot edit) https://docs.aws.amazon.com/cli/latest/reference/organizations/list-policies.html
- AWS CLI: organizations list-targets-for-policy (Targets[] with TargetId, Arn, Name and Type ACCOUNT | ORGANIZATIONAL_UNIT | ROOT) https://docs.aws.amazon.com/cli/latest/reference/organizations/list-targets-for-policy.html
- AWS CLI: organizations describe-organization (FeatureSet ALL | CONSOLIDATED_BILLING; AvailablePolicyTypes is deprecated — use ListRoots) https://docs.aws.amazon.com/cli/latest/reference/organizations/describe-organization.html
- IAM API: RoleDetail — PermissionsBoundary is an optional AttachedPermissionsBoundary (PermissionsBoundaryType, PermissionsBoundaryArn) returned by GetAccountAuthorizationDetails https://docs.aws.amazon.com/IAM/latest/APIReference/API_RoleDetail.html
- AWS GovCloud (US) User Guide: AWS Organizations — all features mandatory, ListRoots and root-referencing operations only in GovCloud (US-West), GovCloud organizations independent of commercial ones, and the permitted policy types https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-organizations.html
- AWS CLI: organizations describe-policy (Policy.PolicySummary with Id, Arn, Name, Description, Type, AwsManaged; Policy.Content is the policy document as a string) https://docs.aws.amazon.com/cli/latest/reference/organizations/describe-policy.html
- AWS CLI: iam get-account-authorization-details (--filter possible values User | Role | Group | LocalManagedPolicy | AWSManagedPolicy; the page describes the parameter as a comma-separated list while the CLI synopsis passes them space-separated, which is the form used here) https://docs.aws.amazon.com/cli/latest/reference/iam/get-account-authorization-details.html
This AWS mapping is authored opinion (overlay v3.0.0), versioned separately from the dataset and written against ruleset 2026.07.14.01. The upstream FedRAMP dataset names none of these tools.
The Change Management run (7)
- automatable
- partial — needs judgement
- narrative — no API proves this
Every authored recipe filed under CMT, in the order the plan works them. The mark says how much of the evidence the command produces on its own.
- partialPatch Manager compliance state plus Amazon Inspector scan status and coverage — proving flaws are being found continuously (Inspector enabled and actually covering your resources) and that the fixes landed (per-node missing/failed patch counts and the time of the last scan or install)dailypatch-and-vulnerability-remediationAWS Config · AWS Systems Manager Patch Manager · Amazon Inspector
- partialWho changed what, when, and from which state to which — CloudTrail's record of every mutating API call and Config's per-resource configuration history, plus, where Change Manager is in use, the change-request executions that carry the approvalweeklycloudtrail-config-change-historyAWS CloudTrail · AWS Config · AWS Systems Manager Change Manager
- partialConfig compliance results proving the ports you declared unnecessary are not reachable from the internet and the software you declared prohibited is not installed, plus the actual installed-application set a periodic review has to readmonthlyconfig-least-functionalityAWS Config · AWS Systems Manager Inventory · Amazon EC2
- partialEvery running instance built from an image you never approved and every node carrying denylisted software, together with proof that an automated action was configured for those findings and a record of what it did when one firedcontinuousunauthorized-component-detection-and-responseAWS Config · AWS Systems Manager Automation · AWS Systems Manager Inventory · Amazon EC2
- partialThe enforced half of who may change what: the service control policy type actually enabled in the organization root, the customer-authored SCPs and the roots, OUs and accounts each one is attached to, and the permissions boundary carried by every principal your own tagging marks as a change authorityyou are herecontinuouschange-authority-restrictions-and-enforcementAWS Organizations · AWS IAM
- partialFor every change that reached the assessed branch, the automated verification that ran against it — which workflows ran, on which commit, and what each concluded — together with the two things that decide whether those runs were a condition of the change or merely adjacent to it: the rule that made the checks required, and the platform's own per-push record of whether that rule held, failed, or was bypassed. The runs alone are activity; the rule and the per-push record are what make them a gate.weeklychange-verification-status-checks-and-run-recordsGitHub Actions · GitHub repository rulesets
- partialThe rule requiring the designated owners of the changed code to approve before it merges, the file that names who those owners are, the platform's own report of whether that file actually parses — and, per change, who approved, on which commit, and when.continuoussecurity-representative-change-approvalGitHub code owners · GitHub repository rulesets · GitHub pull requests