Encryption at rest and KMS policies are the load-bearing primitives of every data-protection control on AWS. As a security engineer, your job is no longer "tick the encryption box" — it is to design a customer-managed CMK hierarchy with key policies, grants, and encryption context that survives audit, to wire per-service encryption (S3, RDS, DynamoDB, EBS, EFS, SQS) so that creation-time-only options never trip you up, to lock down resource policies with Block Public Access, aws:SecureTransport, and Object Lock, and to know when CloudHSM is required because KMS cannot satisfy the regulator. Encryption at rest and KMS policies cover Domain 5 (Data Protection, 18% of SCS-C02) almost entirely, and they bleed into Domains 2 and 3 every time a question mentions confidentiality, integrity, or compliance retention.
This guide walks you through encryption at rest and KMS policies the way the SCS-C02 exam tests them: starting from CMK design and key policy mechanics, through envelope encryption and encryption context, into per-service encryption setup and the creation-time gotchas, then resource policies and S3 hardening, and finally the immutable-storage compliance controls (Object Lock, Vault Lock, Backup Vault Lock) and the narrow CloudHSM use cases. We use a running scenario of a regulated FinTech storing payment records, customer PII, and audit logs to keep the tradeoffs concrete.
What Are Encryption at Rest and KMS Policies on AWS?
Encryption at rest and KMS policies are the combined mechanisms by which AWS protects stored data — in S3 buckets, RDS volumes, DynamoDB tables, EBS volumes, EFS file systems, SQS queues, and many more services — using cryptographic keys whose lifecycle, access, and audit trail you control. Encryption at rest and KMS policies have three layers a security engineer must reason about simultaneously:
- Key layer: customer-managed CMKs (the cryptographic root), AWS-managed keys (
aws/s3,aws/rds, …), AWS-owned keys (invisible), and CloudHSM-resident keys for the rare workload that demands single-tenant HSMs. - Policy layer: key policies (mandatory, the resource policy on every CMK), IAM policies (identity-side), grants (programmatic delegation), encryption context (cryptographically bound key-value pairs), and VPC endpoint policies for
kms:*traffic. - Service-integration layer: how each AWS service wires encryption at rest into its data plane — SSE-S3 vs SSE-KMS vs DSSE-KMS, RDS storage encryption, EBS volume encryption, DynamoDB default encryption, EFS at-create, SQS server-side encryption, and the resource policies (S3 bucket policy, DynamoDB resource-based policy) that complement CMK access control.
- Customer-managed CMK: a KMS key whose key policy, rotation, alias, and lifecycle you control directly.
- AWS-managed key: a CMK with alias prefix
aws/automatically created and rotated by an AWS service; you cannot disable it, schedule it for deletion, or use it cross-account. - Envelope encryption: the pattern where a unique per-object data key encrypts the data, and the CMK encrypts the data key — the only way KMS scales to petabyte-class workloads.
- Encryption context: an authenticated additional-authenticated-data (AAD) dictionary passed to Encrypt/Decrypt; the same context must be provided at decrypt time, and it is logged in CloudTrail.
- KMS Grant: a programmatic, scoped, revocable delegation of CMK permissions, typically used by AWS services (EBS, RDS) to obtain narrow per-resource access.
- CloudHSM: single-tenant FIPS 140-3 Level 3 HSM cluster inside your VPC; the only AWS option where AWS operations staff cannot perform crypto on your keys.
- S3 Object Lock: write-once-read-many retention enforced at the object level; in compliance mode even the root account cannot shorten retention.
- Reference: https://docs.aws.amazon.com/kms/latest/developerguide/overview.html
Why encryption at rest and KMS policies matter for SCS-C02
Domain 5 (Data Protection) carries 18% of the SCS-C02 score, and its Task Statement 5.2 ("Design and implement controls that provide confidentiality and integrity for data at rest") is essentially a checklist of the decisions in this guide: which CMK class, which key policy, which encryption context, which service-level setting, which immutable-storage primitive. Domain 2 (Security Logging and Monitoring) reuses encryption at rest and KMS policies for log integrity. Domain 3 (Infrastructure Security) overlaps when you hard-deny unencrypted resources via SCPs and Config rules. Get the encryption at rest and KMS policies decision tree right and you sweep a disproportionate share of the exam.
Customer-Managed CMK Design — When AWS-Managed Keys Are Not Enough
Every SCS-C02 question that touches encryption at rest implicitly asks "which CMK class". The decision tree is small but unforgiving.
Use a customer-managed CMK when any of these are true
- Audit every use: only customer-managed CMKs surface every Encrypt/Decrypt/GenerateDataKey call in CloudTrail with the calling principal.
- Cross-account access: AWS-managed keys cannot be shared via key policy. The moment a workload in account B must decrypt data produced in account A, you need a customer-managed CMK in A with a key policy that names B.
- Disable on incident: customer-managed CMKs can be disabled (instant) or scheduled for deletion (7–30 day window). AWS-managed keys cannot.
- Imported key material (BYOK): only customer-managed CMKs allow
Origin=EXTERNAL. - Multi-Region replication: only customer-managed CMKs can be
MultiRegion=true. - Key policy conditions on encryption context: only customer-managed CMK policies can use
kms:EncryptionContext:*orkms:EncryptionContextKeysconditions. - Granular IAM separation: customer-managed CMKs let you separate
kms:Encryptfromkms:Decryptfromkms:ReEncrypt*; AWS-managed keys give blanket permission to the integrating service.
AWS-managed keys still have a place
For workloads that are entirely in-account, low-regulation, and cost-sensitive, AWS-managed keys (aws/s3, aws/ebs, aws/rds, aws/dynamodb, aws/secretsmanager) are fine. They cost nothing per month, rotate annually for free, and are zero-touch.
On SCS-C02, every requirement that says "share with another account", "disable during incident response", "import customer-supplied material", "enforce encryption context", or "multi-Region key" rules out AWS-managed keys. The right answer is a customer-managed CMK with an explicit key policy. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html
Naming, aliasing, tagging, and lifecycle
A healthy customer-managed CMK fleet has:
- Aliases that encode tier and purpose:
alias/security/audit-log-cmk,alias/finance/payments-cmk,alias/dev/sandbox-cmk. - Tags for
Owner,Environment,DataClassification, andRotationCadence. - Annual rotation enabled for keys with AWS-managed material. Rotation creates new key material; old material remains for decrypting historical ciphertext.
- AWS Config rules like
kms-cmk-not-scheduled-for-deletionand custom rules requiring tag completeness. - An SCP denying
kms:ScheduleKeyDeletionandkms:DisableKeyoutside a break-glass role.
KMS Key Policies — The Mandatory Resource Policy
A KMS key policy is the primary access-control mechanism for a CMK. Unlike most other AWS services where IAM is sufficient, KMS keys require an explicit key policy that grants permission; IAM alone is never enough unless the key policy delegates trust back to the account via the standard "enable IAM" statement.
The default key policy
When you create a customer-managed CMK in the console, AWS attaches a default key policy with one statement:
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111111111111:root" },
"Action": "kms:*",
"Resource": "*"
}
This statement says "any IAM principal in account 111111111111 may use this CMK if their IAM policy also allows it." Without this statement (or a tighter explicit grant), even the account root cannot use the key — you can lock yourself out, and recovery requires AWS Support.
Key policy patterns the SCS-C02 expects you to write
- Administrators only:
kms:Create*,kms:Describe*,kms:Enable*,kms:List*,kms:Put*,kms:Update*,kms:Revoke*,kms:Disable*,kms:Get*,kms:Delete*,kms:TagResource,kms:UntagResource,kms:ScheduleKeyDeletion,kms:CancelKeyDeletion— assigned to a small admin role. - Use of the key (data plane):
kms:Encrypt,kms:Decrypt,kms:ReEncrypt*,kms:GenerateDataKey*,kms:DescribeKey— assigned to workload roles. - Grant management:
kms:CreateGrant,kms:ListGrants,kms:RevokeGrant— typically scoped to AWS services via thekms:GrantIsForAWSResource: truecondition. - Conditional encryption context enforcement:
"Condition": { "StringEquals": { "kms:EncryptionContext:tenant_id": "${aws:PrincipalTag/tenant_id}" } }— pins use of the key to ciphertexts whose encryption context matches the caller's tag.
Cross-account key policy
For a centralized logging bucket scenario, the owner's CMK key policy must explicitly allow producer accounts:
- Statement 1 — root principal of the owner account, full
kms:*. - Statement 2 — producer principals (specific account roots or an OU via
aws:PrincipalOrgPaths) withkms:GenerateDataKey*andkms:Encrypt. - Statement 3 — narrow set of reader principals with
kms:Decrypt.
Producer accounts also need IAM that names the CMK ARN. Forgetting either side produces an AccessDeniedException whose message references KMS, not the data service — the most common Professional-tier debugging trap.
Unless the key policy has an explicit allow naming the principal directly, the principal also needs IAM permission. Conversely, a permissive IAM policy alone is useless if the key policy does not delegate to IAM via the "Enable IAM User Permissions" statement. Always check both sides. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html
KMS Grants — Temporary, Scoped Delegation
Grants are the SCS-C02-favorite mechanism for narrow, programmatic delegation. While key policies are static and IAM is semi-static, grants are dynamic.
Anatomy of a Grant
A Grant has:
- Grantee principal — the IAM identity that will use the CMK.
- Allowed operations — a subset of
Encrypt,Decrypt,GenerateDataKey*,ReEncrypt*,CreateGrant,RetireGrant,DescribeKey. - Constraints —
EncryptionContextEqualsorEncryptionContextSubsetpin the Grant to ciphertexts whose context matches. - Retiring principal — who can revoke the Grant.
- Optional expiration (no native time-bound expiration; you must
RetireGrantexplicitly or use shadow timeouts via the issuer).
When AWS services use Grants automatically
- EBS creates a Grant when an encrypted volume is attached, scoped to that volume's encryption context (
aws:ebs:id=<vol-id>). - RDS creates a Grant during snapshot, restore, and read-replica operations.
- DynamoDB creates a Grant when a table is created with a customer-managed CMK.
- Lambda creates a Grant to decrypt an encrypted environment variable.
These integration Grants are normal — do not delete them blindly, or the service breaks.
When you create Grants explicitly
- Per-tenant SaaS isolation — one Grant per tenant on a shared CMK, with
EncryptionContextEquals: { tenant_id: "<id>" }. - Just-in-time elevation — break-glass workflow creates a Grant for a responder, logs the issuance, retires after the incident.
- Cross-account ephemeral workloads — Lambda or Fargate task assumes a role and is issued a Grant by the orchestrator.
- Programmatic via
kms:CreateGrant— no IaC pipeline needed to delegate. - Scoped — specific operations + optional encryption context constraints.
- Revocable —
kms:RetireGrantorkms:RevokeGrant. - Additive — cannot override an explicit deny in the key policy.
- Audited — every issuance and use is logged in CloudTrail.
- Soft limit ~50,000 Grants per CMK — not for permanent fleet-wide access; use key policy instead.
- Reference: https://docs.aws.amazon.com/kms/latest/developerguide/grants.html
Envelope Encryption and Encryption Context
Every KMS-integrated AWS service uses envelope encryption under the hood. As a security engineer you must internalize the pattern, because the answer to "why didn't decryption work" is almost always encryption-context-related.
The envelope encryption flow
- Application calls
kms:GenerateDataKeyon a CMK, supplying an encryption context like{ "purpose": "audit-log", "tenant": "4271" }. - KMS returns two values: a plaintext data key (used immediately, discarded after) and an encrypted data key (stored alongside the ciphertext).
- Application encrypts the data with the plaintext data key using AES-256-GCM, then discards the plaintext data key.
- Stored ciphertext =
[encrypted data key | IV | encrypted payload | auth tag]. - To decrypt, application sends the encrypted data key plus the same encryption context to
kms:Decrypt. KMS verifies the context (cryptographically — the context is AAD), returns the plaintext data key, and the application decrypts the payload.
Why encryption context matters for SCS-C02
Encryption context provides authenticated additional data: it must match exactly at decrypt time, or KMS refuses. This is the only way to cryptographically bind a ciphertext to a logical resource (tenant, table, row).
- AWS services use encryption context automatically — for example, S3 SSE-KMS uses
{ "aws:s3:arn": "arn:aws:s3:::bucket/key" }as encryption context. This means a ciphertext copied to a different bucket will not decrypt unless you also usekms:ReEncrypt*or rewrite with the new context. - DynamoDB uses
{ "aws:dynamodb:tableName": "<name>", "aws:dynamodb:subscriberId": "<account>" }. - You can enforce custom encryption context via key policy conditions:
"StringEquals": { "kms:EncryptionContext:tenant": "${aws:PrincipalTag/tenant}" }.
Encryption context shows up in CloudTrail
Every KMS API call logs the encryption context (encryption context keys are logged; values are logged too unless you opt out). This lets your detective controls correlate KMS use with logical resources without parsing application logs.
On SCS-C02, when a question asks "how do you ensure tenant A cannot decrypt tenant B's ciphertext even if both use the same CMK?", the answer is encryption context tied to the caller's principal tag, enforced via key policy condition. Encryption context is the cryptographic complement to ABAC. Reference: https://docs.aws.amazon.com/kms/latest/developerguide/encrypt_context.html
Per-Service Encryption — S3, RDS, DynamoDB, EBS, EFS, SQS
The SCS-C02 exam tests not just KMS abstractions but the per-service knobs. The trap pattern is "encryption is creation-time-only on this service" — get that wrong and your migration plan collapses.
Amazon S3 — SSE-S3, SSE-KMS, DSSE-KMS, SSE-C
S3 supports four server-side encryption modes:
- SSE-S3 (default since 2023) — AES-256 with S3-owned keys. No CloudTrail visibility on key use.
- SSE-KMS — AES-256 with a customer-managed or AWS-managed CMK; full envelope encryption with encryption context
aws:s3:arn. - DSSE-KMS (Dual-layer Server-Side Encryption with KMS) — two independent KMS encryption operations on the same object. Required for some U.S. national security workloads (CNSA Suite). More expensive; rare in commercial scenarios.
- SSE-C — Customer-supplied key; you transmit the key on every request over TLS, S3 uses it once and discards. Useful when you cannot put the key into KMS at all but want server-side encryption.
For SSE-KMS at scale, enable S3 Bucket Keys: a single bucket-level data key generated daily reduces KMS request volume by ~99% — critical for high-throughput buckets where KMS API costs dominate.
Amazon RDS and Aurora — encryption is creation-time only
RDS storage encryption is set at DB instance creation. You cannot toggle it later. To encrypt an existing unencrypted RDS instance:
- Take a snapshot.
- Copy the snapshot with
--kms-key-idset, encryption enabled. The copy is a new encrypted snapshot. - Restore the encrypted snapshot to a new instance.
- Cut over via DNS, blue/green deployment, or logical replication.
For minimum downtime use RDS Blue/Green Deployments (MySQL, MariaDB, PostgreSQL): Green is the encrypted copy, kept in sync via logical replication, promoted with one command.
Amazon DynamoDB — default encryption, three CMK options
DynamoDB encrypts every table at rest by default. You choose:
- AWS-owned key (free, no audit trail) — default for new tables.
- AWS-managed key (
aws/dynamodb, free, no cross-account). - Customer-managed CMK — full control, cross-account, encryption context
aws:dynamodb:tableName.
You can switch CMK class on an existing table (DynamoDB rewrites items to the new key in the background), unlike RDS where it is creation-time.
Amazon EBS — encryption-by-default
Enable EBS encryption-by-default at the account+Region level (ec2:EnableEbsEncryptionByDefault) so every new volume and snapshot is encrypted with the default CMK (or one you specify). Existing unencrypted volumes are not retroactively encrypted; for those:
- Create an encrypted snapshot of the unencrypted volume.
- Create a new encrypted volume from that snapshot.
- Detach old, attach new (downtime).
For root-volume encryption on existing instances, use AMI encryption (copy-image --encrypted --kms-key-id) and re-launch.
Amazon EFS — encryption is creation-time
Like RDS, EFS file systems are encrypted at rest only when the file system is created with --encrypted. You cannot enable encryption on an existing EFS. Migration: aws datasync or rsync from the unencrypted FS to a new encrypted FS.
Amazon SQS — server-side encryption with CMK
SQS supports SSE-KMS with either AWS-managed (aws/sqs) or customer-managed CMKs. Unlike S3, SQS decrypts on the read side automatically — you only need kms:GenerateDataKey on the producer side and kms:Decrypt on the consumer side.
"Enable encryption on the existing database" is never a one-click answer for these services. The workflow is always snapshot → copy-with-encryption → restore (or DataSync for EFS). Distractors that propose modify-db-instance --encrypted true or similar are wrong — the API simply refuses. Reference: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html
Resource Policies for Data Protection — S3, DynamoDB, KMS
Encryption protects data at rest; resource policies protect the data plane around it. The two layers are complementary — a permissive bucket policy can leak encrypted data just as easily as plaintext if the consumer also has the CMK.
S3 bucket policies for hardening
- Block Public Access (BPA) — set at account and bucket level. Overrides any conflicting bucket policy or ACL. Always on for non-public buckets; SCS-C02 expects you to set it.
aws:SecureTransport— denys3:*whenaws:SecureTransportisfalse, forcing TLS for all access.s3:x-amz-server-side-encryption— denys3:PutObjectunless the request specifies SSE-KMS (or SSE-S3) with the expected algorithm.s3:x-amz-server-side-encryption-aws-kms-key-id— denys3:PutObjectunless the named CMK matches the expected ARN; prevents producers from substituting a weaker CMK.aws:SourceVpceoraws:SourceVpc— restrict access to specific VPC endpoints, breaking exfiltration paths that go via public S3.
DynamoDB resource-based policies (relatively new)
DynamoDB now supports resource-based policies on tables, streams, and indexes. As a security engineer you can:
- Deny access from outside an OU (
aws:PrincipalOrgID). - Require
aws:SecureTransport. - Restrict source VPC endpoints.
Combined with the table's customer-managed CMK key policy, you get layered defense — even an over-permissive IAM policy in a workload account cannot exfiltrate the table contents.
KMS key policy as resource policy
KMS key policies are themselves resource policies — every condition you put on a bucket policy can be mirrored on the CMK that protects the bucket's data. Deny kms:Decrypt outside trusted VPCs, deny without a specific encryption context, deny outside business hours for high-sensitivity keys.
A weakly-scoped IAM policy + a strong CMK key policy can still leak data because the principal might have legitimate plaintext access elsewhere. A strong bucket policy + a weak CMK policy lets the bucket be unreachable while a different account decrypts copies. SCS-C02 expects you to layer: BPA + bucket policy + CMK key policy + encryption context, all reinforcing each other. Reference: https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html
Data Integrity Controls — Hashing, Digital Signatures, Object Lock, Vault Lock
Confidentiality is half the Domain 5 mandate — integrity is the other half. SCS-C02 tests integrity via hashing, digital signatures, and immutable storage.
Hashing and digital signatures
- SHA-256 is the default integrity hash for S3 (
x-amz-content-sha256), CloudTrail log file integrity, and most AWS services. Use it for object-level integrity verification on upload/download. - KMS asymmetric keys (RSA, ECC) support
kms:Signandkms:Verifyoperations — you can have KMS sign artifacts and verify signatures without the private key ever leaving KMS. Use cases: signing CodePipeline artifacts, signing CloudTrail-Lake queries, signing Lambda function code. - AWS Signer wraps KMS asymmetric signing for Lambda, IoT, and container image signing — adds revocation and key rotation handling on top.
- CloudTrail log file validation — when enabled, CloudTrail produces a digest file every hour signed with an SHA-256 hash. Use
aws cloudtrail validate-logsto verify integrity post-incident.
S3 Object Lock — compliance vs governance mode
S3 Object Lock stores objects in WORM (write-once-read-many) mode for a fixed retention period or indefinite legal hold.
- Compliance mode — no user, including the root account, can shorten retention or delete the object until the retention period expires. The retention period itself cannot be reduced after it is set. Once set to compliance, you cannot switch back to governance for that object version. Required by SEC 17a-4(f), FINRA 4511, CFTC 1.31.
- Governance mode — users with
s3:BypassGovernanceRetentionpermission can shorten retention or delete. Useful when you want WORM-by-default but need an escape hatch for human error. - Legal hold — independent of retention period; explicit lock that must be removed before delete.
Object Lock requires bucket-level versioning to be enabled. Once Object Lock is enabled on a bucket, you cannot disable it.
Glacier (S3 Glacier vault) Vault Lock
For S3 Glacier vaults (the legacy Glacier API, not the S3 Glacier storage class), Vault Lock is the mechanism to lock a vault access policy in place. Once locked (within a 24-hour edit window), the policy is immutable — you cannot add exceptions, remove restrictions, or shorten retention. Use for SEC-regulated archives, healthcare 7-year retention, etc.
AWS Backup Vault Lock
AWS Backup Vault Lock applies the same WORM principle to AWS Backup recovery points. Two modes:
- Compliance mode — once locked (and after a 3-day cooling-off period), no one can shorten the minimum retention or delete recovery points within that window. Even root cannot delete the lock or recovery points. The ransomware-resilience answer for backups.
- Governance mode — equivalent to S3 Object Lock governance.
For ransomware threat models, the canonical answer is: AWS Backup with cross-account vault + Vault Lock in compliance mode + isolated recovery account. The attacker who compromises production cannot also compromise backups.
Whenever SCS-C02 frames a ransomware or insider-threat scenario asking for "even if attacker has admin/root", the answer is Object Lock compliance mode for S3 and Backup Vault Lock compliance mode for AWS Backup. Standard IAM-based protection is insufficient because root can override IAM. Reference: https://docs.aws.amazon.com/aws-backup/latest/devguide/vault-lock.html
CloudHSM — When KMS Is Not Enough
KMS handles 99% of encryption needs. CloudHSM exists for the narrow workloads where regulators or customers refuse to trust AWS-operated HSMs.
When CloudHSM is required, not just preferred
- PCI HSM — PIN translation, PIN block encryption, and other PCI HSM standard operations. KMS does not implement the PCI HSM API surface. Acquirer banks running card-present authorization need CloudHSM (or equivalent on-premises HSM).
- PKCS #11 / JCE / OpenSSL ENGINE workloads — legacy applications that talk PKCS #11 directly. KMS exposes HTTPS APIs only.
- Single-tenant FIPS 140-3 Level 3 with documented sole custody — when the regulator (BSI TR-03145, certain U.S. DoD/IC standards, PSD2 QES) demands the customer be the sole HSM operator, with crypto officer keys held only by your staff.
- Sovereign data residency where AWS operations must not have any path to keys — rare; usually requires sovereign-cloud regions, but CloudHSM is sometimes the compromise.
- Performance for cryptographic offload — high-volume signing or wrapping workloads where the per-request KMS cost or latency is prohibitive.
CloudHSM availability and cost
- Cluster requires minimum 2 HSMs across 2 Availability Zones for production; 3 across 3 AZs is best practice.
- Cost roughly USD 1.45 per HSM per hour — 2-HSM cluster ~USD 2,100/month, 3-HSM cluster ~USD 3,150/month, before data transfer and operational overhead.
- Cluster is Regional — cross-Region DR requires a second cluster and your own backup/restore key sync.
CloudHSM as KMS custom key store
If you want CloudHSM-resident keys to integrate with KMS-aware AWS services (S3, EBS, RDS), link CloudHSM as a KMS custom key store. CMKs in the custom key store have material physically on CloudHSM but appear as normal CMKs. Tradeoff: KMS-integrated services now depend on CloudHSM availability — if CloudHSM is unreachable, S3/RDS/EBS encryption operations fail.
KMS HSMs are also FIPS 140-3 Level 3. The CloudHSM-only triggers are: explicit PCI HSM API, PKCS #11 application code, regulator demands customer-sole-custody, or sovereign-cloud constraints. Distractors that propose CloudHSM for "high security" or "compliance" without one of those triggers are wrong — KMS is sufficient and cheaper. Reference: https://docs.aws.amazon.com/cloudhsm/latest/userguide/introduction.html
Detective Controls for Encryption at Rest
Encryption is preventive; detective controls prove it stayed on.
- AWS Config rules — managed rules
s3-bucket-server-side-encryption-enabled,rds-storage-encrypted,dynamodb-table-encrypted-kms,ebs-encrypted-volumes,efs-encrypted-check. Aggregate them in an organization-wide AWS Config aggregator for fleet visibility. - AWS Security Hub controls —
[S3.4]ensures S3 buckets have SSE configured;[S3.5]requiresaws:SecureTransport;[KMS.1]flags IAM principals with overly broadkms:Decrypt;[Backup.1]checks Backup Vault Lock. - Amazon Macie — discovers and classifies sensitive data in S3 (PHI, PCI cardholder data, PII) and reports buckets that are unencrypted or publicly accessible.
- CloudTrail data events for S3 + Lambda + KMS — record every object-level access and every KMS API call. Combine with Athena queries to detect anomalous decryption volume per principal.
- GuardDuty findings —
Stealth:S3/ServerAccessLoggingDisabled,Policy:S3/BucketBlockPublicAccessDisabled,CredentialAccess:Kubernetes/MaliciousIPCallerfor stolen creds calling KMS.
A correct encryption-at-rest design without detective controls is a snapshot-in-time configuration that drifts. SCS-C02 expects you to pair every preventive control with at least one Config rule or Security Hub control. Reference: https://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html
Real-World SCS-C02 Scenarios
Scenario 1 — Centralized Audit Log Bucket (Cross-Account)
Requirement: 200 producer accounts write CloudTrail logs to a security-account bucket; only the security team can read; integrity verified.
- Customer-managed CMK in security account, key policy allows producer org path
kms:GenerateDataKey*, only security rolekms:Decrypt. - Bucket policy on security-account bucket:
aws:SecureTransport=true,s3:x-amz-server-side-encryption=aws:kmswith the specific CMK ARN,aws:SourceOrgIDmatches the org. - Object Lock compliance mode with 7-year retention.
- CloudTrail log file validation enabled; integrity verified via
aws cloudtrail validate-logs.
Scenario 2 — Multi-Tenant SaaS with Per-Tenant CMK
Requirement: SaaS platform with thousands of tenants, each tenant must have cryptographic isolation of data.
- Single shared CMK; encryption context
tenant_id=<id>enforced via key policy condition"StringEquals": { "kms:EncryptionContext:tenant_id": "${aws:PrincipalTag/tenant_id}" }. - Application principal tagged at session-creation with the tenant's ID via
sts:TagSession. - KMS Grants per tenant for ephemeral compute (Lambda) with the same encryption context constraint.
- DynamoDB customer-managed CMK using the same scheme; per-item attribute-level encryption with tenant context for the most sensitive fields.
Scenario 3 — Ransomware-Resistant Backups
Requirement: Ransomware attacker compromises production account with admin; backups must remain intact.
- AWS Backup with cross-account backup vault in dedicated isolated account.
- Backup Vault Lock in compliance mode with 90-day minimum retention.
- IAM in production cannot reach the isolated account's vault; only Backup service role assumes into it.
- S3 Object Lock compliance mode on critical bucket.
- Customer-managed CMK in the isolated account with key policy denying
kms:ScheduleKeyDeletionandkms:DisableKeyoutside a break-glass role with hardware MFA.
Scenario 4 — PCI HSM Migration to AWS
Requirement: Acquirer bank running PIN translation must migrate to AWS while remaining PCI HSM compliant.
- KMS is not sufficient — PCI HSM requires PKCS #11 + dedicated HSM with documented sole custody.
- Provision CloudHSM cluster, 3 HSMs across 3 AZs.
- Application uses CloudHSM PKCS #11 client SDK (drop-in for on-premises HSM).
- Document FIPS 140-3 Level 3 certification in PCI RoC.
- KMS is still used for AWS-integrated services (S3, EBS) where PCI cardholder data is stored at rest, with key policies tying decryption to specific compute roles.
SCS-C02 Exam Patterns and Distractors
- "Encrypt the existing RDS instance" → snapshot → copy with
--kms-key-id→ restore. Nevermodify-db-instance --encrypted. - "Cross-account KMS not working" → check both key policy AND consumer IAM; remember encryption context if used.
- "Even root cannot delete" → S3 Object Lock compliance mode OR Backup Vault Lock compliance mode.
- "Cryptographic erasure on demand" → BYOK with imported key material; delete material from KMS to render ciphertext unreadable.
- "AWS operations must not have key access" → CloudHSM with crypto officer credentials held only by you.
- "Per-tenant isolation on shared CMK" → encryption context + key policy condition on
kms:EncryptionContext:tenant_id. - "High-throughput S3 with KMS cost concern" → enable S3 Bucket Keys.
- "Sign artifact with key that never leaves AWS" → KMS asymmetric key with
kms:Sign/kms:Verify. - Distractor patterns: "Use SSE-C for highest security" (no — you must transmit the key on every request); "Use AWS-managed key for cross-account" (impossible); "CloudHSM auto-replicates across Regions" (no, regional only); "Object Lock can be removed by root" (only governance mode; compliance cannot).
Common Mistakes Security Engineers Make
- Forgetting the IAM half of cross-account KMS: key policy delegates to account B, but account B's role does not name the CMK ARN. AccessDeniedException points at KMS, not at S3 — confusing first-time debuggers.
- Using AWS-managed keys for production data: blocks future cross-account, future BYOK, future disable-on-incident. Default to customer-managed CMKs.
- Skipping encryption context: every KMS call without encryption context is harder to audit and impossible to ABAC-bind.
- Toggling encryption on RDS post-creation: not possible. Plan encryption at creation, every time.
- Object Lock governance vs compliance confusion: governance is reversible by privileged users; compliance is not. Audit-driven scenarios always need compliance.
- Backup Vault Lock without cross-account isolation: if backups live in the same account as production, a privileged attacker can disable AWS Backup, schedule key deletion, and erase recovery paths during the cooling-off window. Cross-account isolation closes that gap.
- Choosing CloudHSM by reflex: KMS is FIPS 140-3 Level 3 too. Only specific regulators require CloudHSM.
FAQ — Encryption at Rest and KMS Policies
Q1: When must I use a customer-managed CMK instead of an AWS-managed key?
Whenever the scenario requires any of: cross-account access, multi-Region replication, disable-on-incident, imported key material (BYOK), CloudTrail audit of every key use, or key policy conditions on encryption context. AWS-managed keys cannot satisfy any of those. Default to customer-managed CMKs for production data.
Q2: How do KMS Grants differ from key policy statements?
Key policy is static, attached to the CMK, and changes via an IaC pipeline. Grants are programmatic (issued via kms:CreateGrant), scoped to specific operations and optional encryption context constraints, and revocable on demand. Grants are additive — they cannot override an explicit deny in the key policy. Use grants for ephemeral or per-resource delegation; use key policy for stable fleet-wide permissions.
Q3: What is encryption context, and why does SCS-C02 emphasize it?
Encryption context is an authenticated additional-data dictionary passed to KMS Encrypt/Decrypt. It must match exactly at decrypt time, and KMS verifies cryptographically. It is logged in CloudTrail. SCS-C02 emphasizes it because it is the only way to cryptographically bind a ciphertext to a logical resource (tenant, table, owner) and the only way to ABAC-style restrict CMK use via key policy conditions.
Q4: What is the difference between S3 Object Lock compliance and governance modes?
Governance mode allows users with the s3:BypassGovernanceRetention permission to shorten retention or delete objects — it is a soft WORM. Compliance mode allows no one, including the root account, to shorten retention or delete during the retention period — true WORM. Compliance is required for SEC 17a-4(f), FINRA, CFTC; once set you cannot revert that object version to governance.
Q5: When is AWS CloudHSM required instead of AWS KMS?
CloudHSM is required when the workload must call PKCS #11 / PCI HSM APIs that KMS does not implement, when regulators (BSI, PSD2 QES, certain DoD/IC standards) demand customer-sole-custody of HSM with documented FIPS 140-3 Level 3 single-tenant operation, or when sovereignty rules forbid AWS operations from any path to key material. For "general high security" or routine PCI-DSS at rest, KMS is sufficient and FIPS 140-3 Level 3 itself.
Q6: How do I encrypt an existing unencrypted RDS database with minimum downtime?
You cannot toggle encryption on an existing instance. Take a snapshot, copy the snapshot with --kms-key-id and encryption enabled, restore the encrypted snapshot to a new instance, then cut over. For minimum downtime use the RDS Blue/Green Deployment feature (MySQL, MariaDB, PostgreSQL): the encrypted Green stays in sync via logical replication and you switch with one promotion command.
Q7: How do I make backups resilient to a ransomware attacker who has admin in production?
Use AWS Backup with a cross-account backup vault in a dedicated isolated account, enable Backup Vault Lock in compliance mode with a minimum retention period, and ensure the production account has no IAM path to the isolated vault — only the Backup service role assumes into it. Combine with S3 Object Lock compliance mode on critical buckets and a customer-managed CMK in the isolated account whose key policy denies kms:ScheduleKeyDeletion outside a break-glass role.
Q8: What is the right way to enforce TLS for all access to an S3 bucket?
Add a deny statement in the bucket policy for all s3:* actions when aws:SecureTransport is false. Pair it with Block Public Access at account and bucket level, and an additional deny for s3:PutObject unless s3:x-amz-server-side-encryption matches aws:kms with the expected CMK ARN. Detective control: AWS Config rule s3-bucket-ssl-requests-only.
Wrap-Up
Encryption at rest and KMS policies are not a checkbox — they are an architecture. As a security engineer preparing for SCS-C02, internalize:
- Customer-managed CMKs by default; AWS-managed keys only when no cross-account, no disable-on-incident, no BYOK, no audit demand applies.
- Key policy is mandatory; IAM is complementary; encryption context is the cryptographic ABAC layer; Grants are dynamic, revocable, scoped delegation.
- Per-service encryption gotchas: RDS, Aurora, EBS, EFS, Redshift are creation-time only; DynamoDB and S3 can switch CMKs in place.
- Resource policies layer with CMKs: Block Public Access,
aws:SecureTransport, encryption-required statements on buckets; resource-based policies on DynamoDB; key policy conditions on KMS. - Immutable storage for compliance: S3 Object Lock compliance mode, Glacier Vault Lock, Backup Vault Lock — the only IAM-proof primitives.
- CloudHSM only when a regulator forbids AWS-operated HSM; everything else is KMS.
- Detective controls (Config, Security Hub, Macie, CloudTrail data events) prove your preventive design stays on.
Master encryption at rest and KMS policies and you carry Domain 5 plus a healthy fraction of Domains 2 and 3 into the exam with confidence.