Multi-Account & Compliance

AWS Organizations, SCPs, Control Tower, and compliance automation

Last generated

Lesson 22 of 31 available15 practice questions

SPACED REPETITION · 15 practice questions

Make this lesson stick.

Try 3 questions now. No account needed. Sample answers aren't saved.

Multi-Account & Compliance

A team requests a production account. Account creation succeeds, but its Config recorder is stopped and its incident contact is missing. Is the account ready? Another account has a green compliance dashboard, but its newest Region sends no data. Is it compliant? These are different failures: provisioning, coverage and control evaluation need separate evidence.

This lesson develops four applications: a tested organizational restriction, an account-vending workflow, a verified compliance baseline and a finding-to-evidence process. It assumes familiarity with IAM, CloudTrail and Config. Examples are components for a prepared learning environment; they do not create a complete landing zone or certify compliance.

1. Design account boundaries around responsibility

An AWS account is a useful boundary for ownership, billing, permissions and many service quotas. It does not automatically isolate every network or data path. Cross-account roles, resource policies and shared infrastructure can reconnect those boundaries. A compromise does not inherently grant access to everything in one account, either: effective permissions still matter. Use separate production and development accounts where their owners, change controls or recovery needs differ. Balance that benefit against the work of operating each account. Multi-account guidance.

The organization root is a container, not the management account and not an IAM root user. OUs group accounts and other OUs; the management account is one account in the organization. Group OUs by common policy requirements and lifecycle, rather than mechanically copying an organizational chart.

Organization root
|-- Management account
|-- Security OU
|   |-- Log Archive account
|   `-- Audit account
|-- Infrastructure OU
|   `-- Shared Services account (if needed)
|-- Workloads OU
|   |-- Production OU --> production workload accounts
|   `-- Nonproduction OU --> development/test accounts
`-- Sandbox OU --> bounded experiments

This is an illustrative hierarchy, not a mandatory number of OUs or accounts. Protect the management account with strong identity controls and use it for organization-level administration and billing; keep workloads elsewhere. Delegate supported security administration to a member account. A delegated administrator gains the permissions of the particular integrated service, not unrestricted control of Organizations. Organizations terminology, management account practices.

Consolidated billing combines eligible usage and provides one organization bill, but account ownership does not replace cost-allocation design. Record the accountable owner, environment, cost center, data classification and recovery contact. Organization account tags are not automatically inherited by resources, and a tag alone does not attach an SCP. Automation must deliberately consume that metadata.

2. Application: introduce an SCP without inventing a permission grant

SCPs constrain permissions available to principals in affected member accounts, including their root users. They do not grant access. They do not constrain management-account principals or service-linked roles. An external principal receiving access through a member account's resource policy is not automatically governed by that member's SCP. Resource control policies address supported resource-side permission limits; they have their own scope and exceptions. SCP scope, RCPs.

For an action to survive SCP evaluation, an applicable allow must exist at each level in its organization path, and no applicable explicit deny may block it. Allows within a level combine; limits across levels intersect. In a deny-list approach, retain the necessary FullAWSAccess policies along that path. Passing SCP evaluation does not grant an IAM user or role permission; the relevant authorization path must also allow the action. Account root has inherent account permissions, while member-account root remains subject to applicable SCPs. Other policy limits still need evaluation. Root permissions. There is no useful universal rule that “an IAM allow beats implicit deny everywhere.” SCP evaluation.

Suppose a sandbox may launch EC2 instances only through the us-east-1 and eu-west-1 endpoints. This deliberately narrow SCP limits RunInstances; it does not claim to restrict all services or prove data residency:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "RestrictSandboxEC2LaunchRegions",
    "Effect": "Deny",
    "Action": "ec2:RunInstances",
    "Resource": "*",
    "Condition": {
      "StringNotEquals": {
        "aws:RequestedRegion": ["us-east-1", "eu-west-1"]
      }
    }
  }]
}

aws:RequestedRegion identifies the endpoint invoked, not every location an operation may affect. An all-service region restriction needs careful treatment of global endpoints and service behavior. Adding an unrelated condition can defeat a deny: conditions on different keys/operators generally combine with AND. A supposed exemption matching everyone can make the restriction ineffective. RequestedRegion behavior.

Before attachment, record the current policy attachments and the authorized recovery operator. Enable the SCP policy type in the all-features organization if it is not already enabled. Attach the reviewed policy first to an isolated test OU, not the organization root. Test these outcomes with a member-account role:

  1. A permitted launch in an allowed Region can pass this SCP, provided IAM, quotas and other prerequisites allow it.
  2. The same otherwise-authorized launch outside the list is denied.
  3. Removing the IAM launch permission still denies access in an allowed Region.
  4. A different action, such as describing instances, is not restricted by this statement.

Use a harmless preflight where possible, then a controlled disposable-resource test for the real workflow. A failure can have several causes; examine its evidence before attributing it to the SCP. Test essential recovery operations too. Broaden deployment only after owners understand the affected actions.

A second policy could deny cloudtrail:StopLogging and cloudtrail:DeleteTrail, but those two actions do not protect every audit path. Changing selectors, modifying delivery access or breaking collection in other ways can still affect evidence. Likewise, denying organizations:LeaveOrganization to members does not stop an authorized management-account administrator from performing organization administration. Test the actual threat and recovery paths rather than naming a short deny policy “tamper-proof.”

3. Application: vend an account and verify readiness

Control Tower adds a managed landing zone, controls and account provisioning to Organizations. Its standard shared-account structure includes the management, Log Archive and Audit accounts; Log Archive and Audit sit in the Security OU. A Shared Services account is an additional architecture choice. The audit account is not simply a universally read-only account: review the actual roles and permissions. Existing organizations/accounts can be brought under governance after prerequisite checks and enrollment; complexity is a reason to plan that migration, not a categorical exclusion. Shared accounts, existing organizations.

Keep two control classifications separate:

  • Behavior: preventive controls use SCPs/RCPs to block supported actions; detective controls use Config rules to identify noncompliance; proactive controls use CloudFormation hooks to check supported resources before provisioning. A proactive CloudFormation check is not a universal interceptor for direct API calls.
  • Guidance: mandatory controls apply automatically and cannot be changed; strongly recommended and elective controls are selectable. “Mandatory” and “preventive” describe different properties.

Inspect each control's actual scope and supported Regions. Do not assume every public bucket is universally prevented by a mandatory default. Control behavior and guidance.

For the Service Catalog version of Account Factory, first select the correct home Region, portfolio access, product, active provisioning artifact and launch path. Inspect describe_provisioning_parameters for that product/version/path. Supply its real required parameters, including unique account email, account name, the expected managed-OU value and applicable IAM Identity Center user fields. Do not guess product IDs or assume an OU display name has the required format. Networking and identity choices depend on landing-zone settings. Account Factory for Terraform is another supported workflow, not a requirement for this API example. Account Factory provisioning.

The following functions submit an already-reviewed parameter set and poll a recorded operation. Pass an authenticated servicecatalog client, a persisted request token and a unique provisioned-product name. The caller must save the returned record ID before waiting:

import time

def request_account(sc, product_id, artifact_id, path_id,
                    product_name, parameters, request_token):
    response = sc.provision_product(
        ProductId=product_id,
        ProvisioningArtifactId=artifact_id,
        PathId=path_id,
        ProvisionedProductName=product_name,
        ProvisioningParameters=[
            {"Key": key, "Value": value}
            for key, value in parameters.items()
        ],
        ProvisionToken=request_token
    )
    return response["RecordDetail"]["RecordId"]

def wait_for_account(sc, record_id, timeout_seconds=3600):
    deadline = time.monotonic() + timeout_seconds
    while time.monotonic() < deadline:
        page = sc.describe_record(Id=record_id)
        detail = page["RecordDetail"]
        status = detail["Status"]
        if status == "SUCCEEDED":
            outputs = list(page.get("RecordOutputs", []))
            token = page.get("NextPageToken")
            while token:
                page = sc.describe_record(Id=record_id, PageToken=token)
                outputs.extend(page.get("RecordOutputs", []))
                token = page.get("NextPageToken")
            return {
                "provisioned_product_id": detail["ProvisionedProductId"],
                "outputs": {x["OutputKey"]: x["OutputValue"] for x in outputs}
            }
        if status == "FAILED":
            raise RuntimeError(f"Provisioning failed; inspect record {record_id}")
        if status not in {"CREATED", "IN_PROGRESS", "IN_PROGRESS_IN_ERROR"}:
            raise RuntimeError(f"Unexpected record status: {status}")
        time.sleep(10)
    raise TimeoutError(f"Still unresolved; inspect record {record_id} before retrying")

The token gives idempotency for the provisioning request; retain it with the same request inputs when recovering an uncertain response. It is not a general deduplication scheme for requests with new tokens. A timeout stops this waiter, not the AWS operation. Resume inspection of the existing record rather than requesting another account blindly. Output order is not a contract: use documented output keys for the selected product and verify the resulting account ID. ProvisionProduct, DescribeRecord.

Readiness exercise: after provisioning succeeds, check OU membership and enrollment, owner/contact metadata, federated operator access, applied controls, expected network configuration, log delivery and Config recording. A successful Service Catalog record does not prove those independent operational observations. Account vending ends with a usable baseline and an accountable owner, not merely an account number.

4. Application: deploy a scoped baseline and prove coverage

Config records supported resource configurations and evaluates rules. Recording scope, frequency, rule triggers and service support determine freshness. Managed rules are supplied by AWS; custom rules can use Lambda or Guard. A successful API read is not itself a compliance policy, and an access-denied exception is not proof of resource noncompliance. Current S3 defaults also make an old “new buckets have no encryption” example misleading. Config rules, recording scope.

This complete CloudFormation rule component assumes a running recorder for S3 buckets and EC2 instances and its working delivery setup. Also record AWS::Config::ResourceCompliance for the compliance history and aggregated compliance reporting used here. Verify that the resulting compliance configuration items are recorded before relying on those views. Compliance reporting prerequisites. It does not create or replace the recorder. The required-tags rule checks presence of two tags, not whether their values name real owners:

AWSTemplateFormatVersion: '2010-09-09'
Description: Rule component for accounts with an existing Config baseline
Resources:
  OwnershipTags:
    Type: AWS::Config::ConfigRule
    Properties:
      Scope:
        ComplianceResourceTypes: ['AWS::S3::Bucket', 'AWS::EC2::Instance']
      Source: {Owner: AWS, SourceIdentifier: REQUIRED_TAGS}
      InputParameters:
        tag1Key: Owner
        tag2Key: CostCenter
  BucketPublicRead:
    Type: AWS::Config::ConfigRule
    Properties:
      Scope:
        ComplianceResourceTypes: ['AWS::S3::Bucket']
      Source: {Owner: AWS, SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED}
Outputs:
  OwnershipRuleName: {Value: !Ref OwnershipTags}
  PublicReadRuleName: {Value: !Ref BucketPublicRead}

Deploy first in one nonproduction account/Region. Use a disposable resource with missing tags, observe the rule result, add valid ownership tags, and verify a later evaluation. Test the public-read rule using a reviewed fixture; its compliance assessment is not identical to checking that all four Block Public Access switches are enabled. Required tags rule, S3 public-read rule.

A StackSet can distribute this component to selected accounts/Regions. A template alone is not a StackSet deployment: choose its permission model, targets, execution Regions, concurrency, failure tolerance and future-account behavior. Inspect stack-instance results, not only operation acceptance. Avoid duplicating or overwriting Control Tower-managed resources. Account-wide baseline deployment does not erase per-resource evaluation charges. StackSets concepts.

For a separate organization-wide read-only view, use an organization aggregator. In this example the caller is the organization management account, all features are enabled, and the supplied aggregation role has the documented Config trust and organization-read permissions. Source accounts/Regions already record the desired resources:

def configure_aggregator(config, name, role_arn):
    return config.put_configuration_aggregator(
        ConfigurationAggregatorName=name,
        OrganizationAggregationSource={
            "RoleArn": role_arn,
            "AllAwsRegions": True
        }
    )

def aggregation_sources(config, name):
    token = None
    while True:
        args = {"ConfigurationAggregatorName": name}
        if token:
            args["NextToken"] = token
        page = config.describe_configuration_aggregator_sources_status(**args)
        yield from page.get("AggregatedSourceStatusList", [])
        token = page.get("NextToken")
        if not token:
            break

A registered delegated administrator is an alternative with its own setup requirements. The organization source is an alternative to individually authorized account sources. Aggregation replicates available recorded data; it neither enables all recorders nor grants the ability to remediate through the aggregator. Compare source status and update times with an expected account/Region inventory. A missing source is a coverage failure to investigate, not a compliant account. Aggregator setup API, aggregation semantics.

Do not apply a universal “record every global resource only in us-east-1” rule. Legacy global IAM resource recording, newer global resource home Regions and resource-specific exceptions have different behavior. Plan the supported recording scope per type and Region, then check delivery errors. Configuration items, rule evaluations and conformance-pack evaluations have distinct pricing; an aggregator adds a view rather than removing source costs. Global recording behavior, Config pricing.

5. Application: turn a finding into a controlled action and evidence

Security Hub CSPM provides posture controls and supported standards/findings integrations; Security Hub combines findings and exposure information for prioritization. Distinguish organization administration, regional enablement, cross-Region aggregation and centrally applied configuration policies. Creating an administrator or dashboard does not by itself activate every desired check in every account. Do not assume arbitrary Config rules automatically become Security Hub CSPM findings. Security Hub services, central configuration.

For a standalone, locally managed CSPM account/Region, discover available standards with the paginated describe_standards operation, select the reviewed standard/version ARN, enable the service with enable_security_hub, and subscribe using batch_enable_standards. Then inspect subscription readiness and control evaluation prerequisites. Do not invent create_hub() or assume an old CIS ARN/version is current. Centrally managed members should receive their intended configuration through the central policy workflow. Standards discovery, standards subscription.

For an ASFF Security Hub Findings - Imported EventBridge event, the following pure intake function extracts active high/critical findings for triage. It handles the documented findings array, although the current imported-event format sends one finding per event. This is not a remediation Lambda or the format of every Security Hub event:

def triage_items(event):
    if (event.get("source") != "aws.securityhub" or
            event.get("detail-type") != "Security Hub Findings - Imported"):
        raise ValueError("Unexpected event contract")
    for finding in event["detail"]["findings"]:
        if finding.get("RecordState") != "ACTIVE":
            continue
        if finding.get("Workflow", {}).get("Status") in {"RESOLVED", "SUPPRESSED"}:
            continue
        if finding.get("Severity", {}).get("Label") not in {"HIGH", "CRITICAL"}:
            continue
        yield {
            "event_id": event["id"],
            "severity": finding["Severity"]["Label"],
            "workflow_status": finding.get("Workflow", {}).get("Status"),
            "finding_key": (finding["ProductArn"], finding["Id"]),
            "updated_at": finding["UpdatedAt"],
            "account_id": finding["AwsAccountId"],
            "region": finding.get("Region", event["region"]),
            "resource_ids": [r["Id"] for r in finding.get("Resources", [])]
        }

Connect a narrowly filtered rule to a durable queue/processor with access controls, delivery-failure handling and an incident store. Preserve the original event/finding and distinguish duplicate delivery from finding-state reconciliation. UpdatedAt tracks provider updates; customer BatchUpdateFindings changes to severity or workflow can emit a new Imported event without changing it. Do not discard an escalation solely because identity and UpdatedAt match an earlier event. An event ID helps identify repeat delivery of that event, while the finding key identifies the incident being reconciled. Read current finding/resource state before acting, accounting for update propagation and older deliveries. This preliminary filter must not reopen a resolved incident from stale event data. Customer update behavior. Persist workflow state and use idempotent downstream operations. This function itself provides neither durable deduplication nor exactly-once delivery. Keep webhook credentials in protected configuration and check delivery responses instead of reporting success unconditionally. CSPM event format, finding identification.

The operator should establish resource ownership, account/Region, current state and an approved repair before assuming a narrowly scoped role. For an S3 public-access finding, do not delete the whole bucket policy: that can remove required service grants and protective denies. Review any Block Public Access change against public and private cross-account consumers, and preserve a rollback plan. RestrictPublicBuckets can block explicit external-account grants when a policy is public. Use the controlled, opted-in repair pattern from the security overview, then verify both fresh settings and later evaluation. Block Public Access effects.

An incident record should connect the original finding, approved decision, execution identity, before/after state, failed attempts and verification. A notification is not the repair, and a returned HTTP 200 is not proof the application still works. Test duplicate delivery, an already-fixed resource, denied role assumption and a failed post-change check.

6. Build evidence around an actual requirement

AWS Artifact supplies AWS compliance reports and agreements; these describe AWS's controls and relevant responsibilities, not a certificate for your workload. Map your own requirement to technical and organizational controls, evidence scope, frequency and an accountable reviewer. A managed rule can support that mapping without establishing complete HIPAA, PCI DSS, SOC 2 or GDPR compliance. Use the applicable current framework/version and your assessor's actual requirements rather than an invented YAML “framework” or an obsolete PCI version. Artifact, shared responsibility.

Availability checked 15 September 2026: Audit Manager is in maintenance mode. Since April 30, 2026, it cannot be newly set up in additional accounts/Regions. Existing setups retain documented usage; an existing organization management-account setup may add organization accounts to assessments within its supported scope. Do not plan a new deployment around enabling it. For an eligible existing setup, automated evidence still needs review and complementary manual evidence. For new environments, design an evidence process using current supported collection/reporting tools and owned review workflows. Audit Manager availability.

For example, define a requirement as “review administrative access changes to production weekly.” Collect the selected CloudTrail management events, record collection gaps, run the review, preserve reviewer decisions and follow up exceptions. A trail's existence alone does not prove a weekly review occurred. Log-file validation supports later integrity checks; retention and access controls are separate. An organization trail's event selectors determine collection, and a multi-Region trail does not mean every possible data event is included. Organization trails.

Finally, rehearse account retirement: inventory owners/resources, preserve required evidence and backups, remove access and external integrations, resolve financial obligations and use the documented closure process. Moving an account to a “Suspended” OU does not close it or stop all charges. The governance system is effective when it can explain how an account enters service, stays observable, handles exceptions and leaves service with evidence intact.