AWS Lesson 76 of 123

AWS Well-Architected: Security — Foundations, IAM, Detection, Infrastructure & Data Protection, Incident Response, and AppSec

In a nutshell

Imagine you run security for a bank with many branches. You do not just lock the front door and hope. You give every employee a photographed ID badge instead of a shared key (identity); you keep camera footage of who entered which room and when (traceability); you put separate locks on the lobby, the vault room, and the vault itself so one breach does not open everything (layers); you keep cash in a time-locked safe and shred sensitive paper (protect data); you let tellers serve money without ever holding the vault combination (keep people away from data); and you run fire drills so nobody improvises during a real emergency (prepare for events). The AWS Well-Architected Security pillar is exactly that playbook, translated to the cloud.

This lesson is the second pillar of the AWS Well-Architected Framework (WAF) — a set of design principles and hard questions AWS uses to review a workload. A quick but important warning about names: in AWS, “WAF” is overloaded. Here it means the Well-Architected Framework. Separately, AWS WAF (Web Application Firewall) is a product you can buy — and it shows up later as one tool inside the Infrastructure and Application areas of this pillar. This lesson is about the framework/pillar, not the firewall product. Keep the two straight and the rest is easy.

The pillar answers one question: how do you protect information, systems, and assets while delivering business value? It does that through seven design principles and seven best-practice areas — foundations, identity, detection, infrastructure protection, data protection, incident response, and application security — each expressed as numbered questions (SEC 1 through SEC 11) that you can literally score yourself against in the AWS Well-Architected Tool.

Level: Advanced · Time: ~59 min

Prerequisites. You should be comfortable with the core AWS building blocks — accounts, IAM users, roles, and policies, VPCs, and S3 — and it helps to have read the first pillar, Operational Excellence, since detection and incident response lean on good operations. You do not need to have built a multi-account landing zone yet; this lesson explains why you will want one.

After this lesson you will be able to:

Where this fits

The Security pillar is the second of the six pillars in the AWS Well-Architected Framework (after Operational Excellence, and before Reliability, Performance Efficiency, Cost Optimization, and Sustainability). Its design principles are familiar but worth restating because every decision below ladders up to them: implement a strong identity foundation, maintain traceability, apply security at all layers, automate security best practices, protect data in transit and at rest, keep people away from data, and prepare for security events. The pillar decomposes into seven areas — security foundations, identity and access management, detection, infrastructure protection, data protection, incident response, and application security — and the Framework expresses its expectations as numbered best-practice questions (SEC 1 through SEC 11). This article walks each area as you would actually implement it in a multi-account AWS organization, naming the concrete services, artifacts, and trade-offs.

AWS Well-Architected Framework — animated overview

Security foundations (SEC 1)

What it is. Foundations is the operating model that everything else sits on: how you separate workloads across AWS accounts, how you centrally govern those accounts, how you stay aware of threats and compliance obligations, and how you keep your security guardrails as code rather than as tribal knowledge. It maps to SEC 1 (“How do you securely operate your workload?”).

Why it matters. A single AWS account is a single blast radius. The moment you have production data, a CI/CD pipeline, and a sandbox in the same account, a leaked credential or a misconfigured IAM policy threatens all three. Account separation is the cheapest, strongest isolation boundary AWS gives you, and the foundations area is where you decide how to use it.

How to do it well. Use AWS Organizations to create an organizational unit (OU) structure, then govern it. The reference pattern is AWS Control Tower (or, increasingly, a hand-rolled landing zone) which stands up a multi-account environment with a management account, a dedicated Log Archive account, and a Security Tooling / Audit account in a Security OU. Apply service control policies (SCPs) at the OU level as preventive guardrails — these set the maximum permissions available in member accounts and cannot be overridden by an account-local administrator. Classic SCPs deny disabling CloudTrail, GuardDuty, or Config; deny leaving the organization; restrict to approved Regions; and deny use of the account root user for anything but the handful of tasks that require it. Newer resource control policies (RCPs) complement SCPs by setting an upper bound on resource-based policies (e.g., enforcing aws:PrincipalOrgID so an S3 bucket can never be shared outside the org). Declarative policies let you enforce a desired configuration for a service (such as blocking public AMIs) that persists even as the service adds features. Maintain everything as code — Terraform, CloudFormation, or AWS CDK — and stamp new accounts through Account Factory for Terraform (AFT) or Control Tower Account Factory so the baseline is identical every time.

Foundational control AWS service Scope What it prevents/provides
Account/OU structure AWS Organizations, Control Tower Org-wide Blast-radius isolation, central billing
Preventive guardrails SCPs, RCPs, declarative policies OU / account Bound max permissions, enforce Region/config
Config baseline as code AFT, CloudFormation StackSets Per account Repeatable, drift-free account provisioning
Central identity broker IAM Identity Center Org-wide Single sign-on, no long-lived IAM users
Threat & advisory intel AWS Security Hub, Trusted Advisor, AWS Health Org-wide Staying aware of vulnerabilities and posture

Artifacts and decisions. A landing-zone design document; the OU hierarchy diagram; the SCP/RCP policy set in version control; an account vending process; a Region-restriction decision; and a documented account baseline (centralized logging, mandatory CloudTrail, default encryption, tagging policy). The key decision is granularity: too few accounts and you lose isolation; too many and IAM Identity Center permission-set sprawl becomes its own problem. A common landing on this is one account per workload per environment (prod/stage/dev), grouped into Workload, Sandbox, Infrastructure, and Security OUs.

Worked example — a guardrail SCP, read line by line. Foundations stays abstract until you see the code. Here is a trimmed service control policy attached to an OU. An SCP does not grant anything; it sets the ceiling on what any principal — even an account administrator — in that OU can do. This one denies three destructive actions and pins the OU to two Regions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyDisablingGuardrails",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:StopLogging",
        "cloudtrail:DeleteTrail",
        "guardduty:DeleteDetector",
        "config:DeleteConfigurationRecorder",
        "config:StopConfigurationRecorder"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenyLeavingOrg",
      "Effect": "Deny",
      "Action": "organizations:LeaveOrganization",
      "Resource": "*"
    },
    {
      "Sid": "RegionLockExceptGlobal",
      "Effect": "Deny",
      "NotAction": [
        "iam:*", "sts:*", "organizations:*", "cloudfront:*",
        "route53:*", "support:*", "waf:*", "shield:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": ["ap-south-1", "eu-west-1"]
        }
      }
    }
  ]
}

Read it as three guardrails. DenyDisablingGuardrails means even a compromised administrator cannot switch off your audit trail or threat detection — the logs keep flowing, which is the whole point of traceability. DenyLeavingOrg stops an account being pulled out from under your central policies. RegionLockExceptGlobal uses NotAction plus the aws:RequestedRegion condition to deny every API in every Region except the two you approved — with a carve-out for genuinely global services (IAM, STS, CloudFront, Route 53) that only “live” in us-east-1. Forget that carve-out and you lock yourself out of IAM; that single mistake is the most common self-inflicted SCP outage.

Foundations also introduces resource control policies (RCPs), the mirror image of SCPs: where an SCP bounds what your principals can do, an RCP bounds what your resources will accept. The classic RCP enforces the aws:PrincipalOrgID condition so an S3 bucket or KMS key can never be read by a principal outside your organization — closing the “accidentally public bucket” and “confused-deputy” doors at the resource edge. Keep both as code (the Organizations SCP guardrails lesson goes deep on this) so a review can diff them like any other change.

Identity and access management (SEC 2, SEC 3)

What it is. IAM is how you manage human identities (workforce, partners) and machine identities (workloads, services), and how you grant each the least privilege needed. SEC 2 covers managing identities; SEC 3 covers managing permissions for those identities.

Why it matters. Most cloud breaches are identity breaches — a stolen access key, an over-permissive role, a forgotten admin user with no MFA. Getting identity right closes the most-exploited door.

How to do it well — humans. Stop creating IAM users. Federate workforce identity through IAM Identity Center (formerly AWS SSO), connected to your IdP (Microsoft Entra ID, Okta, or the built-in store) and ideally provisioned via SCIM. Users assume permission sets (which become IAM roles in the target accounts) and receive short-lived credentials — no long-term keys to leak. Enforce MFA universally; for the highest assurance, require phishing-resistant FIDO2/WebAuthn. The root user of every account is locked down: a hardware MFA, no access keys, and — for member accounts in an organization — centralized root access management so you don’t even store member-account root credentials.

How to do it well — machines. Never embed access keys in code or AMIs. EC2 workloads use IAM roles via instance profiles; EKS pods use IAM Roles for Service Accounts (IRSA) or the newer EKS Pod Identity; Lambda uses an execution role. For workloads outside AWS or in CI/CD, use IAM Roles Anywhere (X.509-based) or OIDC federation (e.g., GitHub Actions assuming a role with no stored secret). For application secrets and credentials that must exist, use AWS Secrets Manager with automatic rotation, not environment variables.

How to do it well — permissions. Practice least privilege as a lifecycle, not a one-time grant. Start from AWS managed policies, then tighten. Use IAM Access Analyzer to: find resources shared externally, generate fine-grained policies from CloudTrail access history, and validate policies against best practices in CI. Constrain with permissions boundaries (a ceiling on what a delegated admin can grant), session policies, and attribute-based access control (ABAC) using tags so policies scale without per-resource rewrites. Review continuously with last-accessed data to strip unused permissions.

Concern Anti-pattern Well-Architected pattern
Workforce login Shared IAM users + passwords IAM Identity Center + IdP federation + SCIM
MFA Optional, SMS-based Mandatory, FIDO2/WebAuthn phishing-resistant
EC2 credentials Access keys in user-data Instance profile (IAM role)
CI/CD to AWS Stored long-lived access key OIDC/Roles Anywhere, short-lived STS creds
Permission scoping *:* “to unblock the team” Access Analyzer-generated least-privilege policy
Delegated admin Full IAM access Permissions boundary caps the grantable set

Artifacts and decisions. An identity architecture diagram (IdP -> Identity Center -> permission sets -> accounts); the permission-set catalog mapped to job functions; a secrets-rotation policy; an Access Analyzer finding-triage runbook; and a documented break-glass procedure for the rare case where federation is down.

Worked example — machine identity without a single stored key. The IAM area says “give machines roles, not keys.” Here is what that actually looks like for a CI/CD pipeline. Instead of pasting an AKIAIOSFODNN7EXAMPLE-style access key into GitHub secrets (a key that never expires and leaks in logs), you let GitHub Actions federate into a role using OIDC. The role’s trust policy — who is allowed to assume it — is the security control:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
      },
      "StringLike": {
        "token.actions.githubusercontent.com:sub": "repo:finpeak/payments-api:ref:refs/heads/main"
      }
    }
  }]
}

The sub condition is the load-bearing line: only a workflow running on the main branch of the finpeak/payments-api repository can assume this role. A pull request from a fork, or any other repository, is rejected by STS before a single API call runs. There is no long-lived secret to steal, and the credentials handed back last minutes, not forever. Get the sub filter wrong — leave it as repo:finpeak/* — and any repository in your org can deploy to production; this is the single most important line to review.

The permission side uses permissions boundaries to delegate safely. A boundary is a managed policy that sets the maximum a principal can ever be granted, even by another admin. A platform team can let product teams create their own roles as long as every role carries the boundary — the team can grant s3:* on their own buckets but can never grant themselves iam:* or step outside the guardrail. Pair that with IAM Access Analyzer generating least-privilege policies from real CloudTrail history, and least privilege stops being a manual guessing game and becomes a review of a machine-proposed policy.

Detection (SEC 4)

What it is. Detection is your ability to identify a misconfiguration, an unexpected change, or an active threat — and to investigate it. It maps to SEC 4 (“How do you detect and investigate security events?”).

Why it matters. Prevention will eventually fail or be bypassed; detection is what bounds the dwell time of an attacker and proves to auditors that you’d notice. The Framework’s traceability principle lives here.

How to do it well. Build on three layers — logging, analysis, and alerting — and centralize all three in your Security/Log Archive accounts.

Capability Primary service What it answers
Who did what, when CloudTrail (org trail) API/management audit trail
Did config drift / violate policy AWS Config + conformance packs Continuous compliance & change detection
Is there active threat activity Amazon GuardDuty Anomalous/malicious behavior
One pane of glass + scoring AWS Security Hub Aggregated, normalized posture
Root-cause investigation Amazon Detective Entity behavior over time
Centralized log data lake Amazon Security Lake Long-term, queryable, OCSF logs

Artifacts and decisions. A logging architecture (sources -> central bucket/lake -> retention/lifecycle); the Config conformance packs you enforce; a GuardDuty/Security Hub delegated-administrator setup (run them org-wide from the Audit account); finding-severity-to-response mappings; and decisions on log retention (regulatory) versus cost (data events and Flow Logs can dominate the bill — sample or scope them).

Worked example — turning a finding into a page. Detection is only useful if a human or a robot acts on it, and the glue is Amazon EventBridge. Every GuardDuty finding is emitted as an event; this rule pattern matches only high-severity findings (GuardDuty scores severity on a 0–10 scale; 7.0 and up is “High”) and forwards them to an SNS topic that fans out to PagerDuty and Slack:

{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "severity": [{ "numeric": [">=", 7.0] }]
  }
}

That numeric filter is why you are not paged for every low-severity port scan — noise is the enemy of a detection program, because an on-call that cries wolf gets muted. In the console this is a two-minute setup; as code it is an aws_cloudwatch_event_rule plus a target. The same pattern — match a finding shape, route it somewhere — is how you wire auto-remediation later: a finding for a public S3 bucket can instead target a Systems Manager Automation document that flips the bucket private, with no human in the loop.

A second detection reflex worth building early is AWS Config as your “what changed?” engine. Config records every resource configuration over time, so after an incident you can answer “when did this security group open port 22 to 0.0.0.0/0, and who did it?” — pairing the state change from Config with the API call from CloudTrail gives you the full story. Bundle Config rules into conformance packs (ready-made CIS or PCI DSS sets) so posture is measured continuously, not in a once-a-year audit scramble.

Infrastructure protection (SEC 5, SEC 6)

What it is. Defending your networks (SEC 5) and your compute resources (SEC 6) through defense in depth. This is “security at all layers” applied to the plumbing.

Why it matters. A flat network or an unpatched host turns a single foothold into lateral movement across the estate. Layered controls ensure no single failure is catastrophic.

How to do it well — network. Design VPCs with private subnets for workloads and no direct internet path; use NAT gateways for egress and VPC endpoints (interface/Gateway) so traffic to AWS services never traverses the internet. Segment with security groups (stateful, instance-level, default-deny) and network ACLs (stateless, subnet-level) as a second layer. Centralize egress and inspection through AWS Network Firewall (stateful IDS/IPS, domain filtering) and Route 53 Resolver DNS Firewall in an inspection VPC fronting a Transit Gateway. At the edge, AWS WAF protects HTTP(S) endpoints (ALB, CloudFront, API Gateway, AppSync) with managed and custom rules, and AWS Shield Advanced provides DDoS protection with cost protection and a response team. Govern WAF/Firewall rules org-wide with AWS Firewall Manager.

How to do it well — compute. Reduce the attack surface and patch continuously. Harden AMIs with EC2 Image Builder producing golden, scanned images on a schedule. Manage patching with AWS Systems Manager Patch Manager and operate hosts agentlessly via SSM Session Manager (no SSH bastions, no inbound 22). Scan continuously with Amazon Inspector for CVEs and network reachability across EC2, ECR container images, and Lambda. Enforce IMDSv2 to defeat SSRF-based credential theft. Prefer immutable infrastructure: rebuild and redeploy rather than patch in place. For serverless and containers, the principle is the same — minimal base images, scanned in the pipeline, with the smallest possible execution role.

Layer Control AWS service
Edge / L7 WAF rules, DDoS mitigation AWS WAF, AWS Shield Advanced
Network perimeter IDS/IPS, domain/egress filtering AWS Network Firewall, DNS Firewall
Segmentation Stateful + stateless rules Security groups, network ACLs
Private connectivity Keep traffic off the internet VPC endpoints, PrivateLink
Host access Agentless shell, no inbound SSH SSM Session Manager
Patch & image hygiene Golden images, patch baselines EC2 Image Builder, Patch Manager
Vulnerability scanning CVE + reachability Amazon Inspector
Org-wide rule enforcement Central WAF/SG policy AWS Firewall Manager

Artifacts and decisions. Network topology and segmentation diagrams; the centralized-inspection design; AMI hardening pipeline definitions; a patch SLA per environment; and the WAF rule baseline. Key decision: centralized inspection VPC (clean, governable, adds latency/cost) versus distributed firewalls.

Worked example — closing the SSRF credential door. Infrastructure protection is where a small default flips a whole class of attack on or off. The instance metadata service (IMDS) hands an EC2 instance its role credentials at http://169.254.169.254/. Under the old IMDSv1, any code that could make an outbound HTTP request from the box — including a server-side request forgery (SSRF) bug in your web app — could ask for those credentials and walk away with your role. IMDSv2 requires a PUT to fetch a session token first, which an SSRF cannot perform. Enforce it; do not just enable it:

# Require IMDSv2 (token) and stop an extra network hop reaching IMDS
aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc123def4567890 \
  --http-tokens required \
  --http-put-response-hop-limit 1 \
  --http-endpoint enabled

--http-tokens required is the line that kills IMDSv1; the hop limit of 1 stops a container on the host from reaching metadata through an extra hop. Bake this into your launch template and enforce it fleet-wide with an SCP-backed Config rule so a new instance cannot be born insecure.

The other everyday control is the security group — a stateful, default-deny allow-list. The mistake beginners make is 0.0.0.0/0 on port 22 “just to SSH in.” The Well-Architected answer is to have no inbound SSH at all: reach hosts through SSM Session Manager, which tunnels over the AWS API with full IAM control and CloudTrail logging, so there is no open port to scan. A security group should reference other security groups (“allow the app tier from the load-balancer SG”) rather than raw CIDRs, so the rules describe intent and survive IP changes.

Data protection (SEC 7, SEC 8, SEC 9)

What it is. Classifying data (SEC 7), protecting it at rest (SEC 8) and in transit (SEC 9), and keeping people away from it. The unifying goal of the pillar — reduce the chance that the wrong eyes ever see sensitive data.

Why it matters. Data is the asset you actually protect. Encryption and classification limit the impact of every other control failing.

How to do it well — classify. You cannot protect uniformly what you don’t understand. Define data classification tiers (e.g., Public / Internal / Confidential / Restricted) and tag resources accordingly. Use Amazon Macie to discover and classify sensitive data (PII, credentials, financial data) in S3 automatically, feeding findings into Security Hub.

How to do it well — at rest. Encrypt everything, and make it the default. AWS KMS is the backbone: use customer-managed keys (CMKs) for sensitive data so you control the key policy, rotation, and grants; the key policy plus IAM is how you enforce separation of duties (the team that uses data isn’t the team that can delete its key). Enable default encryption on S3, EBS, RDS/Aurora, DynamoDB, and snapshots; enforce it preventively with SCPs and Config rules (deny unencrypted creation). For regulatory custody requirements, AWS CloudHSM gives you single-tenant FIPS 140-2/3 Level 3 HSMs. Protect against accidental or malicious deletion with S3 Object Lock, versioning, MFA Delete, and AWS Backup with vault lock (WORM). Reduce direct human access to data entirely with tokenization and query-only access patterns.

How to do it well — in transit. Enforce TLS everywhere. Issue and rotate certificates with AWS Certificate Manager (ACM); for internal PKI, use AWS Private CA. Terminate TLS at ALB/CloudFront/API Gateway with modern policies; enforce HTTPS-only via WAF or listener rules; and use VPC endpoints so service traffic stays on the AWS network. Set S3 bucket policies that deny aws:SecureTransport = false.

Goal Control AWS service
Know what’s sensitive Automated discovery/classification Amazon Macie
Encrypt at rest, you hold keys Customer-managed keys + key policy AWS KMS (CMK)
Highest custody assurance Single-tenant FIPS L3 HSM AWS CloudHSM
Prevent unencrypted resources Preventive guardrail SCP / RCP / Config rule
Immutable, recoverable data WORM backups, object lock AWS Backup Vault Lock, S3 Object Lock
Encrypt in transit TLS certs + enforcement ACM, Private CA, secure-transport policy
Keep people away from data Tokenization, query-only access Macie + IAM + least privilege

Artifacts and decisions. A data classification policy and tagging standard; a KMS key hierarchy with documented key policies and rotation; an encryption-by-default enforcement set; a backup and retention (WORM) plan; and a TLS policy. Key decisions: KMS managed rotation versus manual; CloudHSM only where regulation demands it (it’s expensive and operationally heavy).

Worked example — separation of duties in a KMS key policy. “Keep people away from data” sounds like a slogan until you write the key policy. Encryption at rest with a customer-managed key (CMK) lets you split two powers that a single person should never hold at once: the power to use data and the power to destroy the key that protects it. In this policy, the application role can encrypt and decrypt but cannot administer the key; a separate key-admin role can manage the key but cannot read data with it:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "KeyAdministration",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::123456789012:role/key-admins" },
      "Action": [
        "kms:Create*", "kms:Describe*", "kms:Enable*", "kms:Disable*",
        "kms:PutKeyPolicy", "kms:ScheduleKeyDeletion", "kms:CancelKeyDeletion"
      ],
      "Resource": "*"
    },
    {
      "Sid": "KeyUsageByApp",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::123456789012:role/payments-app" },
      "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey", "kms:DescribeKey"],
      "Resource": "*"
    }
  ]
}

The key-admins role can delete the key but has no Decrypt; the payments-app role can decrypt but cannot change the policy or delete the key. Neither can quietly become the other — that is separation of duties, enforced by the key policy itself. For the deeper mechanics — envelope encryption, grants, and rotation — see the KMS deep dive.

Worked example — make encryption and TLS non-optional. Encryption-by-default only holds if the unencrypted path is refused. This S3 bucket policy denies any request not using TLS, and any upload that does not ask for server-side encryption with KMS:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::finpeak-cardholder-data",
        "arn:aws:s3:::finpeak-cardholder-data/*"
      ],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    },
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::finpeak-cardholder-data/*",
      "Condition": {
        "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
      }
    }
  ]
}

DenyInsecureTransport forces HTTPS — the aws:SecureTransport key is false for plain HTTP. DenyUnencryptedUploads rejects any PutObject that does not request aws:kms encryption. S3 now applies server-side encryption by default, so this policy is a belt-and-braces guarantee that survives a bucket being recreated without that default — exactly the kind of preventive control an auditor wants to see. Enforce the same intent org-wide with an SCP or a Config rule so no team can opt out.

Incident response (SEC 10)

What it is. Your prepared, rehearsed ability to respond to a security event and recover with minimal impact — SEC 10 (“How do you anticipate, respond to, and recover from incidents?”).

Why it matters. Assume compromise will happen. The difference between a contained incident and a breach headline is preparation: pre-provisioned access, automation, and practice.

How to do it well. Prepare before the incident. Educate the team and define roles (incident commander, investigator, communications). Pre-stage a dedicated security/forensics account with the tooling and a clean environment for analysis. Pre-create least-privilege IR IAM roles so responders aren’t fumbling for access mid-incident, plus a break-glass path. Codify response so it’s fast and consistent: EventBridge rules trigger Systems Manager Automation runbooks or Lambda to isolate a compromised EC2 instance (swap to a quarantine security group, snapshot its EBS volume for forensics, deregister it), revoke sessions, or disable a leaked key. Use GuardDuty findings as the common trigger and Detective for scoping. Keep detailed, immutable logs (the central CloudTrail/Security Lake) as your forensic source of truth. Critically, run game days — simulate a credential leak or a public S3 bucket and execute the playbook end to end, then feed lessons back into automation.

IR phase Preparation artifact AWS mechanism
Prepare Runbooks, roles, forensics account IAM roles, dedicated account, SSM docs
Detect Alerting on findings GuardDuty, Security Hub -> EventBridge
Contain Isolate instance, revoke creds SSM Automation, Lambda, quarantine SG
Eradicate/Recover Rebuild from clean images Image Builder, AWS Backup, IaC redeploy
Investigate Forensic capture & analysis EBS snapshots, Detective, Security Lake
Learn Post-incident review Game-day findings -> automation updates

Artifacts and decisions. A documented IR plan mapping severity to actions; named playbooks for the top scenarios (leaked key, exposed bucket, compromised instance, IAM privilege escalation); pre-provisioned IR roles and forensics account; and a game-day cadence (quarterly). Decision: how much to automate containment outright versus require a human approval gate (over-aggressive auto-isolation can cause its own outage).

Worked example — automated containment of a compromised instance. The difference between an incident and a breach is often minutes, so the top IR scenarios are pre-wired. Here the trigger is a GuardDuty finding that an EC2 instance is talking to a known command-and-control host; an EventBridge rule matches that finding type and starts a Systems Manager Automation runbook:

{
  "source": ["aws.guardduty"],
  "detail-type": ["GuardDuty Finding"],
  "detail": {
    "type": [{ "prefix": "Backdoor:EC2" }, { "prefix": "Trojan:EC2" }]
  }
}

The runbook it launches performs containment in a fixed order: snapshot the EBS volume first (so forensic evidence is captured before anything changes), then swap the instance’s security group for a quarantine SG with no ingress and no egress except to a forensics endpoint, deregister it from its load balancer, and finally page the incident commander. Snapshot-before-isolate matters — isolate first and a panicking attacker may wipe the disk before you have a copy.

The decision every team wrestles with is how much to automate. Full auto-isolation is fast but can take down a healthy instance on a false positive; a human-approval gate is safer but adds minutes. A common compromise is to auto-snapshot and auto-tag immediately (non-disruptive) but require a one-click approval to isolate. Whatever you choose, rehearse it: a game day that fires a benign finding and runs the whole runbook end-to-end is the only way to learn that your quarantine SG still allowed DNS out, or that the IR role had quietly expired.

Application security (SEC 11)

What it is. Building security into how applications are designed, built, and shipped — shifting left so vulnerabilities are caught in the pipeline, not in production. SEC 11 is the newest area in the pillar.

Why it matters. The application layer is where business logic — and its flaws — live. Network and host controls won’t stop a SQL injection or a leaked secret in source. Security must be a property of the SDLC.

How to do it well. Embed controls across the pipeline and make secure the easy path. Train developers and provide paved-road templates with security built in. In the pipeline: scan source with SAST, dependencies with SCA (e.g., GitHub/CodeGuru, third-party scanners), and container images with Amazon Inspector in ECR; block on critical findings as a CI gate. Catch hardcoded secrets before commit with secret scanning, and store real secrets in Secrets Manager. Use Amazon CodeGuru Security (and increasingly Amazon Q Developer’s review capabilities) for ML-assisted code review of vulnerabilities and leaked credentials. Enforce that infrastructure is reviewed too — run IAM Access Analyzer policy validation and cfn-guard / Checkov against IaC in CI. At runtime, protect the deployed app with AWS WAF (managed rule groups for OWASP Top 10, bot control, rate limiting) and authenticate/authorize APIs with Amazon Cognito or a custom authorizer. Validate the whole thing periodically with penetration testing. Manage the build-to-deploy chain for integrity (signed artifacts, provenance) and centralize developer scanning at scale.

SDLC stage Risk addressed Tool/service
Code Injection, insecure patterns SAST, Amazon CodeGuru Security, Amazon Q
Dependencies Vulnerable libraries SCA / Inspector for Lambda & functions
Secrets Hardcoded credentials Pre-commit secret scanning + Secrets Manager
Containers Vulnerable images Amazon Inspector (ECR)
Infrastructure as code Misconfig, over-permission Access Analyzer validation, cfn-guard/Checkov
Runtime (L7) OWASP Top 10, bots, scraping AWS WAF managed rules + Shield
AuthN/Z Broken access control Amazon Cognito, custom authorizers

Artifacts and decisions. A secure SDLC standard; the CI gate policy (what severity blocks a merge); a paved-road service template; a dependency/SBOM policy; a pen-test schedule; and a WAF rule baseline for every public endpoint. Decision: how hard to gate (blocking criticals is non-negotiable; blocking every medium will get the gate disabled — tune to keep developer trust).

Worked example — a CI gate that blocks on criticals. Application security becomes real at the moment a pipeline refuses to merge insecure code. The shape of every effective gate is the same: run a scanner, read its severity, exit non-zero on critical. Here is the idea as a build stage that scans infrastructure-as-code and fails the build if a check fails:

# buildspec fragment — block the deploy on IaC misconfig or leaked secrets
phases:
  build:
    commands:
      - pip install checkov detect-secrets
      # Fail the build on any HIGH/CRITICAL IaC misconfiguration
      - checkov -d ./infra --compact --hard-fail-on HIGH
      # Fail if a credential-shaped string was committed
      - detect-secrets scan ./ > .secrets.report && detect-secrets audit .secrets.report

The --hard-fail-on HIGH flag is the gate: a bucket that would be created public, a security group open to the world, or an over-broad IAM policy stops the pipeline before it ever reaches AWS. Complement static IaC checks with IAM Access Analyzer policy validation in the same job, container image scanning with Amazon Inspector in ECR, and Amazon CodeGuru Security (or Amazon Q Developer’s review) for the application code itself.

The tuning that keeps the gate alive is what severity blocks. Block every low and medium and developers will disable the gate within a sprint; block only criticals plus known-bad (leaked secrets, public data stores) and the gate keeps their trust. Then make the secure path the easy path with a paved-road template that ships a least-privilege role, WAF, and Cognito already wired in — so doing the right thing is less work than doing the wrong thing.

Real-world enterprise scenario

FinPeak Lending is a fictional digital consumer-lending company (~600 engineers, regulated under PCI DSS and regional banking rules) migrating from a sprawl of 40-plus unmanaged AWS accounts into a governed organization ahead of an audit. Their CISO mandates Well-Architected Security alignment in two quarters. Here is what they do for each area.

Security foundations. They deploy AWS Control Tower, restructure into a Security OU (Log Archive + Audit accounts), Workloads OU (prod/stage/dev per the four product lines), Infrastructure OU (shared networking, CI/CD), and Sandbox OU. SCPs deny disabling CloudTrail/GuardDuty/Config, restrict to two Regions (ap-south-1, eu-west-1), and deny root access except for break-glass. An RCP enforces aws:PrincipalOrgID on all resource policies. Accounts are vended via Account Factory for Terraform — a baseline now takes 25 minutes instead of the prior two-day manual checklist.

Identity and access management. They federate Entra ID into IAM Identity Center with SCIM, retire 280 standing IAM users, and define 22 permission sets mapped to job functions. FIDO2 MFA is mandatory. GitHub Actions deploys via OIDC role assumption — they delete 60-plus long-lived CI keys. Access Analyzer runs in CI and flags one external-sharing finding on a marketing bucket within the first week.

Detection. An organization CloudTrail trail lands in the locked Log Archive bucket. GuardDuty and Security Hub run org-wide from the Audit account (delegated admin), with the AWS FSBP and PCI DSS standards enabled; their initial Security Hub score is 71%. Config conformance packs enforce PCI controls. EventBridge routes high/critical findings to PagerDuty and Slack; Security Lake centralizes logs for their Splunk SIEM.

Infrastructure protection. Workloads move into private subnets behind a centralized inspection VPC (Transit Gateway + AWS Network Firewall + DNS Firewall). Public endpoints get AWS WAF (managed OWASP rules) governed by Firewall Manager, plus Shield Advanced on the customer-facing CloudFront distributions. Bastions are gone — all access is via SSM Session Manager. Inspector scans EC2 and ECR continuously; IMDSv2 is enforced fleet-wide via an SCP-backed Config rule.

Data protection. Macie scans S3 and finds unencrypted PII in two legacy buckets on day three. They define four classification tiers, enable default KMS CMK encryption on S3/EBS/RDS/DynamoDB, and add an SCP denying creation of unencrypted resources. Cardholder data sits in a dedicated account with a CloudHSM-backed key and tokenization, so application teams query tokens, not PANs. AWS Backup with vault lock provides WORM recovery; ACM + Private CA enforce TLS end to end.

Incident response. A dedicated forensics account is pre-staged with IR roles and SSM Automation runbooks: a GuardDuty “compromised instance” finding auto-snapshots the EBS volume, moves the instance to a quarantine SG, and pages the on-call IC. They run a quarterly game day; the first one (simulated leaked access key) exposes a missing session-revocation step, which they then automate.

Application security. Every pipeline gains SAST, SCA, secret scanning (pre-commit), CodeGuru Security review, and ECR image scanning; criticals block the merge. IaC is validated with cfn-guard and Access Analyzer in CI. A paved-road service template ships with a least-privilege role, WAF, and Cognito wired in.

Measurable outcome. Within two quarters: Security Hub score rises from 71% to 94%; standing IAM users drop from 280 to 0 and long-lived CI keys from 60+ to 0; mean time to detect (via GuardDuty -> PagerDuty) falls from days to under 15 minutes; 100% of S3/EBS/RDS encrypted with customer-managed keys; account provisioning drops from ~2 days to 25 minutes; and FinPeak passes its PCI DSS assessment with zero critical findings.

Going deeper

The seven areas above are the map. This section is the terrain an experienced engineer actually navigates: how the policies combine, where the sharp edges are, and what it costs.

How a request is actually authorized (policy evaluation)

Every “can this principal do this?” decision runs the same evaluation, and understanding the order is what separates people who guess at IAM from people who reason about it. AWS starts from an implicit deny and evaluates several policy types together:

  1. Organization SCPs / RCPs — the outer ceiling. If an SCP does not allow the action (or explicitly denies it), the request dies here no matter what any account-level policy says. This is why an admin in a member account still cannot turn off CloudTrail when the SCP forbids it.
  2. Resource-based policy — e.g., the S3 bucket policy or the KMS key policy. A resource policy can grant access to a principal without an identity policy (cross-account access works this way).
  3. Identity-based policy — the policy attached to the user or role.
  4. Permissions boundary — the cap on that principal.
  5. Session policy — an optional further narrowing passed at AssumeRole time.

The rules that matter: an explicit Deny anywhere wins, always. Absent a deny, the action must be explicitly allowed by the relevant policy set (with the nuance that a resource-policy allow can stand alone for cross-account). SCPs, boundaries, and session policies only ever subtract — they never grant. So the mental model is an intersection of ceilings over a union of grants: the effective permission is what the identity and resource policies grant, clipped by every ceiling (SCP, RCP, boundary, session), minus any explicit deny. When something “should work but doesn’t,” walk these layers top-down; the culprit is almost always a ceiling you forgot, not the identity policy you were staring at.

The data perimeter: three questions, three condition keys

Mature teams frame infrastructure and data protection as a data perimeter — guardrails that answer three questions, each with a global condition key you enforce in SCPs, RCPs, and VPC endpoint policies:

Perimeter Question Where you enforce it Condition key
Identity Is this one of my identities? RCP on resources aws:PrincipalOrgID
Resource Is this one of my resources? SCP on principals aws:ResourceOrgID
Network Is this from an expected network? VPC endpoint policy / SCP aws:SourceVpc, aws:SourceVpce

Together they make three promises: only your identities can act, they can only act on your resources, and only from your networks. That triad is what actually stops the “data exfiltrated to an attacker’s account” and “credentials replayed from an unexpected IP” scenarios that pure identity policies miss.

Running org-wide services the right way: delegated administration

A recurring foundations decision is which account runs GuardDuty, Security Hub, Config, IAM Access Analyzer, Macie, and Detective for the whole organization. The answer is almost never the management account — it sits at the top of your blast radius and should hold as little as possible. Instead, designate a dedicated Audit / Security Tooling account as the delegated administrator for each service. From there you enable the service org-wide, auto-enroll new accounts as they are vended, and view every account’s findings in one place — all without handing day-to-day responders access to the management account. The management account keeps a deliberately tiny footprint: Organizations, billing, and break-glass, nothing else.

Cost and scale: where security bills hide

Security controls are cheap to turn on and expensive to leave un-tuned:

The Well-Architected trade-off here is explicit: more telemetry improves detection and forensics but costs money and creates noise. The right answer is risk-weighted coverage, not maximal coverage.

KMS at scale: key policies, grants, and reach

The KMS key policy is the root of trust for a key, but at scale you rarely hand-edit it per consumer. Two mechanisms extend it: grants (temporary, programmatic permissions an AWS service creates on your behalf — for example EBS asking to use a key to encrypt a volume) and the kms:ViaService condition, which restricts a key so it can be used only through a named service (say, only via s3.ap-south-1.amazonaws.com), never directly by a principal. For workloads spanning Regions, multi-Region keys share key material across Regions so you can decrypt in a failover Region without a cross-Region call — powerful, but they widen the trust boundary, so reserve them for genuine multi-Region data. Cross-account key use always requires both the key policy to allow the external account and that account’s identity policy to allow the key — the same “grant on both sides” rule as any cross-account access.

Failure modes and API caveats worth knowing

The Well-Architected review as a mechanism

Finally, the pillar is not a document you read once — it is a review you run. In the AWS Well-Architected Tool you define a workload and answer the SEC 1–SEC 11 questions; unanswered or “no” responses surface as High-Risk Issues (HRIs) and Medium-Risk Issues with linked improvement guidance. Save a milestone at each review so you can show posture improving release over release (FinPeak’s Security Hub score climbing 71% → 94% below is exactly this, quantified). Treat the output as a prioritized backlog: fix HRIs first, automate the fix so it cannot regress, then re-review. That loop — review, remediate, automate, re-review — is how the Security pillar becomes a habit instead of a slogan.

Deliverables & checklist

Common pitfalls

Common beginner mistakes

These are the misconceptions newcomers carry into the Security pillar — not architecture anti-patterns (those are in Common pitfalls above) but wrong mental models that make the whole subject harder than it is.

Practice challenges

Work these in order; each has a worked solution. Do them against a sandbox account — several are preventive controls that will deliberately block things.

1 (Beginner) — Map the principles. Name which of the seven security design principles each of these serves: (a) enabling an organization CloudTrail trail, (b) requiring FIDO2 MFA, © enabling default S3 encryption, (d) running a quarterly game day.

<details><summary>Solution</summary>

(a) Maintain traceability; (b) Implement a strong identity foundation; © Protect data in transit and at rest; (d) Prepare for security events. (Enabling encryption also supports keep people away from data.) Why: every control should ladder up to a named principle — if you cannot name it, question whether the control is pulling its weight.

</details>

2 (Beginner) — Read the SCP. Using the Region-lock SCP earlier in this lesson, explain what happens when an engineer tries to create an IAM role, and separately when they try to launch an EC2 instance in us-west-2.

<details><summary>Solution</summary>

The IAM role succeedsiam:* is in the NotAction carve-out because IAM is a global service transacting in us-east-1. The EC2 launch in us-west-2 is denied — it is not in the ["ap-south-1","eu-west-1"] allow-list and EC2 is not a carved-out global service. Why: the NotAction + aws:RequestedRegion pattern is the standard Region guardrail, and knowing why global services are exempt saves you from the classic “I locked out IAM” outage.

</details>

3 (Intermediate) — Kill the standing key. A GitHub Actions workflow deploys to AWS using a stored AKIA… access key. Describe the change that removes the key entirely, and the one policy line that stops other repositories abusing it.

<details><summary>Solution</summary>

Create an IAM OIDC identity provider for token.actions.githubusercontent.com, then a role whose trust policy allows sts:AssumeRoleWithWebIdentity with a StringLike condition on token.actions.githubusercontent.com:sub scoped to the exact repo and branch (e.g. repo:org/repo:ref:refs/heads/main); the workflow uses aws-actions/configure-aws-credentials with no stored secret. The load-bearing line is the sub condition — without it, any repo can assume the role. Why: short-lived federated credentials remove the #1 breach vector (leaked long-lived keys), and the sub filter is the control that scopes trust to exactly one pipeline.

</details>

4 (Intermediate) — Enforce encryption preventively. Default SSE is on, but compliance wants a guarantee that objects in finpeak-cardholder-data are always written with your KMS key and always over TLS. Name the two Deny conditions.

<details><summary>Solution</summary>

A bucket-policy Deny on s3:PutObject with Condition: StringNotEquals { "s3:x-amz-server-side-encryption": "aws:kms" }, and a Deny on s3:* with Condition: Bool { "aws:SecureTransport": "false" } (see the worked example in Data protection). Why: default encryption can be silently lost when a bucket is recreated, so an explicit deny is the belt-and-braces control an auditor accepts, and aws:SecureTransport = false is how you force HTTPS.

</details>

5 (Advanced) — Trace the evaluation. A role has an identity policy allowing s3:GetObject on a bucket, the bucket policy is silent, yet the call is denied. The account is in an OU with an SCP. Where do you look, in order, and what is the most likely cause?

<details><summary>Solution</summary>

Walk the ceilings top-down: (1) SCP — does it allow s3:GetObject in this Region? A Region-lock or a service-deny SCP is the most likely culprit, since the identity policy clearly allows the action. (2) Permissions boundary on the role — does it cap out s3? (3) VPC endpoint policy if the call goes through a Gateway endpoint. (4) An explicit Deny in any policy (an RCP, a bucket-policy condition) — explicit deny always wins. Why: “allowed but denied” is almost always a ceiling (SCP / boundary / endpoint / explicit-deny), not the identity policy, so reasoning about the evaluation order finds it fast.

</details>

6 (Advanced) — Design automated containment. Design the trigger-to-action chain that contains an EC2 instance GuardDuty flags as Backdoor:EC2/C&CActivity, capturing forensics without letting an attacker destroy evidence. State the ordering constraint and the human-gate decision.

<details><summary>Solution</summary>

An EventBridge rule matches source: aws.guardduty with a detail.type prefix of Backdoor:EC2, targeting a Systems Manager Automation runbook (or Lambda) that: (1) snapshots the EBS volume first, (2) replaces the instance’s security group with a no-ingress/no-egress quarantine SG, (3) deregisters it from its load balancer / target group, (4) tags it and pages the incident commander. Ordering constraint: snapshot before isolate, so evidence is captured before a panicking attacker can wipe the disk. Human gate: auto-snapshot and auto-tag are safe to fully automate; auto-isolation is often behind a one-click approval to avoid taking down a healthy box on a false positive. Why: pre-wired, ordered containment turns a multi-hour scramble into minutes, and snapshot-first preserves forensics.

</details>

Glossary

What’s next

Part 3 of the AWS Well-Architected Framework series tackles the Reliability pillar — designing for resilience, recovery, and graceful degradation across foundations, workload architecture, change management, and failure management.

AWSWell-ArchitectedSecurityEnterprise
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments