Domain 2: Security (26%)¶
Overview¶
This domain covers implementing authentication and authorization, encryption, and managing sensitive data in applications. Security is critical for the Developer Associate exam.
AWS Identity and Access Management (IAM)¶
π IAM User Guide - Complete guide to AWS identity and access management
IAM Core Concepts¶
IAM Roles for Applications¶
- EC2 Instance Roles: Attach IAM roles to EC2 instances
- Lambda Execution Roles: Grant Lambda functions permissions to AWS services
- ECS Task Roles: Permissions for containerized applications
- Cross-Account Roles: Access resources across AWS accounts
IAM Policy Types¶
// Identity-based policy (attached to users, groups, roles)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
// Resource-based policy (attached to resources like S3, SQS, Lambda)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccountAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
IAM Policy Evaluation Logic¶
- Explicit Deny: Always takes precedence
- Explicit Allow: Permits action if no deny exists
- Implicit Deny: Default deny if no explicit allow
- Policy Boundaries: Sets maximum permissions for IAM entity
π Policy Evaluation Logic - How AWS evaluates policies to authorize requests
AWS Security Token Service (STS)¶
π AWS STS API Reference - Temporary security credentials with STS
Temporary Credentials¶
import boto3
# Assume role
sts = boto3.client('sts')
response = sts.assume_role(
RoleArn='arn:aws:iam::123456789012:role/MyRole',
RoleSessionName='session-name',
DurationSeconds=3600
)
credentials = response['Credentials']
temp_session = boto3.Session(
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken']
)
# Use temporary credentials
s3 = temp_session.client('s3')
Common STS Operations¶
- AssumeRole: Cross-account or same-account role assumption
- AssumeRoleWithWebIdentity: For mobile/web apps with identity providers
- AssumeRoleWithSAML: For SAML-based federation
- GetFederationToken: For federated users
- GetSessionToken: For MFA-enabled users
IAM Best Practices for Developers¶
- Use IAM Roles: Never embed credentials in code
- Least Privilege: Grant minimum necessary permissions
- Temporary Credentials: Use STS for temporary access
- Policy Conditions: Use conditions for fine-grained control
- Rotate Credentials: Regular rotation of access keys
- Enable MFA: Multi-factor authentication for sensitive operations
Amazon Cognito¶
π Amazon Cognito Developer Guide - User authentication and authorization for web and mobile apps
Cognito User Pools¶
User Authentication¶
// AWS Amplify example for User Pool authentication
import { Auth } from 'aws-amplify';
// Sign up
await Auth.signUp({
username: 'user@example.com',
password: 'TempPassword123!',
attributes: {
email: 'user@example.com',
name: 'John Doe'
}
});
// Confirm sign up
await Auth.confirmSignUp('user@example.com', 'confirmation-code');
// Sign in
const user = await Auth.signIn('user@example.com', 'Password123!');
// Get current user
const currentUser = await Auth.currentAuthenticatedUser();
// Sign out
await Auth.signOut();
User Pool Features¶
- Sign-up and Sign-in: Email/username and password authentication
- MFA: SMS or TOTP-based multi-factor authentication
- Password Policies: Configurable password requirements
- Email/SMS Verification: Account verification workflows
- Custom Attributes: Additional user metadata
- Lambda Triggers: Pre/post authentication, token generation hooks
Cognito Identity Pools¶
π Amazon Cognito Identity Pools - Federated identities for AWS resource access
Federated Access to AWS¶
// Configure identity pool
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:12345678-1234-1234-1234-123456789012',
Logins: {
'cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123': idToken
}
});
// Get temporary AWS credentials
AWS.config.credentials.get((err) => {
if (!err) {
// Use AWS services with temporary credentials
const s3 = new AWS.S3();
s3.listBuckets((err, data) => {
console.log(data.Buckets);
});
}
});
Identity Pool Use Cases¶
- Guest Access: Unauthenticated user access to AWS resources
- Authenticated Access: Access after authentication via User Pool or external IdP
- Role-Based Access: Different IAM roles for authenticated/unauthenticated users
- Fine-Grained Access: Use identity ID in IAM policies for user-specific access
Cognito Integration Patterns¶
API Gateway + Cognito Authorizer¶
# API Gateway configuration
authorizers:
CognitoAuthorizer:
type: COGNITO_USER_POOLS
providerARNs:
- arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_ABC123
identitySource: method.request.header.Authorization
AWS Key Management Service (KMS)¶
π AWS KMS Developer Guide - Create and manage encryption keys
KMS Key Types¶
Customer Managed Keys (CMK)¶
- Full Control: Create, rotate, disable, delete keys
- Key Policies: Fine-grained access control
- Automatic Rotation: Annual key rotation (optional)
- CloudTrail Logging: All key usage logged
AWS Managed Keys¶
- Service-Specific: Created by AWS services (e.g., aws/s3, aws/rds)
- Limited Control: Cannot delete or modify key policies
- Automatic Rotation: Rotated every 3 years
KMS Operations¶
Encryption and Decryption¶
import boto3
import base64
kms = boto3.client('kms')
# Encrypt data
plaintext = 'Sensitive data'
response = kms.encrypt(
KeyId='arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
Plaintext=plaintext
)
ciphertext = base64.b64encode(response['CiphertextBlob']).decode()
# Decrypt data
response = kms.decrypt(
CiphertextBlob=base64.b64decode(ciphertext)
)
decrypted_plaintext = response['Plaintext'].decode()
# Generate data key (for envelope encryption)
response = kms.generate_data_key(
KeyId='alias/my-key',
KeySpec='AES_256'
)
plaintext_key = response['Plaintext']
encrypted_key = response['CiphertextBlob']
KMS Key Policies¶
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/MyAppRole"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*"
}
]
}
Envelope Encryption Pattern¶
π Envelope Encryption - Learn about envelope encryption with KMS
# 1. Generate data key
response = kms.generate_data_key(KeyId='alias/my-key', KeySpec='AES_256')
plaintext_key = response['Plaintext']
encrypted_key = response['CiphertextBlob']
# 2. Encrypt data with plaintext key
from cryptography.fernet import Fernet
cipher = Fernet(base64.urlsafe_b64encode(plaintext_key[:32]))
encrypted_data = cipher.encrypt(b'Large amount of data')
# 3. Store encrypted data + encrypted key
# 4. To decrypt: first decrypt the data key with KMS, then decrypt data
AWS Secrets Manager¶
π AWS Secrets Manager User Guide - Manage and rotate secrets throughout their lifecycle
Managing Application Secrets¶
Store and Retrieve Secrets¶
import boto3
import json
secrets_client = boto3.client('secretsmanager')
# Create secret
secrets_client.create_secret(
Name='prod/myapp/db-credentials',
Description='Database credentials for production',
SecretString=json.dumps({
'username': 'admin',
'password': 'SecurePassword123!',
'host': 'mydb.cluster-abc.us-east-1.rds.amazonaws.com',
'port': 3306
})
)
# Retrieve secret
response = secrets_client.get_secret_value(SecretId='prod/myapp/db-credentials')
secret_dict = json.loads(response['SecretString'])
# Update secret
secrets_client.update_secret(
SecretId='prod/myapp/db-credentials',
SecretString=json.dumps({'username': 'admin', 'password': 'NewPassword456!'})
)
# Rotate secret
secrets_client.rotate_secret(
SecretId='prod/myapp/db-credentials',
RotationLambdaARN='arn:aws:lambda:us-east-1:123456789012:function:RotateSecret',
RotationRules={'AutomaticallyAfterDays': 30}
)
Automatic Secret Rotation¶
- Lambda-based Rotation: Custom Lambda function for rotation logic
- Rotation Strategies: Single user vs alternating users
- RDS Integration: Built-in rotation for RDS credentials
- Versioning: Maintains secret versions during rotation
Secrets Manager vs Parameter Store¶
| Feature | Secrets Manager | Parameter Store |
|---|---|---|
| Purpose | Secrets rotation and lifecycle | Configuration and secrets |
| Cost | $0.40/secret/month + API calls | Free (Standard), $0.05/parameter (Advanced) |
| Rotation | Built-in automatic rotation | Manual rotation |
| Size Limit | 64 KB | 4 KB (Standard), 8 KB (Advanced) |
| Use Case | Database credentials, API keys | Application configuration, simple secrets |
AWS Systems Manager Parameter Store¶
π AWS Systems Manager Parameter Store - Secure storage for configuration data and secrets
Store Configuration Data¶
import boto3
ssm = boto3.client('ssm')
# Put parameter
ssm.put_parameter(
Name='/myapp/config/api-url',
Value='https://api.example.com',
Type='String',
Description='API endpoint URL',
Tier='Standard'
)
# Put secure parameter
ssm.put_parameter(
Name='/myapp/config/api-key',
Value='secret-api-key-12345',
Type='SecureString',
KeyId='alias/aws/ssm', # KMS key for encryption
Tier='Standard'
)
# Get parameter
response = ssm.get_parameter(Name='/myapp/config/api-url')
value = response['Parameter']['Value']
# Get parameter with decryption
response = ssm.get_parameter(Name='/myapp/config/api-key', WithDecryption=True)
api_key = response['Parameter']['Value']
# Get parameters by path
response = ssm.get_parameters_by_path(
Path='/myapp/config',
Recursive=True,
WithDecryption=True
)
AWS Certificate Manager (ACM)¶
π AWS Certificate Manager User Guide - Provision and manage SSL/TLS certificates
SSL/TLS Certificate Management¶
Request Certificate¶
# Request public certificate
aws acm request-certificate \
--domain-name example.com \
--subject-alternative-names www.example.com \
--validation-method DNS
# Import certificate
aws acm import-certificate \
--certificate fileb://certificate.pem \
--private-key fileb://private-key.pem \
--certificate-chain fileb://certificate-chain.pem
ACM Integration¶
- Load Balancers: ALB/NLB SSL termination
- CloudFront: HTTPS for CDN distributions
- API Gateway: Custom domain SSL/TLS
- Elastic Beanstalk: SSL for applications
- Automatic Renewal: ACM auto-renews public certificates
Application Security Best Practices¶
Secure Coding Practices¶
Input Validation¶
import re
from html import escape
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def sanitize_input(user_input):
# Escape HTML to prevent XSS
return escape(user_input)
def validate_sql_input(user_input):
# Use parameterized queries instead of string concatenation
# GOOD: cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# BAD: cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
pass
Secure Environment Variables¶
import os
# Load sensitive data from environment variables
DB_HOST = os.environ.get('DB_HOST')
DB_PASSWORD = os.environ.get('DB_PASSWORD')
API_KEY = os.environ.get('API_KEY')
# For Lambda, load from Secrets Manager
def get_db_credentials():
secret_name = os.environ['SECRET_NAME']
response = secrets_client.get_secret_value(SecretId=secret_name)
return json.loads(response['SecretString'])
Encryption Best Practices¶
π Data Protection in AWS - Best practices for encrypting data at rest and in transit
Data at Rest¶
- S3: Server-side encryption (SSE-S3, SSE-KMS, SSE-C)
- EBS: Encrypted volumes with KMS
- RDS: Encryption with KMS at creation time
- DynamoDB: Encryption at rest enabled by default
Data in Transit¶
- HTTPS: All API communication over TLS
- VPC Endpoints: Private connectivity to AWS services
- VPN: Encrypted connections to VPC
- TLS 1.2+: Use modern TLS versions
IAM Permission Boundaries¶
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"dynamodb:*",
"lambda:*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2"]
}
}
}
]
}
Common Security Scenarios¶
Scenario 1: Secure API with Cognito¶
Client β API Gateway (Cognito Authorizer) β Lambda β DynamoDB
- User authenticates with Cognito User Pool
- Receives JWT token
- Token validated by API Gateway
- Lambda accesses DynamoDB with IAM role
Scenario 2: Encrypt Sensitive Data¶
Application β KMS (generate data key) β Encrypt data β S3 (encrypted object)
- Generate data key from KMS
- Encrypt data with data key (envelope encryption)
- Store encrypted data and encrypted key
- Decrypt: retrieve encrypted key, decrypt with KMS, decrypt data
Scenario 3: Database Credential Rotation¶
Application β Secrets Manager β RDS
- Application retrieves credentials from Secrets Manager
- Lambda function rotates credentials automatically
- Application always uses current credentials
- Zero downtime rotation
Study Tips¶
- IAM Mastery: Understand policy evaluation, roles, and temporary credentials
- Cognito Deep Dive: Know User Pools vs Identity Pools use cases
- KMS Operations: Practice encryption, decryption, and envelope encryption
- Secrets Management: Compare Secrets Manager vs Parameter Store
- Certificate Management: Understand ACM integration with AWS services
- Security Best Practices: Always choose most secure option in exam scenarios
CLI Quick Reference¶
# IAM
aws iam create-role --role-name MyRole --assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy --role-name MyRole --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/MyRole --role-session-name session1
# KMS
aws kms create-key --description "My application key"
aws kms encrypt --key-id alias/my-key --plaintext "secret data"
aws kms decrypt --ciphertext-blob fileb://encrypted.dat
# Secrets Manager
aws secretsmanager create-secret --name MySecret --secret-string "MyPassword"
aws secretsmanager get-secret-value --secret-id MySecret
aws secretsmanager rotate-secret --secret-id MySecret
# Parameter Store
aws ssm put-parameter --name /myapp/db/password --value "password" --type SecureString
aws ssm get-parameter --name /myapp/db/password --with-decryption
aws ssm get-parameters-by-path --path /myapp --recursive