Defense in depth
Defense in depth means no single control is trusted to hold. The BuiltForProd AWS Baseline layers controls so that each catches what the previous one cannot: policies that even an administrator cannot bypass, detection across every account, automated response for clear-cut cases, and evidence stored where the account it describes cannot alter it.
Why it matters in production
Every control fails sometimes. A security group rule is loosened for a debugging session, a role is granted more than it needs, a bucket is made public by a script. One layer alone turns each of those into an incident. Layers turn them into a finding: the policy blocks the change, or the detector reports it, or the remediation reverses it, or the audit trail shows exactly what happened. Compliance frameworks ask for the same structure, which is why the offerings note lists SOC 2, HIPAA, PCI DSS 4.0, CMMC, NIST CSF and the CIS AWS Foundations Benchmark as out-of-the-box readiness.
How the platform applies it
Preventive: rules an administrator cannot lift
Three service control policies (SCPs) are attached to both organizational units. acme-security-guardrails denies creating IAM users and access keys, denies deleting or changing S3 Block Public Access except for platform automation and SSO roles, and denies any action without MFA outside the approved principals. acme-region-restriction denies activity outside the home region, the regions that have folders and us-east-1. acme-audit-protection denies stopping or deleting CloudTrail and AWS Config. SCPs hold against an account administrator, which is why they carry the non-negotiable rules. The organization tag policy pins tag keys and values; the account baseline turns on default EBS encryption and the account-wide S3 public-access block in every account.
Network: route tables per isolation domain and hub egress
Each isolation domain has its own Transit Gateway route table. The domain tables never learn each other's routes, and each one blackholes the address range of every stage outside it, so a packet aimed across the boundary is dropped at the Transit Gateway rather than reaching the other domain through the hub. Every spoke still reaches the hub and the runner VPC, as described under hub-and-spoke networking. Egress leaves only through the hub, where AWS Network Firewall inspection can be switched on. Firewall Manager applies a baseline AWS WAF policy (Common, Known Bad Inputs, SQL injection and IP Reputation rule groups) to every workload load balancer, with auto-remediation, so a new load balancer is covered without per-team configuration. Shield Standard applies; Shield Advanced is a switch.
Identity: short-lived and scoped
People and pipelines never hold long-lived keys, and access narrows toward production; see least privilege. Secrets are encrypted per stage with keys whose policy decides who can decrypt.
Workload: hardened by default
The application chart runs every stage as a non-root user (UID 10001) with a read-only root filesystem, all capabilities dropped and the RuntimeDefault seccomp profile; a default-deny NetworkPolicy allows only the stage VPC on port 8080, DNS, the data stores, the Pod Identity agent and HTTPS out, enforced by the VPC CNI's network policy agent. TLS is required wherever traffic crosses a boundary: CloudFront TLSv1.2_2021, HTTPS-only load balancers, DocumentDB and ElastiCache in-transit encryption, and bucket policies that deny non-TLS access to the state and audit buckets. Everything is encrypted at rest; customer-managed KMS keys with annual rotation protect the audit trail and the per-stage secrets.
Detective: one account sees everything
core-security is delegated administrator for GuardDuty, Security Hub, Inspector, Macie, IAM Access Analyzer and Firewall Manager. Which services run is decided in one file, environments/core/security/security.hcl, read by both the management account (which delegates) and the security account (which runs the service), so the two halves always agree. GuardDuty, Security Hub and the access analyzers are on; Inspector, Macie, the Security Hub standards and Shield Advanced are switches with their price beside them. AWS Config records every supported resource type in every account and evaluates a SOC 2 baseline conformance pack; 28 further packs are available.
Responsive: fix the obvious, alert on the rest
EventBridge rules in core-security route GuardDuty findings of severity 7 and above, EC2 and VPC findings and selected Config non-compliance to the acme-security-alerts SNS topic, whose email subscriber is set with security_alert_email. A Security Hub finding about a public S3 bucket triggers the SSM automation that disables public access, everywhere except core-public. CIS metric filters on the CloudTrail log group raise alarms into the same topic.
Evidentiary: history nobody can rewrite
One organization CloudTrail, multi-region, with log file validation, delivers every account's events to the audit bucket in core-audit, alongside Config history and every VPC's flow logs. The bucket is KMS-encrypted, versioned, TLS-only, retained indefinitely with tiering to cheaper storage, and lives in an account whose only job is to hold evidence. A compromised workload account cannot alter its own history.
Worked example: a public bucket
An engineer with PowerUser access in dev runs a script that removes a bucket's public-access block. The acme-security-guardrails policy denies the account-level change, but a bucket-level policy edit slips through. AWS Config evaluates the bucket as non-compliant; Security Hub raises a finding; the EventBridge rule invokes the SSM automation that re-blocks public access within minutes, and the alert reaches the security email. CloudTrail in core-audit records who made the change and when. Four layers were involved, and the bucket was public for minutes rather than months.
Common mistakes
- Weakening an SCP to make a deployment pass. Design around the policy: name workload roles
acme-*or tag themmfa-exempt = trueinstead. - Switching a security service off in one unit.
security.hclis read by both accounts; a change there is owned by the infra admins and the security team through code ownership, and turning a service off changes the whole organization. - Treating security groups as the only network control. Each isolation domain has its own Transit Gateway route table, cross-domain traffic is blackholed there whatever a security group allows, and egress leaves through the hub; a security group is the last layer, not the first.
- Sending logs to the account that produced them. Evidence lives in
core-auditso that the account it describes cannot rewrite it. - Making a bucket public outside
core-public. Remediation re-blocks it everywhere else.