AWSDVA-C02

Domain 2: Security

Topic 2 of 4 · Study notes

AWS Certified Developer – Associate (DVA-C02)

Domain 2: Security

Exam Code: DVA-C02 | Level: Associate
Domain Weight: 26% | Total Domains: 4 | Passing Score: 720/1000


Table of Contents

  1. AWS IAM — Identity & Access Management
  2. AWS STS — Security Token Service
  3. AWS KMS — Key Management Service
  4. Amazon S3 Security
  5. Amazon Cognito Security
  6. API Gateway Security
  7. Secrets Manager & SSM Parameter Store
  8. Encryption at Rest & In Transit
  9. Network Security
  10. AWS CloudTrail & Audit
  11. Exam Tips & Quick Reference

1. AWS IAM — Identity & Access Management

IAM is the security centre of every AWS account. It controls who can authenticate (who you are) and what they are authorized to do (what you can access). Every AWS API call is authorized through IAM.

1.1 Core Components & Policy Structure

Component Description
Root Account Created with the AWS account. Has unrestricted access. Never use for daily tasks.
Users Individual identities for humans or applications. Have long-term credentials (passwords and access keys).
Groups Collections of IAM users. Policies attached to a group apply to all its members.
Roles Identities assumed temporarily. No long-term credentials. Used by services, applications, and federated users.
Policies JSON documents that define permissions. Attached to users, groups, or roles.

Key structural rules:

  • Groups contain users only — you cannot nest groups inside groups.
  • A user can belong to multiple groups simultaneously.
  • Roles are assumed temporarily via STS — they issue short-lived credentials.

IAM Policy JSON Structure:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3Read",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::my-bucket/*"],
      "Condition": {
        "StringEquals": { "aws:RequestedRegion": "us-east-1" }
      }
    }
  ]
}
Field Required Notes
Version Yes Always "2012-10-17". Omitting it causes subtle permission failures.
Effect Yes "Allow" or "Deny".
Principal Resource policies only Specifies who the policy applies to. Not used in identity-based policies.
Action Yes AWS API actions (e.g., s3:GetObject, ec2:*).
Resource Yes ARN of the target resource. Use "*" to match all resources.
Condition No Optional constraints — MFA required, source IP, time of day, etc.

Critical: The Principal field only appears in resource-based policies (S3 bucket policies, SQS queue policies, Lambda resource policies, KMS key policies). Identity-based policies attached to users, groups, and roles do NOT include a Principal.

Policy Types:

Type Attached To Key Characteristic
AWS Managed Users, groups, roles Maintained and updated by AWS. Suitable for common use cases.
Customer Managed Users, groups, roles You own them. Versioned, reusable, centrally managed. Best practice.
Inline A single user, group, or role Strict 1:1 binding. Deleted when the principal is deleted. Not reusable.
Resource-based AWS resources (S3, SQS, Lambda) Attached to the resource itself. Includes Principal. Enables cross-account access.

1.2 Policy Evaluation Logic

┌─────────────────────────────────────────────────────────────────────┐
│                    IAM Policy Evaluation Flow                        │
│                                                                       │
│  Start: Default DENY (implicit)                                       │
│                                                                       │
│  Evaluate ALL applicable policies:                                    │
│  • Identity-based policies (user, group, role)                        │
│  • Resource-based policies (S3 bucket policy, etc.)                   │
│  • Permissions boundaries                                             │
│  • SCPs (Service Control Policies, if using AWS Organizations)        │
│                                                                       │
│  ┌────────────────────────────────────────┐                           │
│  │  Any EXPLICIT DENY found?              │──► YES ──► Final: DENY    │
│  └────────────────────────────────────────┘                           │
│                       │ NO                                            │
│                       ▼                                               │
│  ┌────────────────────────────────────────┐                           │
│  │  Any EXPLICIT ALLOW found?             │──► YES ──► Final: ALLOW   │
│  └────────────────────────────────────────┘                           │
│                       │ NO                                            │
│                       ▼                                               │
│                  Final: DENY (implicit)                               │
└─────────────────────────────────────────────────────────────────────┘

Critical: An explicit DENY always wins over any ALLOW, regardless of which policy contains it. There is no way to override an explicit DENY.

Union evaluation — IAM + S3 Bucket Policy:

IAM Policy S3 Bucket Policy Result
Allow No bucket policy Allow — IAM policy alone is sufficient
Allow Explicit Deny Deny — explicit deny always wins
No S3 permissions Allow Allow — resource policy alone is sufficient
Explicit Deny Allow Deny — explicit deny always wins

1.3 IAM Roles & iam:PassRole

Role components:

  • Trust Policy — defines who can assume this role (the principal: a service, another account, a user).
  • Permission Policy — defines what the role can do once assumed.
// Trust Policy example — allows EC2 to assume this role
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "ec2.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}

Common service role assignments:

Service Role Type Purpose
EC2 Instance Profile Allows application code on EC2 to call AWS APIs without hardcoded keys
Lambda Execution Role Allows Lambda to access S3, DynamoDB, CloudWatch Logs, etc.
ECS Task Task Role Allows container application code to access AWS services
CodeBuild Service Role Allows CodeBuild to pull from CodeCommit, push to ECR, read Parameter Store
CloudFormation Service Role Allows CloudFormation to create, update, and delete stack resources

iam:PassRole — The gatekeeper permission:

When you assign an IAM role to an AWS service (launch EC2 with a role, create a Lambda function with an execution role), you are "passing" that role to the service. AWS requires you to have explicit permission to do this.

// Policy granting a developer the ability to pass a specific role to EC2
{
  "Effect": "Allow",
  "Action": ["iam:PassRole", "iam:GetRole"],
  "Resource": "arn:aws:iam::123456789012:role/EC2AppRole"
}

Critical Exam Trap: Having ec2:RunInstances permission does NOT grant the ability to launch an EC2 instance with an IAM role. iam:PassRole is a separate, required permission. Missing it results in Access Denied even when the user has full EC2 permissions.

1.4 Permissions Boundary & Condition Keys

Permissions Boundary:
A managed policy that acts as an upper limit on what permissions an identity policy can grant. The effective permissions are the intersection of the boundary and the identity policy.

Permissions Boundary: Allow S3, EC2
Identity Policy:      Allow S3, DynamoDB
────────────────────────────────────────
Effective Permissions: Allow S3 only

Key Rule: A boundary does not GRANT permissions.
          It only LIMITS what identity policies can grant.

Use case: allow developers to create IAM roles for their services, but prevent them from creating roles with permissions beyond what they themselves have (preventing privilege escalation).

Common IAM Condition Keys:

// Require MFA for sensitive actions
"Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } }

// Restrict access to a specific AWS region
"Condition": { "StringEquals": { "aws:RequestedRegion": "us-east-1" } }

// Require HTTPS (deny non-secure transport)
"Condition": { "Bool": { "aws:SecureTransport": "true" } }

// S3: restrict access to each user's own prefix
"Condition": { "StringLike": { "s3:prefix": ["home/${aws:username}/*"] } }

// DynamoDB: restrict access to each user's own rows
"Condition": {
  "ForAllValues:StringEquals": {
    "dynamodb:LeadingKeys": ["${aws:userid}"]
  }
}

// Restrict by resource tag value
"Condition": { "StringEquals": { "aws:ResourceTag/Environment": "Production" } }

1.5 Credential Chain & Audit Tools

AWS CLI and SDK Credential Resolution Order (first match wins):

1. Command-line options  (e.g., --profile, --region flags)
2. Environment variables  (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
3. AWS credentials file   (~/.aws/credentials)
4. AWS config file        (~/.aws/config)
5. ECS container credentials  (for tasks running on ECS)
6. EC2 Instance Profile   (IMDS at 169.254.169.254) ← lowest priority

Critical Exam Trap: If environment variables are set on an EC2 instance, they override the Instance Profile — even though the Instance Profile is the recommended and more secure approach. Always remove hardcoded environment variable credentials from EC2 and rely on the Instance Profile instead.

IAM Audit Tools:

Tool What It Shows
IAM Credentials Report Account-level snapshot: all users, their password status, access key ages, last used dates, MFA status
IAM Access Advisor Per user/role: which AWS services were last accessed and when. Use to identify and remove unused permissions.
AWS CloudTrail All IAM API calls with caller identity, timestamp, and source IP

IAM Best Practices:

  • Never use the root account for daily operations. Lock it down and enable MFA.
  • Enable MFA on all privileged users.
  • One physical person = one IAM user. Never share credentials.
  • Assign permissions to groups, not directly to individual users.
  • Use IAM roles for all service-to-service access. Never hardcode access keys.
  • Rotate access keys regularly. Use the Credentials Report to find old keys.
  • Apply least privilege — grant only what is needed and nothing more.

2. AWS STS — Security Token Service

STS issues temporary, limited-privilege security credentials for IAM users, federated users, or AWS services assuming roles.

2.1 Key APIs & Cross-Account Access

API Use Case
AssumeRole Assume an IAM role in the same account or a different account
AssumeRoleWithSAML Federate with a corporate SAML 2.0 identity provider (Active Directory, Okta)
AssumeRoleWithWebIdentity Federate with a web identity provider (Google, Facebook, OIDC). AWS recommends using Cognito instead.
GetSessionToken Get temporary credentials that satisfy MFA-required IAM conditions
GetCallerIdentity Returns the account ID, user ID, and ARN of the current caller. Essential for debugging identity issues.
DecodeAuthorizationMessage Decodes the encoded error message returned in an authorization failure response

Cross-Account Access Flow:

┌─────────────────────────────────────────────────────────────────────┐
│                   Cross-Account Role Assumption                      │
│                                                                       │
│  Account A (Dev)                    Account B (Prod)                 │
│  ┌──────────────┐                   ┌───────────────────────────┐    │
│  │  IAM User    │──sts:AssumeRole──►│  IAM Role "ReadProdData"  │    │
│  │  "Alice"     │                   │  Trust: Account A allowed │    │
│  └──────────────┘                   └──────────────┬────────────┘    │
│        │                                           │                 │
│        │◄─────── Temporary credentials ───────────┘                 │
│        │         (AccessKey, SecretKey, SessionToken)                │
│        │                                                             │
│        └──────────────────────────────────────────────────────────► │
│                   Access Account B resources using temp creds        │
└─────────────────────────────────────────────────────────────────────┘

Setup requirements for cross-account access:

  1. Account B: Create an IAM Role with a Trust Policy that allows Account A's user or role to assume it.
  2. Account A: Attach an IAM Policy to the user/role that allows sts:AssumeRole on Account B's role ARN.

Temporary credential duration:

  • Minimum: 15 minutes.
  • Maximum: 1 hour for most role assumptions.
  • Maximum: 12 hours for console federation sessions.

MFA with CLI:

# Step 1: Get temporary credentials using your MFA device
aws sts get-session-token \
  --serial-number arn:aws:iam::123456789012:mfa/alice \
  --token-code 123456 \
  --duration-seconds 3600

# Step 2: Export the returned credentials as environment variables
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

# Now run commands that require MFA — credentials contain the MFA assertion

3. AWS KMS — Key Management Service

KMS is the central service for creating and managing cryptographic keys. All KMS API calls are logged in CloudTrail, providing a complete audit trail of key usage.

3.1 Key Types & Algorithms

By Ownership:

Key Type Monthly Cost Auto-Rotation Level of Control
AWS Owned Free AWS-managed None — used internally by AWS services
AWS Managed Free Every 1 year (automatic) View only — you cannot change policies
Customer Managed (CMK) $1/month Optional (enable for 1-year rotation) Full control — policies, rotation, deletion
Imported Key Material $1/month Manual only — via alias update You supply and manage the key material

Critical: Imported key material does NOT support automatic rotation. To rotate, you must create a new CMK, import new material, and update the alias to point to the new key.

By Algorithm:

Algorithm Type Use Case
AES-256 (Symmetric) Single key for encrypt and decrypt All AWS service integrations (S3, EBS, RDS). You never see the raw key material.
RSA / ECC (Asymmetric) Public key + private key pair Sign/verify or encrypt/decrypt. Download public key for use outside AWS without calling KMS.

3.2 KMS APIs & Envelope Encryption

Core KMS APIs:

API Data Size Limit Purpose
Encrypt 4 KB maximum Encrypt small data (passwords, tokens) directly using a CMK
Decrypt 4 KB maximum Decrypt data previously encrypted by KMS
GenerateDataKey No limit Generate a data encryption key — returns plaintext copy AND encrypted copy
GenerateDataKeyWithoutPlaintext No limit Returns only the encrypted copy — for deferred use
ReEncrypt 4 KB Decrypt then re-encrypt under a different CMK — key material never leaves KMS

Critical: The Encrypt API has a hard 4 KB limit. For anything larger — files, documents, database records — you must use Envelope Encryption via GenerateDataKey.

Envelope Encryption:

┌─────────────────────────────────────────────────────────────────────┐
│                    Envelope Encryption Flow                          │
│                                                                       │
│  ENCRYPTION:                                                          │
│  1. Call GenerateDataKey (CMK ARN)                                    │
│     → Returns: Plaintext DEK  +  Encrypted DEK                       │
│  2. Use Plaintext DEK to encrypt your large file locally (AES-256)   │
│  3. Immediately discard Plaintext DEK from memory                     │
│  4. Store: [ Encrypted File ] + [ Encrypted DEK ] together           │
│                                                                       │
│  DECRYPTION:                                                          │
│  1. Retrieve: [ Encrypted File ] + [ Encrypted DEK ]                  │
│  2. Call KMS Decrypt with the Encrypted DEK                           │
│     → Returns: Plaintext DEK                                          │
│  3. Use Plaintext DEK to decrypt the file locally                     │
│  4. Immediately discard Plaintext DEK from memory                     │
│                                                                       │
│  Key insight: The CMK never leaves KMS. Only the small Encrypted DEK │
│  travels with your data. KMS never sees your raw file content.        │
└─────────────────────────────────────────────────────────────────────┘

Exam Rule: Any question about encrypting data larger than 4 KB using KMS → the answer involves GenerateDataKey and Envelope Encryption.

3.3 Key Policies, Quotas & CloudHSM

Key Policies:

  • Every CMK must have a key policy. Without one, no one — not even the root account — can use the key.
  • The default key policy grants the root account full control, allowing IAM policies to then delegate access.
  • A custom key policy specifies exactly which principals can administer and use the key.
  • Cross-account KMS access requires: (1) key policy allows the other account, AND (2) IAM policy in the other account allows the action.

KMS Quotas (causes ThrottlingException):

Region Group Symmetric CMK Request Quota
us-east-1, us-west-2, eu-west-1 30,000 requests/second
Most other regions 5,500 – 10,000 requests/second

When throttled: implement exponential backoff. For S3 workloads using SSE-KMS at high volume, enable S3 Bucket Keys to reduce KMS API calls by approximately 99%.

KMS vs CloudHSM:

Feature AWS KMS AWS CloudHSM
Hardware tenancy Multi-tenant (shared hardware) Single-tenant (dedicated physical HSM)
Key control AWS manages the hardware and software You manage keys entirely
FIPS compliance FIPS 140-2 Level 3 FIPS 140-2 Level 3
AWS service integration Direct (native integration) Via KMS Custom Key Store
Cost $1/month per CMK ~$1.60/hour per HSM
Choose when Standard encryption needs Regulatory compliance mandating dedicated hardware, full key ownership

4. Amazon S3 Security

4.1 Access Control Layers

S3 has multiple overlapping access control mechanisms. Understanding how they interact — especially with Block Public Access — is critical for the exam.

Mechanism Scope Use Case
IAM Policies Attached to users, roles, groups Control which IAM principals can call which S3 APIs
Bucket Policies (resource-based) Bucket level Public access, cross-account access, enforce encryption
Object ACLs Individual object Fine-grained per-object control (can be disabled at bucket level)
Block Public Access Bucket or account level Override setting — blocks all public access regardless of bucket policy

Critical: Block Public Access settings override bucket policies. If Block Public Access is enabled on a bucket, a bucket policy granting public access has no effect.

Common Bucket Policy Patterns:

// Force HTTPS — deny all non-secure transport
{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:*",
  "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
  "Condition": { "Bool": { "aws:SecureTransport": "false" } }
}

// Force SSE-KMS encryption on all uploads
{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:PutObject",
  "Resource": "arn:aws:s3:::my-bucket/*",
  "Condition": {
    "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" }
  }
}

// Grant cross-account read access
{
  "Effect": "Allow",
  "Principal": { "AWS": "arn:aws:iam::ACCOUNT-B:root" },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}

4.2 S3 Encryption Methods

Method Key Managed By Header Key Requirement
SSE-S3 AWS (fully internal) x-amz-server-side-encryption: AES256 No audit trail of key usage
SSE-KMS AWS KMS (customer controls policy) x-amz-server-side-encryption: aws:kms CloudTrail logs every key use
SSE-C Customer (provided on every request) Key in request header HTTPS is mandatory
Client-side Customer (before data leaves app) None — data arrives already encrypted AWS never sees plaintext

Exam Rule: If the question requires an audit trail of who used which key and when → SSE-KMS.
If the question says the customer must own and manage the key entirely (not in KMS) → SSE-C (HTTPS mandatory) or Client-side encryption.

SSE-KMS at high volume:
Every SSE-KMS upload calls GenerateDataKey. Every download calls Decrypt. At tens of thousands of requests per second, this hits KMS rate limits. Solution: enable S3 Bucket Keys to generate a bucket-level data key that encrypts individual object keys locally — reduces KMS API calls by ~99%.

Critical: An S3 PutObject with SSE-KMS returns Access Denied when the uploading user or role lacks kms:GenerateDataKey permission on the CMK. The S3 permission alone is insufficient.

4.3 MFA Delete, Pre-signed URLs & CORS

MFA Delete:

  • Requires an MFA code to permanently delete an object version or suspend versioning.
  • Can only be enabled or disabled by the bucket owner using the root account credentials.
  • Versioning must be enabled before MFA Delete can be configured.

Pre-signed URLs:

Attribute Value
Console expiry Maximum 720 minutes (12 hours)
CLI expiry Maximum 604,800 seconds (7 days)
IAM role-signed Expires when the underlying STS token expires (may be less than 7 days)
Permissions Inherits the permissions of the signing IAM entity — not the bucket policy

CORS (Cross-Origin Resource Sharing):
Configured on the target bucket — the bucket that holds the assets being loaded by the browser from a different origin.

[{
  "AllowedOrigins": ["https://www.example.com"],
  "AllowedMethods": ["GET", "PUT"],
  "AllowedHeaders": ["*"],
  "MaxAgeSeconds": 3000
}]

Exam Trap: A 403 error on a cross-origin S3 request almost always means the CORS configuration is missing or incorrect on the target bucket — not an IAM permission issue.


5. Amazon Cognito Security

Cognito provides authentication and authorization for web and mobile applications. Its two components serve completely different purposes and are commonly confused on the exam.

5.1 User Pools vs Identity Pools

┌─────────────────────────────────────────────────────────────────────┐
│                    Cognito — Two Services                            │
│                                                                       │
│  COGNITO USER POOL (CUP)          COGNITO IDENTITY POOL (CIP)        │
│  ─────────────────────────        ──────────────────────────────     │
│  AuthN — Who are you?             AuthZ — What can you access?       │
│                                                                       │
│  Input:  Username + Password      Input:  A valid identity token     │
│          (or social/SAML token)           (from CUP, Google, SAML)  │
│                                                                       │
│  Output: JWT Tokens               Output: Temporary AWS credentials  │
│          • ID Token                        via STS AssumeRole        │
│          • Access Token                    (AccessKey + SecretKey    │
│          • Refresh Token                    + SessionToken)          │
│                                                                       │
│  Use for: Your APIs, ALB          Use for: S3, DynamoDB, Kinesis     │
│           API Gateway                      direct SDK calls          │
│                                                                       │
│  Guest access: No                 Guest access: Yes (unauthenticated)│
└─────────────────────────────────────────────────────────────────────┘

Critical Exam Rule: A JWT token from a User Pool grants access to your API (via API Gateway Cognito Authorizer). It does NOT grant access to AWS services like S3 or DynamoDB directly. To call AWS services directly from a mobile app, you need Identity Pools to exchange the JWT for temporary AWS credentials.

Cognito User Pools — Key Features:

  • Handles sign-up, sign-in, MFA, email/phone verification, and password reset.
  • Federates with: Facebook, Google, Amazon, Apple, SAML 2.0 IdPs, and OIDC providers.
  • MFA options: TOTP (authenticator apps) or SMS OTP.
  • Adaptive authentication: assigns a risk score to each sign-in attempt and can require MFA when risk is high.

Cognito Identity Pools:

  • Assigns each user a unique Identity ID regardless of which identity provider they used.
  • Two IAM roles: one for authenticated users, one for unauthenticated (guest) users.
  • Guest access: provide limited AWS access without any login required.

5.2 Fine-Grained Access & Lambda Triggers

Per-user resource isolation using IAM policy variables:

// Restrict each Cognito user to their own S3 folder
{
  "Effect": "Allow",
  "Action": ["s3:GetObject", "s3:PutObject"],
  "Resource": "arn:aws:s3:::my-bucket/${cognito-identity.amazonaws.com:sub}/*"
}

// Restrict each Cognito user to their own DynamoDB rows (LeadingKeys)
{
  "Effect": "Allow",
  "Action": ["dynamodb:GetItem", "dynamodb:PutItem"],
  "Resource": "arn:aws:dynamodb:us-east-1:*:table/UserData",
  "Condition": {
    "ForAllValues:StringEquals": {
      "dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
    }
  }
}

Lambda Triggers (User Pools):

Trigger When It Fires Common Use Case
Pre Sign-Up Before registration is confirmed Block unwanted email domains, auto-confirm certain users
Pre Authentication Before login is validated Add custom validation logic
Post Confirmation After email or phone is verified Send a welcome email, populate a user record
Pre Token Generation Before the JWT token is issued Add, modify, or suppress claims in the token
Migrate User On first login for a user not found in the pool Silently migrate users from a legacy authentication system

Critical: The Cognito Hosted UI custom domain requires an ACM certificate in us-east-1, regardless of the User Pool's region. This is a commonly tested trap.


6. API Gateway Security

6.1 Authorizer Types

API Gateway supports three authorizer mechanisms. Choosing the right one is a frequent exam scenario.

┌─────────────────────────────────────────────────────────────────────┐
│               API Gateway Authorizer Decision Tree                   │
│                                                                       │
│  Caller is an AWS service/EC2/Lambda using AWS credentials?          │
│  └──► YES: IAM Authorization + SigV4 signing                         │
│                                                                       │
│  Caller uses a 3rd-party JWT, OAuth, or custom token?                │
│  └──► YES: Lambda Authorizer (custom logic in your Lambda function)  │
│                                                                       │
│  Caller is a mobile/web app user authenticated via Cognito?          │
│  └──► YES: Cognito User Pool Authorizer (API GW validates JWT)       │
└─────────────────────────────────────────────────────────────────────┘
Authorizer How It Works Caching Cross-Account
IAM Caller signs request with SigV4. API GW verifies against IAM. N/A Yes — combine with resource policy
Lambda (Custom) Lambda receives token/headers, returns an IAM policy (Allow or Deny). Policy is cached by API GW. Yes — configurable TTL Yes
Cognito API GW validates Cognito JWT automatically. No Lambda needed. Yes — token validation cached No

Exam Trap: The Cognito Authorizer handles authentication only — confirming the user is who they claim to be. Authorization (what the user can do) must be enforced in your backend application code. API Gateway does not enforce method-level permissions based on Cognito user attributes.

6.2 Resource Policies & Usage Plans

Resource Policies:
JSON policies attached directly to an API Gateway REST API. Used to:

  • Restrict API access to specific AWS accounts.
  • Restrict access to specific source IP ranges or CIDR blocks.
  • Allow access only from specific VPCs or VPC Endpoints (for private APIs).

API Keys and Usage Plans:

Step-by-step setup (exam tests this order):

1. Create the API → configure methods to require an API key → deploy to a stage
2. Generate or import API keys
3. Create a Usage Plan (define throttle rate and monthly request quota)
4. Associate the API stage with the Usage Plan
5. Associate API Keys with the Usage Plan (via CreateUsagePlanKey API)

If step 5 is skipped → API key returns 403 Forbidden

Exam Trap: Creating an API key alone does nothing. The key must be associated with a Usage Plan via CreateUsagePlanKey. A newly created key returns 403 until this association is made.


7. Secrets Manager & SSM Parameter Store

Two services for storing secrets and configuration. Choosing between them is a common exam scenario.

Feature AWS Secrets Manager AWS SSM Parameter Store
Automatic rotation Yes — built-in for RDS, Aurora, Redshift, DocumentDB No — must build with Lambda + EventBridge
KMS encryption Mandatory — always encrypted Optional — use SecureString type for encrypted values
Cost $0.40/secret/month + $0.05 per 10K API calls Free tier available; Standard parameters are free
RDS native integration Yes — rotates credentials and updates the connection Manual
Cross-account access Yes — via resource-based policy Limited
Use when Database credentials, API keys needing automatic rotation Application config, non-rotating secrets, feature flags

SSM Parameter Store types:

# Store a plaintext value
aws ssm put-parameter --name "/myapp/config/db-host" --value "db.example.com" --type String

# Store an encrypted secret (KMS-encrypted)
aws ssm put-parameter --name "/myapp/secrets/db-password" --value "MySecureP@ss" --type SecureString

# Retrieve and decrypt a SecureString
aws ssm get-parameter --name "/myapp/secrets/db-password" --with-decryption

Reference in buildspec.yml (CodeBuild):

env:
  parameter-store:
    DB_PASSWORD: /myapp/secrets/db-password
  secrets-manager:
    API_KEY: arn:aws:secretsmanager:us-east-1:123:secret:my-api-key

Best Practice: Never store secrets as plaintext in env.variables in buildspec.yml. Always use parameter-store or secrets-manager sections.


8. Encryption at Rest & In Transit

Encryption at Rest — Service Summary

Service Default Encryption Customer CMK Support
S3 SSE-S3 (AES-256) Yes — SSE-KMS
EBS Not enabled by default Yes — set at volume creation
RDS Not enabled by default Yes — set at DB instance creation
DynamoDB AWS Owned keys Yes — Customer Managed CMK
Lambda env vars Lambda service key Yes — via KMSKeyArn in function config
Secrets Manager AWS Managed KMS key Yes — specify CMK at secret creation
CloudWatch Logs Not encrypted by default Yes — CLI only (associate-kms-key)
SQS Not encrypted by default Yes — SSE via CMK
Kinesis Not encrypted by default Yes — SSE via CMK

Critical: CloudWatch Logs KMS encryption cannot be configured from the AWS Management Console. You must use the AWS CLI command aws logs associate-kms-key for existing log groups, or specify the KMS key at creation time.

# Encrypt an existing CloudWatch Logs log group (CLI only)
aws logs associate-kms-key \
  --log-group-name /aws/lambda/my-function \
  --kms-key-id arn:aws:kms:us-east-1:123456789012:key/abc-123

Encryption in Transit

  • Force HTTPS on S3: Use a bucket policy that denies requests where aws:SecureTransport is false.
  • SSE-C requires HTTPS: The encryption key is included in the HTTP request header — using plain HTTP would expose the key in transit.
  • API Gateway: Always serves HTTPS. HTTP is not available.
  • CloudFront — Viewer Protocol Policy: Set to HTTPS Only or Redirect HTTP to HTTPS to enforce HTTPS between clients and CloudFront.
  • CloudFront — Origin Protocol Policy: Set to HTTPS Only to enforce HTTPS between CloudFront and the S3 or ALB origin.

9. Network Security

9.1 Security Groups vs NACLs

Feature Security Groups Network ACLs
State Stateful — return traffic is automatically allowed Stateless — return traffic must be explicitly allowed
Rules Allow rules only — cannot explicitly deny Allow and Deny rules
Scope EC2 instance / ENI level Subnet level — applies to all resources in the subnet
Rule evaluation All rules evaluated together Rules evaluated in order, lowest number first
Default behavior All inbound blocked; all outbound allowed All inbound and outbound allowed (default VPC NACL)
Changes take effect Immediately Immediately

Exam Rule: Connection Timeout when connecting to EC2 → Security Group is blocking the traffic. Connection Refused → traffic reached EC2 but the application is not running or listening on the expected port.

9.2 VPC Endpoints & AWS WAF

VPC Endpoints — two types:

Type Works With Cost Configuration
Gateway Endpoint S3 and DynamoDB only Free Added as a route table entry
Interface Endpoint Most other AWS services Hourly + data charge Creates an ENI in your subnet with a private IP

Use case: Lambda or ECS in a VPC needs to access S3 or DynamoDB without traversing the internet. Add a Gateway Endpoint — no NAT Gateway required. This is cheaper and more secure than routing through a NAT Gateway.

AWS WAF (Web Application Firewall):

  • Attach to: ALB, API Gateway REST API, CloudFront.
  • Protects against: SQL injection, XSS, HTTP floods, bad bots, geographic restrictions.
  • Rules match on: IP addresses, HTTP headers, URI strings, request body content.
  • Uses Web ACLs containing rules and rule groups.

VPC Flow Logs:

  • Capture metadata about network traffic flowing through ENIs, subnets, or VPCs.
  • Records include: source IP, destination IP, port, protocol, bytes transferred, accept/reject status.
  • Does NOT capture application-layer content — it is network metadata only.
  • Destination: CloudWatch Logs or S3.

10. AWS CloudTrail & Audit

10.1 Event Types & Retention

CloudTrail records all API calls made to your AWS account, regardless of whether the call came from the Console, CLI, SDK, or another AWS service.

Event Type Logged by Default Description
Management Events Yes Control plane operations: creating resources, attaching policies, modifying configurations
Data Events No (extra cost) Data plane operations: S3 GetObject/PutObject, Lambda Invoke, DynamoDB GetItem
Insights Events No (extra cost) Detects unusual patterns in management event activity

Retention:

  • CloudTrail stores events for 90 days in the CloudTrail console.
  • For longer retention: configure a Trail to deliver events to an S3 bucket, then analyze with Amazon Athena.

CloudTrail + EventBridge — Automated Response Pattern:

IAM user deletes a production DynamoDB table
  ──► CloudTrail records the DeleteTable API call
       ──► EventBridge rule matches on source: "aws.dynamodb" + action: "DeleteTable"
            ──► SNS topic sends alert to security team
            ──► Lambda function attempts automated remediation

10.2 CloudTrail vs CloudWatch vs X-Ray

Dimension CloudTrail CloudWatch AWS X-Ray
What it monitors AWS API calls and account activity Metrics, logs, alarms Distributed request traces
Primary question it answers Who did what to which resource and when? Is my application performing within thresholds? Where is the latency in my distributed system?
Used by Security and compliance teams Operations and development teams Developers debugging microservices
Example scenario "Who deleted the S3 bucket at 3 AM?" "CPU utilization is above 80% — trigger an alarm" "Why is the API response time 4 seconds?"
Retention 90 days (longer via S3 Trail) Configurable (depends on metric resolution) 30 days

11. Exam Tips & Quick Reference

Scenario-to-Answer Mapping

Scenario Keyword / Requirement Correct Answer
"Encrypt data larger than 4 KB using KMS" GenerateDataKey — envelope encryption
"S3 + SSE-KMS at high throughput hitting KMS limits" Enable S3 Bucket Keys (~99% fewer KMS calls)
"S3 PutObject Access Denied with SSE-KMS" Uploading principal needs kms:GenerateDataKey on the CMK
"KMS key needs annual rotation" Customer Managed CMK with automatic rotation enabled
"Imported KMS key rotation" Manual only — create new key, update alias to point to it
"Store DB password with automatic rotation" AWS Secrets Manager
"Store app config, no rotation needed" SSM Parameter Store
"Developer can't launch EC2 with an IAM role" Missing iam:PassRole permission
"Explicit Deny vs Allow in IAM" Explicit Deny always wins — no exceptions
"EC2 has environment variables AND Instance Profile" SDK uses environment variables (higher priority) — remove them
"Cross-account AWS resource access" IAM Role in target account + sts:AssumeRole from source account
"Decode an encoded Access Denied error" aws sts decode-authorization-message
"Determine current caller identity in CLI/SDK" aws sts get-caller-identity
"Mobile app users, social login, need AWS resource access" Cognito User Pools (authN) + Identity Pools (AWS credentials)
"Guest access to AWS resources without login" Cognito Identity Pool with unauthenticated identity role
"Per-user DynamoDB row isolation" IAM condition key: dynamodb:LeadingKeys = ${cognito-identity.amazonaws.com:sub}
"Restrict API to specific AWS account" API Gateway resource policy
"Prevent privilege escalation when delegating IAM" Permissions Boundary
"Audit all S3 object-level access" CloudTrail Data Events (not enabled by default)
"CloudWatch Logs encryption via KMS" CLI command aws logs associate-kms-key — not available in console
"Force HTTPS on S3 bucket" Bucket policy: Deny where aws:SecureTransport is false
"Find users with unused permissions" IAM Access Advisor
"Find users without MFA enabled" IAM Credentials Report
"Who deleted the resource?" CloudTrail Management Events
"New API key returns 403 Forbidden" Call CreateUsagePlanKey to associate the key with a usage plan

Common Traps

  • iam:PassRole is separate from service permissions: Having full EC2 or Lambda permissions does not include the ability to assign an IAM role to those services. iam:PassRole is a distinct permission that must be explicitly granted.
  • Cognito User Pools produce JWTs, not AWS credentials: A JWT from a User Pool lets you call your own API. To call AWS services directly (S3, DynamoDB), exchange the JWT for temporary credentials via a Cognito Identity Pool.
  • CloudWatch Logs KMS via CLI only: The AWS Management Console does not support associating a KMS key with a CloudWatch Logs log group. This must be done via the associate-kms-key CLI command.
  • SSE-C requires HTTPS: When using server-side encryption with a customer-provided key, the key is included in the request header. Using plain HTTP would expose the key in transit. HTTPS is mandatory.
  • S3 Bucket Key reduces CloudTrail events too: When S3 Bucket Keys are enabled, KMS generates one data key per bucket per time period instead of one per object. This reduces both KMS API calls and the number of CloudTrail log entries for KMS key usage.
  • Block Public Access overrides bucket policies: A bucket policy granting public access is irrelevant if Block Public Access is enabled. The Block Public Access setting wins.
  • Permissions Boundary does not grant permissions: A boundary defines the maximum possible permissions. An identity still needs an explicit Allow in their identity policy. Boundary alone = no access.

Key Terms — Domain 2

Term One-Line Definition
Explicit Deny An IAM statement with "Effect": "Deny" — always overrides any Allow
iam:PassRole Permission required to assign an IAM role to an AWS service
Permissions Boundary Managed policy that sets the maximum permissions an identity can have
Envelope Encryption Pattern where a data key (DEK) encrypts data and a master key (CMK) encrypts the DEK
SSE-KMS S3 server-side encryption using a KMS-managed key — provides CloudTrail audit trail
SSE-C S3 server-side encryption with a customer-provided key — HTTPS mandatory
Customer Managed CMK KMS key you create and control — supports key policies, rotation, and deletion
Credential Chain The ordered list of locations the AWS CLI and SDK check for credentials
Resource-based Policy Policy attached to an AWS resource (S3, SQS, Lambda) that includes a Principal
Cognito User Pool User directory that handles sign-up/sign-in and issues JWT tokens
Cognito Identity Pool Federates identities and issues temporary AWS credentials via STS
STS AssumeRole API call that exchanges identity for temporary credentials scoped to an IAM role
CloudTrail Data Events High-volume events (S3 object access, Lambda invocations) — not logged by default
VPC Gateway Endpoint Free VPC endpoint for S3 and DynamoDB — no NAT Gateway required
MFA Delete S3 versioning protection — requires root account MFA to permanently delete versions

End of Domain 2: Security. Continue to Domain 3: Deployment →

Ready to test yourself?

Practice questions for this topic

Start Practicing →

DVA-C02 Topics

Topic 2 of 4