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 — Deep Dive
  2. AWS STS — Temporary Credentials
  3. Amazon Cognito
  4. AWS KMS — Key Management Service
  5. AWS Secrets Manager
  6. AWS Systems Manager — Parameter Store
  7. S3 Encryption — All Options
  8. API Gateway Security
  9. Lambda Security
  10. AWS WAF — Web Application Firewall
  11. AWS ACM — Certificate Manager
  12. SigV4 — Request Signing
  13. Exam Tips & Quick Reference

1. AWS IAM — Deep Dive

IAM controls WHO (authentication) can do WHAT (authorization) on which AWS resources. Understanding IAM policy evaluation is the single most tested security concept across all AWS certification exams.

1.1 Principals, Identities & Policies

Principals — entities that can make requests to AWS:

Principal Description
IAM User Long-term credentials (access key + secret). One per human or service account
IAM Group Collection of users; policies attached to group apply to all members
IAM Role Temporary credentials; assumed by users, services, or applications
AWS Service EC2, Lambda, ECS — assume roles to call AWS APIs
Federated Identity External users authenticated via SAML 2.0, OIDC, or Web Identity

IAM Policy Types:

Policy Type Attached To Purpose
Identity-Based User, Group, Role Grants permissions to the principal
Resource-Based S3, SQS, KMS, Lambda, etc. Grants access FROM specific principals TO the resource
Permission Boundary User or Role Sets the maximum permissions an identity can have
SCP (Service Control Policy) AWS Organizations OU/Account Sets the maximum for the entire account
Session Policy STS AssumeRole call Restricts permissions within a temporary session
ACL (Access Control List) S3, VPC Legacy; controls cross-account access at the bucket/object level

1.2 IAM Policy Evaluation Logic

This is the most commonly tested concept in security questions. Understanding the order of evaluation is critical.

┌─────────────────────────────────────────────────────────────────────────────┐
│                        IAM Policy Evaluation Logic                           │
│                                                                               │
│  Request Comes In                                                             │
│       │                                                                       │
│       ▼                                                                       │
│  ┌──────────────────────┐                                                    │
│  │ 1. Explicit DENY?     │── YES ──► DENY (Explicit Deny always wins)        │
│  │   (any policy)        │                                                    │
│  └──────────┬───────────┘                                                    │
│             │ NO                                                              │
│             ▼                                                                 │
│  ┌──────────────────────┐                                                    │
│  │ 2. SCP in Org?        │── Doesn't allow ──► DENY                         │
│  └──────────┬───────────┘                                                    │
│             │ Allows                                                          │
│             ▼                                                                 │
│  ┌──────────────────────┐                                                    │
│  │ 3. Resource-Based     │── Allows (same account) ──► ALLOW                │
│  │    Policy?            │── Allows (cross-account) ──► Check identity policy│
│  └──────────┬───────────┘                                                    │
│             │ No resource-based policy                                        │
│             ▼                                                                 │
│  ┌──────────────────────┐                                                    │
│  │ 4. Permission         │── Does NOT allow ──► DENY                        │
│  │    Boundary?          │                                                    │
│  └──────────┬───────────┘                                                    │
│             │ Allows                                                          │
│             ▼                                                                 │
│  ┌──────────────────────┐                                                    │
│  │ 5. Session Policy?    │── Does NOT allow ──► DENY                        │
│  └──────────┬───────────┘                                                    │
│             │ Allows                                                          │
│             ▼                                                                 │
│  ┌──────────────────────┐                                                    │
│  │ 6. Identity-Based     │── Yes ──► ALLOW                                  │
│  │    Policy Allows?     │── No  ──► DENY (implicit deny)                   │
│  └──────────────────────┘                                                    │
└─────────────────────────────────────────────────────────────────────────────┘

The Golden Rules:

  1. Explicit DENY always overrides any ALLOW — in any policy.
  2. Default is DENY — without an explicit allow, access is denied.
  3. SCPs set the ceiling — an SCP cannot grant permissions, it can only restrict.
  4. Resource-Based Policy allows same-account access without needing identity-based policy.
  5. Cross-account access requires BOTH the resource-based policy (or role trust policy) AND the identity-based policy on the requesting account.

1.3 IAM Roles & Trust Policies

A role has two policies:

  1. Trust Policy — defines WHO can assume this role (the principal).
  2. Permissions Policy — defines WHAT the role can do (the actions/resources).
// Trust Policy — allows EC2 service to assume this role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
// Trust Policy — allows cross-account role assumption
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT-B-ID:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "UniqueExternalId123"
        }
      }
    }
  ]
}

ExternalId is used to prevent the Confused Deputy Problem — a scenario where an attacker tricks your trusted third-party service into accessing your resources using the third party's permissions.

1.4 Resource-Based Policies vs Identity-Based Policies

Dimension Identity-Based Policy Resource-Based Policy
Attached to IAM User, Group, Role Resource (S3, SQS, KMS, Lambda, etc.)
Specifies Principal No (the principal is implied by attachment) Yes (explicitly names WHO can access)
Cross-account Must be combined with resource-based policy Can grant access on its own (same account or cross-account)
Services that support it All S3, SQS, SNS, KMS, Lambda, API Gateway, Secrets Manager, ECR, and others

Critical Cross-Account Rule: To allow Account A to access an S3 bucket in Account B:

  • Account B bucket policy must allow Account A's principal.
  • Account A identity-based policy must allow the S3 action.
    Both must allow. One allow is not enough for cross-account.

1.5 IAM Policy Conditions & Permission Boundaries

Policy Conditions add fine-grained control:

Condition Key Example Use
aws:RequestedRegion Restrict actions to specific regions
aws:PrincipalTag Control based on IAM tags on the principal
aws:ResourceTag Control based on tags on the resource
aws:SecureTransport Require HTTPS (TLS) for S3 requests
aws:MultiFactorAuthPresent Require MFA for sensitive operations
s3:prefix Restrict S3 access to a specific key prefix
iam:PassedToService Control which services a role can be passed to
// Deny all S3 actions unless request uses TLS
{
  "Effect": "Deny",
  "Action": "s3:*",
  "Resource": "*",
  "Condition": {
    "Bool": {
      "aws:SecureTransport": "false"
    }
  }
}

Permission Boundaries:
A permission boundary is an identity-based policy that sets the maximum permissions a user or role can have. It does NOT grant permissions on its own — it only restricts the effective permissions.

Effective Permissions = Identity Policy ∩ Permission Boundary

Example:
Identity Policy: Allow S3:*, EC2:*, DynamoDB:*
Permission Boundary: Allow S3:*, EC2:*
Effective: Allow S3:*, EC2:*   (DynamoDB removed by boundary)

Exam Tip: Permission boundaries are commonly used to allow developers to create IAM roles for Lambda functions without being able to grant themselves permissions beyond what they have. A developer can only grant a role permissions that fall within their own permission boundary.


2. AWS STS — Temporary Credentials

AWS Security Token Service (STS) issues temporary, limited-privilege credentials. These consist of: Access Key ID, Secret Access Key, and a Session Token. Temporary credentials expire automatically.

2.1 AssumeRole, AssumeRoleWithWebIdentity & AssumeRoleWithSAML

STS Action Use Case Who Calls It
AssumeRole Cross-account access; EC2/Lambda service roles IAM users, roles, AWS services
AssumeRoleWithWebIdentity Mobile/web app users authenticated by OIDC providers (Google, Facebook, Apple, Cognito) Application using ID token
AssumeRoleWithSAML Corporate users authenticated by SAML 2.0 IdP (Okta, ADFS) SAML assertion from IdP
GetSessionToken MFA-protected API calls; already-authenticated IAM users IAM users needing MFA temp creds
GetFederationToken Broker-based federation (older pattern) IAM users creating federation tokens

AssumeRoleWithWebIdentity Flow (Modern Apps):

1. User authenticates with Google/Facebook → receives ID Token (JWT)
2. App calls STS:AssumeRoleWithWebIdentity(roleArn, webIdentityToken)
3. STS validates token with the OIDC provider
4. STS returns temporary credentials (AccessKey, SecretKey, SessionToken)
5. App uses temporary credentials to call AWS services directly

Note: AWS now recommends using Cognito Identity Pools instead of calling
      AssumeRoleWithWebIdentity directly in mobile/web apps.

2.2 Session Policies & Credential Duration

Session Policies are passed inline during AssumeRole to further restrict permissions within the session. They cannot expand permissions beyond the role's permissions policy.

# AssumeRole with an inline session policy (further restrict access)
response = sts_client.assume_role(
    RoleArn='arn:aws:iam::123456789:role/MyRole',
    RoleSessionName='my-session',
    DurationSeconds=3600,
    Policy=json.dumps({
        "Version": "2012-10-17",
        "Statement": [{
            "Effect": "Allow",
            "Action": ["s3:GetObject"],
            "Resource": "arn:aws:s3:::my-bucket/*"
        }]
    })
)
credentials = response['Credentials']
Duration Setting Range Default
AssumeRole 900s – 43200s (1 hour – 12 hours) 1 hour
AssumeRoleWithWebIdentity 900s – 43200s 1 hour
GetSessionToken 900s – 129600s (up to 36 hours) 12 hours

3. Amazon Cognito

Cognito is AWS's fully managed authentication, authorization, and user management service for web and mobile applications.

3.1 User Pools

A User Pool is a user directory that provides sign-up, sign-in, and profile management. It issues JWT tokens (ID token, access token, refresh token).

┌────────────────────────────────────────────────────────────────────┐
│                      Cognito User Pool                              │
│                                                                      │
│  ┌───────────┐   Sign-up/Sign-in    ┌───────────────────────────┐  │
│  │  User     │─────────────────────►│  User Pool                │  │
│  │  (Browser/│                       │                           │  │
│  │  Mobile)  │◄─────────────────────│  Issues JWT Tokens:       │  │
│  └───────────┘   Returns tokens      │  • ID Token (user info)   │  │
│                                      │  • Access Token (scopes)  │  │
│  Federated IdPs:                     │  • Refresh Token          │  │
│  • Google, Facebook, Apple           └───────────────────────────┘  │
│  • SAML 2.0 (Okta, ADFS)                                            │
│  • OIDC providers                                                    │
└────────────────────────────────────────────────────────────────────┘

Key User Pool Features:

Feature Description
MFA SMS-based or TOTP (time-based one-time password)
Lambda Triggers Pre/Post authentication, pre/post sign-up, token generation, custom messages
Hosted UI Pre-built, customizable sign-in page
App Clients Each app that accesses the user pool needs an app client
User Groups Assign users to groups; groups can map to IAM roles
Password Policy Configure minimum length, complexity, expiry

Cognito Lambda Triggers (commonly tested):

Trigger When It Fires Use Case
Pre Sign-up Before a new user is saved Validate email domain, auto-confirm users
Post Confirmation After user confirms Add user to database
Pre Authentication Before every sign-in Block sign-in based on custom logic
Post Authentication After successful sign-in Log sign-in events
Pre Token Generation Before JWT issued Add/modify/suppress claims in the token
Custom Message Before sending SMS/email Customize verification messages
Migrate User If user not found in pool Migrate users from legacy system on first login

3.2 Identity Pools (Federated Identities)

An Identity Pool provides temporary AWS credentials to authenticated or unauthenticated (guest) users, enabling direct access to AWS services.

┌────────────────────────────────────────────────────────────────────────┐
│                      Cognito Identity Pool Flow                         │
│                                                                          │
│  1. User authenticates with:                                            │
│     • Cognito User Pool                                                  │
│     • Google / Facebook / Apple (OIDC)                                  │
│     • SAML IdP                                                           │
│     • Custom Developer Authenticated Identity                            │
│                                                                          │
│  2. App sends token to Cognito Identity Pool                            │
│                                                                          │
│  3. Identity Pool calls STS:AssumeRoleWithWebIdentity                   │
│                                                                          │
│  4. STS returns temporary AWS credentials                               │
│     (AccessKey + SecretKey + SessionToken)                               │
│                                                                          │
│  5. App uses credentials to access S3, DynamoDB, API Gateway, etc.     │
└────────────────────────────────────────────────────────────────────────┘

Authenticated vs Unauthenticated (Guest) Roles:

  • Authenticated role: Assigned to verified users. Broader permissions.
  • Unauthenticated role: Assigned to anonymous (guest) users. Minimal permissions. Can be disabled.

Key Concept: Cognito User Pools = Authentication (who you are). Identity Pools = Authorization (what AWS resources you can access). They are separate services that work together.

3.3 User Pool + Identity Pool Combined Flow

This is the most common real-world pattern and the most frequently tested combined flow:

Mobile App
    │
    │ 1. Sign in
    ▼
Cognito User Pool ──► Returns ID Token (JWT)
    │
    │ 2. Exchange ID Token
    ▼
Cognito Identity Pool ──► Calls STS ──► Returns AWS Temp Credentials
    │
    │ 3. Use credentials
    ▼
AWS Services (S3, DynamoDB, API Gateway)

User Pool Groups → Identity Pool IAM Role Mapping:
Assign users to User Pool Groups. Map each group to a specific IAM Role in the Identity Pool. Users in the "Admin" group get the AdminRole; users in the "Users" group get the UserRole.

3.4 Cognito Sync & AppSync

Service Purpose
Cognito Sync Deprecated. Synchronize user profile data across devices.
AWS AppSync Recommended replacement. Managed GraphQL API with real-time subscriptions and Cognito integration.

4. AWS KMS — Key Management Service

KMS is a managed service for creating and controlling cryptographic keys. All KMS operations are logged in CloudTrail — every Encrypt, Decrypt, GenerateDataKey call is auditable.

4.1 Key Types

┌─────────────────────────────────────────────────────────────────────┐
│                         KMS Key Types                                │
│                                                                       │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐  │
│  │ AWS Managed Key  │  │ Customer Managed│  │   AWS Owned Key     │  │
│  │ (aws/s3, aws/rds)│  │ Key (CMK)       │  │ (SSE-S3 default)   │  │
│  ├─────────────────┤  ├─────────────────┤  ├─────────────────────┤  │
│  │ Free             │  │ $1/month        │  │ Free, no visibility │  │
│  │ No key policy    │  │ Full key policy │  │ Fully managed by AWS│  │
│  │ control          │  │ control         │  │                     │  │
│  │ Rotated: yearly  │  │ Rotated: yearly │  │ Rotated by AWS      │  │
│  │ (auto, mandatory)│  │ (opt-in auto or │  │                     │  │
│  │                  │  │ manual)         │  │                     │  │
│  └─────────────────┘  └─────────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

Key Material Origin:

Origin Description
KMS (default) AWS generates and manages key material in HSMs
External (BYOK) You import your own key material. You manage rotation manually
Custom Key Store (CloudHSM) Key material stored in your dedicated HSM cluster

Key Policies: Every KMS key has exactly one key policy. Without a key policy statement explicitly allowing the AWS account, no one can use the key — even the account root user. This is unlike IAM policies.

Critical: The default KMS key policy allows the AWS account root to administer the key, which then allows IAM policies to control KMS access. If you create a CMK and DON'T add "Principal": {"AWS": "arn:aws:iam::ACCOUNT_ID:root"} to the key policy, even the root user cannot use the key.

4.2 Envelope Encryption

KMS has a 4 KB limit per encrypt/decrypt call. For encrypting large data, AWS uses Envelope Encryption:

┌─────────────────────────────────────────────────────────────────────────┐
│                       Envelope Encryption Flow                           │
│                                                                           │
│  ENCRYPT:                                                                 │
│  1. Call KMS GenerateDataKey → returns plaintext DEK + encrypted DEK    │
│  2. Use PLAINTEXT DEK to encrypt your data locally (AES-256-GCM)        │
│  3. Store ENCRYPTED DEK alongside the encrypted data                     │
│  4. Immediately discard the plaintext DEK from memory                   │
│                                                                           │
│  DECRYPT:                                                                 │
│  1. Read encrypted DEK from storage                                      │
│  2. Call KMS Decrypt(encryptedDEK) → returns plaintext DEK              │
│  3. Use plaintext DEK to decrypt your data locally                      │
│  4. Discard plaintext DEK                                                │
│                                                                           │
│  Result: KMS never sees your data. Only the DEK is managed by KMS.      │
│  KMS CMK ──encrypts──► DEK ──encrypts──► Your Data                      │
└─────────────────────────────────────────────────────────────────────────┘

KMS API Operations:

API Description Key Distinction
Encrypt Encrypt up to 4 KB of plaintext using CMK Direct encryption, no DEK
Decrypt Decrypt ciphertext using CMK KMS determines the key from ciphertext
GenerateDataKey Returns both plaintext and encrypted DEK Envelope encryption start
GenerateDataKeyWithoutPlaintext Returns only encrypted DEK Defer decryption to later
ReEncrypt Decrypt then re-encrypt with a different key without exposing plaintext Key rotation
DescribeKey Get key metadata
CreateKey Create a new CMK

Exam Tip: GenerateDataKeyWithoutPlaintext is used when you want to generate and store the encrypted DEK now but do the actual encryption later (e.g., batch jobs that encrypt overnight).

4.3 KMS API & Key Policies

KMS Grants are an alternative to key policies for programmatic, temporary delegation of key use.

# Create a grant that allows a Lambda function to use a key
kms_client.create_grant(
    KeyId='arn:aws:kms:...',
    GranteePrincipal='arn:aws:iam::123456789:role/LambdaRole',
    Operations=['Decrypt', 'GenerateDataKey']
)

KMS Key Alias: Human-readable names for keys (alias/my-app-key). Can be updated to point to a different key — allowing key rotation without changing application code.

4.4 KMS Multi-Region Keys

Multi-Region Keys allow you to encrypt data in one region and decrypt it in another without re-encrypting.

Primary Key                    Replica Keys
us-east-1 ──(sync key material)──► eu-west-1
                                ──► ap-southeast-1

Same key ID prefix: mrk-... 
Encrypt in us-east-1, decrypt in eu-west-1 without calling KMS cross-region

Use Case: Global DynamoDB tables, Aurora Global Databases, S3 replication — any scenario where data is replicated cross-region and must be decryptable in the replica region.


5. AWS Secrets Manager

Secrets Manager stores, rotates, manages, and retrieves database credentials, API keys, and other secrets. It integrates with Lambda for automatic rotation.

5.1 Secret Rotation

Automatic rotation uses a Lambda rotation function that AWS provides for supported databases (RDS MySQL, PostgreSQL, Oracle, SQL Server, Redshift, DocumentDB).

Rotation Flow:
1. Secrets Manager triggers rotation Lambda (on schedule or on demand)
2. Lambda creates a new password (AWSPENDING version)
3. Lambda updates the database with the new password
4. Lambda tests the new credentials
5. Lambda updates the AWSCURRENT version to point to new creds
6. AWSPREVIOUS version retained for safety

Accessing Secrets in Code:

import boto3
import json

def get_secret():
    client = boto3.client('secretsmanager')
    response = client.get_secret_value(SecretId='prod/myapp/dbpassword')
    secret = json.loads(response['SecretString'])
    return secret['password']

# Best Practice: Cache the secret in memory; re-fetch only on auth failure
# Avoid calling GetSecretValue on every request

5.2 Secrets Manager vs SSM Parameter Store

Feature Secrets Manager SSM Parameter Store
Cost $0.40/secret/month + $0.05/10K API calls Free (Standard Tier); $0.05/10K API calls (Advanced)
Automatic Rotation Yes — built-in with Lambda No (requires custom Lambda)
Secret Versioning Yes (AWSCURRENT, AWSPENDING, AWSPREVIOUS) Yes
KMS Encryption Always (KMS mandatory) Optional (SecureString requires KMS)
Max Size 65 KB 4 KB (Standard), 8 KB (Advanced)
Cross-Account Yes (resource policy) No
Hierarchical Paths No Yes (/myapp/prod/dbpassword)
CloudFormation dynamic reference: {{resolve:secretsmanager:...}} {{resolve:ssm-secure:...}}
Best For Database passwords, API keys (needs rotation) App config, feature flags, non-sensitive config

Decision Rule: If it needs automatic rotation → Secrets Manager. If it's configuration (with or without encryption, no rotation) → SSM Parameter Store. Secrets Manager is more expensive but rotation is its key differentiator.


6. AWS Systems Manager — Parameter Store

Parameter Store provides secure, hierarchical storage for configuration data and secrets.

6.1 Parameter Tiers & Types

Parameter Type Encrypted Use Case
String No Non-sensitive config (region, table names)
StringList No Comma-separated values
SecureString Yes (KMS) Passwords, API keys
Tier Max Size Cost Policies
Standard 4 KB Free No
Advanced 8 KB $0.05/10K calls Yes (TTL, notification)

Hierarchical Parameters:

/myapp/dev/database/host
/myapp/dev/database/password
/myapp/prod/database/host
/myapp/prod/database/password

Retrieve all parameters for an environment in one call:

response = ssm_client.get_parameters_by_path(
    Path='/myapp/prod/',
    Recursive=True,
    WithDecryption=True  # Required for SecureString
)

CloudFormation Dynamic References:

# Reference SSM Parameter in CloudFormation template
MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Environment:
      Variables:
        DB_HOST: '{{resolve:ssm:/myapp/prod/database/host}}'
        DB_PASS: '{{resolve:ssm-secure:/myapp/prod/database/password}}'  # KMS decrypted

7. S3 Encryption — All Options

7.1 Server-Side Encryption (SSE)

Encryption is performed by S3 on the server side. Since November 2023, all new S3 objects are encrypted by default (SSE-S3).

┌─────────────────────────────────────────────────────────────────────────────┐
│                          S3 Server-Side Encryption Options                   │
│                                                                               │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────────┐                 │
│  │   SSE-S3       │  │   SSE-KMS      │  │   SSE-C        │                 │
│  │ (AES-256)      │  │ (KMS CMK)      │  │ (Customer Key) │                 │
│  ├────────────────┤  ├────────────────┤  ├────────────────┤                 │
│  │ • Default       │  │ • You control  │  │ • You provide  │                 │
│  │   since 2023    │  │   the key      │  │   key per req  │                 │
│  │ • No extra cost │  │ • Audit in     │  │ • AWS never    │                 │
│  │ • Header:       │  │   CloudTrail   │  │   stores key   │                 │
│  │   AES256        │  │ • Header:      │  │ • HTTPS only   │                 │
│  │                 │  │   aws:kms      │  │ • Not for CLI/ │                 │
│  │                 │  │ • KMS limits   │  │   console      │                 │
│  │                 │  │   apply        │  │                │                 │
│  └────────────────┘  └────────────────┘  └────────────────┘                 │
└─────────────────────────────────────────────────────────────────────────────┘
Option Header Key Managed By Key Stored By
SSE-S3 x-amz-server-side-encryption: AES256 AWS AWS
SSE-KMS x-amz-server-side-encryption: aws:kms You AWS (KMS)
SSE-C x-amz-server-side-encryption-customer-algorithm: AES256 + key You NOT stored (you send per request)

Critical SSE-KMS Consideration: Every PUT and GET on an SSE-KMS object calls KMS. For high-throughput S3 buckets, this can exhaust KMS API limits (10,000 requests/second default). Request a KMS quota increase if needed.

SSE-KMS with DSSE-KMS (Dual-Layer): Applies two layers of SSE-KMS encryption. Used for compliance requirements (e.g., CNSSI 1253). Each object has two different data keys.

7.2 Client-Side Encryption (CSE)

Data is encrypted before being uploaded to S3. AWS never sees plaintext.

CSE Method Key Source Use Case
CSE-KMS KMS CMK Use AWS SDK + KMS. AWS Encryption SDK handles envelope encryption.
CSE-Custom Your own key management Full key control; you manage everything

7.3 Bucket Policies to Enforce Encryption

Deny unencrypted uploads:

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

Deny non-TLS requests:

{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:*",
  "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
  "Condition": {
    "Bool": {
      "aws:SecureTransport": "false"
    }
  }
}

8. API Gateway Security

8.1 IAM Authorization (SigV4)

Use IAM authorization when the caller is an AWS service (EC2, Lambda, another service) or a trusted internal user with AWS credentials.

  • The caller signs the request with SigV4 using their IAM credentials.
  • API Gateway validates the signature and checks IAM permissions.
  • The IAM policy must allow execute-api:Invoke on the API's ARN.
  • Resource format: arn:aws:execute-api:REGION:ACCOUNT_ID:API_ID/STAGE/METHOD/RESOURCE
// IAM policy allowing API Gateway invocation
{
  "Effect": "Allow",
  "Action": "execute-api:Invoke",
  "Resource": "arn:aws:execute-api:us-east-1:123456789:abc123def/prod/GET/users"
}

8.2 Lambda Authorizer (Custom Authorizer)

A Lambda function that validates any bearer token (JWT, OAuth, custom) or request parameters before API Gateway forwards the request to the backend.

Two Types:

Type Validates Caching Key
Token-based Bearer token in Authorization header Token value
Request-based Headers, query params, path params, stage vars Combination of parameters
Client ──► API Gateway ──► Lambda Authorizer
                │               │
                │           (validate token)
                │               │
                │           Return IAM Policy
                │               │
                ◄───────────────┘
                │
           If Allow → forward to backend
           If Deny  → return 403

Authorizer Response — IAM Policy:

{
  "principalId": "user-001",
  "policyDocument": {
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:us-east-1:*:*/*/*/*"
    }]
  },
  "context": {
    "userId": "user-001",
    "role": "admin"
  }
}

Caching: Lambda Authorizer results are cached by default (TTL up to 3600 seconds). The cache key is the token value (for token-based) or the combination of parameters (for request-based). Setting TTL=0 disables caching.

8.3 Cognito User Pool Authorizer

API Gateway natively validates Cognito User Pool JWTs (access tokens or ID tokens). No Lambda function needed.

Client ──► Sign in to Cognito User Pool ──► Receives JWT
       ──► API Gateway (Authorization: Bearer <JWT>)
       ──► API Gateway validates JWT with Cognito
       ──► Forward to Lambda if valid

Comparison:

Authorizer Backend Needed Supports Use Case
IAM No (native) AWS internal callers Service-to-service
Lambda Yes (your Lambda) Any token/auth scheme Custom OAuth, API keys, complex logic
Cognito No (native) Cognito User Pool JWTs Mobile/web apps using Cognito

Exam Trap: Cognito User Pool Authorizer validates the token format and signature but does NOT check IAM permissions. Lambda Authorizer returns an IAM policy that is then evaluated. They work differently despite both being "authorizers."


9. Lambda Security

9.1 Execution Role & Resource-Based Policy

Execution Role: An IAM role that Lambda assumes when it runs. Grants Lambda permission to call other AWS services (write to DynamoDB, publish to SNS, write logs to CloudWatch). Every Lambda function must have an execution role.

// Minimum execution role trust policy (required)
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "lambda.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}
// Minimum permissions (allow CloudWatch Logs)
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents"
    ],
    "Resource": "arn:aws:logs:*:*:*"
  }]
}

Resource-Based Policy (Lambda): Controls which principals can invoke the function. When API Gateway, S3, SNS, or EventBridge triggers Lambda, AWS automatically adds a resource-based policy statement granting that service permission to invoke the function.

// Lambda resource-based policy: allow API Gateway to invoke
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "apigateway.amazonaws.com"},
    "Action": "lambda:InvokeFunction",
    "Resource": "arn:aws:lambda:us-east-1:123456789:function:MyFunction",
    "Condition": {
      "ArnLike": {
        "AWS:SourceArn": "arn:aws:execute-api:us-east-1:123456789:api-id/*"
      }
    }
  }]
}

9.2 Lambda in a VPC

By default, Lambda runs in an AWS-managed VPC with internet access. When you place Lambda in your VPC, it can access private resources (RDS, ElastiCache, private ALB) but loses direct internet access.

Lambda in VPC:
  ✅ Can access: RDS, ElastiCache, private EC2, private ALB
  ❌ Cannot access: Internet, AWS public endpoints (S3, DynamoDB, STS, etc.)

Solutions to restore access:
  • Internet access → NAT Gateway in a public subnet + Lambda in private subnet
  • AWS services → VPC Gateway Endpoints (S3, DynamoDB) or Interface Endpoints (VPC PrivateLink)

VPC Configuration Requirements:

  • Subnet(s) — must be private subnets for security.
  • Security Group — controls inbound/outbound from Lambda's ENI.
  • Lambda creates an Elastic Network Interface (ENI) in your subnet. ENI creation time was previously a cold start contributor, but AWS now pre-creates ENIs (Hyperplane ENIs), eliminating this overhead.

Classic Exam Scenario: "Lambda times out connecting to RDS." → Check: Lambda is in the same VPC? Lambda's security group allows outbound to RDS port? RDS security group allows inbound from Lambda's security group?


10. AWS WAF — Web Application Firewall

WAF protects web applications from common exploits (SQL injection, XSS, bot traffic). It works at Layer 7.

Can be attached to:

  • CloudFront distributions
  • Application Load Balancer (ALB)
  • API Gateway (REST API)
  • AWS AppSync
  • Cognito User Pool

WAF Components:

Component Description
Web ACL The container for rules. Attached to a CloudFront, ALB, or API GW.
Rule Group Reusable collection of rules
AWS Managed Rules Pre-built rule groups (OWASP Top 10, AWS IP Reputation List, Bot Control)
Rate-Based Rule Block IPs exceeding a request threshold (minimum: 100 req/5 min)
IP Set Allow or block specific IP addresses or CIDR ranges
Regex Pattern Set Match request components against regex patterns

Rule Actions:

Action Effect
Allow Forward the request
Block Return 403 Forbidden
Count Count the request (monitoring only, no block)
CAPTCHA Verify human with a challenge

Exam Tip: WAF rate-based rules are the correct answer for "block users who are making too many requests" (DDoS/brute force scenarios at Layer 7). For Layer 3/4 DDoS protection, AWS Shield is the answer.


11. AWS ACM — Certificate Manager

ACM provisions, manages, and deploys public SSL/TLS certificates for AWS services.

Feature Detail
Public certificates Free; auto-renewed by ACM
Private certificates ACM Private CA (paid)
Integration CloudFront, ALB, API Gateway, CloudWatch, Elastic Beanstalk
Import Import third-party certificates (you manage renewal)
Validation DNS validation (preferred, auto-renews) or Email validation

Critical Regional Constraint: For CloudFront, certificates must be in us-east-1 (N. Virginia), regardless of where your CloudFront distribution is deployed. For ALB or API Gateway, the certificate must be in the same region as the load balancer/API.


12. SigV4 — Request Signing

AWS Signature Version 4 (SigV4) is the process of signing HTTP requests to AWS services using your AWS credentials to prove authenticity.

Components of a SigV4 Signature:

Authorization: AWS4-HMAC-SHA256
Credential=ACCESS_KEY_ID/DATE/REGION/SERVICE/aws4_request,
SignedHeaders=content-type;host;x-amz-date,
Signature=CALCULATED_HMAC_SIGNATURE

Signing Flow:

1. Create Canonical Request
   (method + URI + query string + headers + hashed payload)

2. Create String to Sign
   (algorithm + datetime + credential scope + hash of canonical request)

3. Calculate Signature
   HMAC-SHA256(SigningKey, StringToSign)
   where SigningKey = HMAC(HMAC(HMAC(HMAC("AWS4"+SecretKey, Date), Region), Service), "aws4_request")

4. Add to Authorization header or as query string parameters (presigned URLs)

Where SigV4 is Used:

  • All AWS API calls (CLI, SDK automatically sign requests)
  • API Gateway with IAM Authorization
  • S3 pre-signed URLs
  • CloudFront Signed URLs/Cookies use their own mechanism (different from SigV4)

Exam Tip: If a question asks "how does a service prove its identity when calling another AWS service without storing credentials," the answer involves an IAM Role (the service assumes the role) with STS temporary credentials, and requests are signed with SigV4.


13. Exam Tips & Quick Reference

Scenario-to-Answer Mapping

Scenario Keyword / Requirement Correct Answer
"Auto-rotate database credentials" Secrets Manager with automatic rotation
"Store encrypted app config; no rotation needed" SSM Parameter Store (SecureString)
"Mobile users authenticate with Google, then access S3 directly" Cognito Identity Pool + AssumeRoleWithWebIdentity
"Add user directory, sign-up/sign-in, JWT tokens" Cognito User Pool
"Validate custom API token before API Gateway routes request" Lambda Authorizer
"Validate Cognito JWT in API Gateway natively" Cognito User Pool Authorizer
"Service-to-service API Gateway calls (EC2 → API GW)" IAM Authorization + SigV4
"Encrypt S3 objects with your own KMS key; audit access" SSE-KMS
"Encrypt S3 objects; AWS manages key entirely" SSE-S3
"Encrypt large data (>4 KB) with KMS" Envelope Encryption (GenerateDataKey)
"Share encrypted data across regions without re-encrypting" KMS Multi-Region Keys
"Block SQL injection attacks on API Gateway" AWS WAF
"Lambda cannot access RDS; connection timeout" Lambda in VPC; check SG rules
"Lambda needs internet AND access to private RDS" Lambda in private subnet + NAT Gateway
"Prevent a developer from granting themselves more than their permissions" IAM Permission Boundary
"Third-party service accessing your resources; prevent confused deputy" STS ExternalId in trust policy

Common Traps

  • Cognito User Pool vs Identity Pool: User Pool = authentication, JWT tokens. Identity Pool = AWS credentials for direct service access. They work together but serve different purposes.
  • SSE-KMS costs: Every GET/PUT on SSE-KMS objects calls KMS. High-throughput buckets can hit KMS throttle limits. Monitor NumberOfRequestsToKMS metric.
  • Lambda Authorizer caching: By default, API Gateway caches the IAM policy returned by the authorizer. A cached policy for a different resource or action could incorrectly grant or deny access. Set cache TTL=0 for sensitive endpoints where every request needs fresh validation.
  • Permission Boundary ≠ SCP: Permission Boundary applies to a specific user or role within an account. SCP applies to the entire AWS account (or OU). They both SET CEILINGS, not grant permissions.
  • KMS Key Policy is mandatory: Unlike IAM, a KMS key with no key policy is inaccessible to everyone. The default key policy must include the account root ARN.
  • Cross-account S3 access: Requires BOTH the S3 bucket policy in Account B allowing Account A AND an IAM policy in Account A allowing the S3 action. One alone is insufficient.

Key Terms — Domain 2

Term One-Line Definition
Principal The entity (user, role, service) making an API request
Explicit Deny A DENY statement that overrides any ALLOW — the highest-priority rule
Permission Boundary A policy that caps the maximum permissions a user or role can have
SCP (Service Control Policy) Organization-level policy setting the ceiling for entire AWS accounts
Envelope Encryption Encrypting a Data Encryption Key (DEK) with a master KMS key
DEK (Data Encryption Key) A symmetric key used to encrypt data; itself encrypted by a KMS CMK
CMK (Customer Master Key) A KMS key used to encrypt/decrypt Data Encryption Keys
JWT (JSON Web Token) A signed, base64-encoded token containing user claims; issued by Cognito User Pools
SigV4 AWS's request signing algorithm; proves request authenticity using HMAC-SHA256
Lambda Authorizer A Lambda function that validates tokens and returns an IAM policy for API Gateway
Trust Policy Defines who can assume an IAM role (the Principal for sts:AssumeRole)
ExternalId A secret value in a role trust policy to prevent the Confused Deputy problem
Pre-signed URL Time-limited S3 URL granting temporary access without AWS credentials
WAF Web ACL Web Application Firewall rule set attached to CloudFront, ALB, or API Gateway
Automatic Rotation Secrets Manager feature that automatically updates a secret using a Lambda function

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

Ready to test yourself?

Practice questions for this topic

Start Practicing →

DVA-C02 Topics

Topic 2 of 4