Security is 26% of scored content, in three tasks: authentication and authorization, encryption and sensitive data (merged into one task in DVA-C03), and a new task on the security risks of using AI services. The exam does not ask you to administer IAM users and groups. It asks how an application gets credentials, proves who a user is, encrypts data, and keeps secrets out of code. Most answers favour roles over keys, managed services over homemade code, and the least privilege that still works.
IAM policies and permissions
Policy types
| Type | Attached to | Purpose |
|---|---|---|
| Identity-based (principal) | User, group, role | What this identity may do |
| Resource-based | The resource (S3 bucket, SQS queue, Lambda function, KMS key, SNS topic, secret) | Who may use this resource, including other accounts |
| Permissions boundary | User or role | A ceiling on what identity policies can grant |
| Service control policy (SCP) | Organization, OU or account | A ceiling for the whole account. Grants nothing by itself |
| Session policy | Passed on AssumeRole/federation |
Narrows one session further |
| Trust policy | A role | Who may assume the role (a resource-based policy on the role) |
| Endpoint policy | VPC endpoint | What can pass through that endpoint |
AWS managed policies are maintained by AWS and cover common jobs (AmazonS3ReadOnlyAccess). They can be broader than you need. Customer managed policies are yours: reusable across identities, versioned, and tailored to least privilege. Inline policies are embedded in one identity and are deleted with it. Prefer customer managed for reuse, and managed policies are not the answer when a question demands exact permissions.
Evaluation logic
- Everything is implicitly denied by default.
- An explicit deny anywhere always wins.
- Otherwise an explicit allow is needed. Boundaries and SCPs must also allow the action.
- Same account: an allow in either the identity policy or the resource policy is enough (except for services like KMS that require the key policy to permit).
- Cross account: both sides must allow. The caller’s identity policy and the resource’s policy.
Policy elements: Effect, Principal (resource policies only), Action, Resource, and Condition (for example aws:SourceIp, aws:SecureTransport, aws:PrincipalOrgID, aws:MultiFactorAuthPresent, s3:prefix). Wildcards work in actions and ARNs. NotAction and NotResource invert matching and are easy to get wrong.
Least privilege: grant only the actions on only the resources needed, start narrow, and tighten with IAM Access Analyzer (generates a policy from CloudTrail activity and finds unintended external access). ABAC (attribute-based) matches tags on the principal and the resource, so one policy scales across projects. RBAC assigns permissions by job role through groups and roles.
ACLs: S3 bucket and object ACLs are legacy. New buckets disable them (Object Ownership: bucket owner enforced). Use policies. In application code, “ACL authorization” often means your own per-resource list of who may do what. A DynamoDB table of permissions or Cognito groups serves that role.
Roles and credentials
- An IAM role has no long-lived keys. A caller assumes it through AWS STS and receives temporary credentials (access key, secret key, session token).
- Compute gets its role automatically: Lambda execution role, EC2 instance profile, ECS task role (different from the ECS task execution role, which pulls images and writes logs), EKS service accounts (IRSA or Pod Identity), CodeBuild service role.
- Never put access keys in code, AMIs, containers or repos. Locally, use named profiles and IAM Identity Center (SSO) for short-lived credentials.
- Lambda also needs a resource-based policy (
lambda:InvokeFunctionfor the principal) when another service or account invokes it. The console adds this for triggers you configure there. With IaC you addAWS::Lambda::Permission.
STS API calls
| Call | Use |
|---|---|
AssumeRole |
Take a role in your or another account. Duration 15 minutes to 12 hours (default 1 hour, but role chaining caps at 1 hour). Optional external ID protects against the confused-deputy problem with third parties, and MFA can be required |
AssumeRoleWithSAML |
Enterprise SAML 2.0 identity (for example Entra ID, ADFS) gets AWS credentials |
AssumeRoleWithWebIdentity |
OIDC tokens (Google, Facebook, Cognito, GitHub, Kubernetes service accounts). Called without AWS credentials |
GetSessionToken |
MFA-protected temporary credentials for an IAM user |
GetCallerIdentity |
Who am I? Needs no permission |
DecodeAuthorizationMessage |
Decode the encoded text of an UnauthorizedOperation error to see why access was denied (needs sts:DecodeAuthorizationMessage) |
Programmatic access: temporary credentials in the SDK come from the credential chain, and AssumeRole profiles in the shared config file give you cross-account access (role_arn, source_profile). A call signs requests with Signature Version 4 using the credentials. The SDK does it for you. Calls from outside AWS to an API Gateway endpoint with IAM authorization are signed the same way.
Federation and identity
Identity federation lets users from an outside identity provider (IdP) access AWS or your app without a new IAM user per person.
| Protocol | Notes |
|---|---|
| SAML 2.0 | XML assertions. Common for workforce SSO. Use IAM SAML provider or IAM Identity Center |
| OpenID Connect (OIDC) | Identity layer on OAuth 2.0 that returns an ID token (a JWT). Social and modern IdPs |
| OAuth 2.0 | Delegated authorization with access tokens (what an app may do on a user’s behalf) |
Bearer tokens such as JWTs are sent in the Authorization header, and whoever holds the token can use it, so send them only over HTTPS and keep them short-lived. A JWT has three Base64URL parts (header, payload of claims, signature). Validate signature, issuer (iss), audience (aud or client_id), expiry (exp) and token use before trusting claims. The payload is encoded, not encrypted, so do not put secrets in it.
Amazon Cognito
| User pool | Identity pool | |
|---|---|---|
| Answers | Who are you? (authentication) | What AWS resources can you use? (authorization) |
| Provides | Sign-up, sign-in, MFA, password policy, user directory, hosted UI, federation with social/SAML/OIDC, JWT tokens | Temporary AWS credentials through STS, mapped to IAM roles |
| Output | ID token, access token, refresh token | AWS access key, secret and session token |
| Use for | Logging users in to your app or API | Letting a mobile app call S3 or DynamoDB directly, including guests (unauthenticated role) |
- Typical flow: user signs in to a user pool, gets a JWT, then exchanges it with an identity pool for AWS credentials. Identity pools also accept social, SAML, OIDC and developer-authenticated identities directly.
- Token lifetimes: ID and access tokens 5 minutes to 1 day (default 1 hour), refresh token default 30 days. The access token authorizes API calls and is used for
GetUser. The ID token carries user attributes (claims). Use the refresh token to get new tokens. - API Gateway with Cognito: a REST API Cognito user pool authorizer validates the JWT for you with no code. HTTP APIs use a JWT authorizer. Both can check OAuth scopes.
- Identity pool roles use
cognito-identity.amazonaws.com:subin a policy condition to give each user their own S3 prefix or DynamoDB rows (dynamodb:LeadingKeys). - Triggers (Lambda): pre sign-up, post confirmation, pre token generation (add or change claims), custom auth. App clients with a secret are for server-side apps. Public mobile and browser apps use no secret and PKCE.
- Cognito Sync is legacy. AppSync and Amplify handle offline sync now.
API authorizers
| Option | Use when |
|---|---|
| IAM authorization (SigV4) | Callers already have AWS credentials (services, internal apps) |
| Cognito user pool authorizer | Users sign in with Cognito |
| Lambda authorizer (token or request type) | Custom or third-party tokens, or logic like header and query checks. Returns an IAM policy, and results can be cached by token (TTL default 300 s). If permissions change, cached policy still applies until it expires |
| API key | Identification and throttling per client. Not security |
| Resource policy / WAF / mTLS | Restrict by IP, VPC or account, block attacks, require client certificates |
Encryption
Concepts
- In transit: TLS (HTTPS). Enforce with an S3 bucket policy condition on
aws:SecureTransport, ALB/CloudFront HTTPS listeners, and TLS to databases. - At rest: data on disk is encrypted, usually with KMS keys.
- Server-side encryption (SSE): the service encrypts after receiving and decrypts for you. Client-side encryption: your code encrypts before sending, so AWS never sees plaintext or the key (use the AWS Encryption SDK or the S3/DynamoDB encryption clients).
- Envelope encryption: a data key encrypts the data, and a KMS key encrypts the data key. KMS
Encrypthandles only 4 KB, so for anything larger you callGenerateDataKey, encrypt locally with the plaintext key, discard the plaintext key, and store the encrypted key with the data. To decrypt, callDecrypton the encrypted data key.
AWS KMS
| Key type | Who controls | Cost and rotation |
|---|---|---|
| AWS owned | AWS, shared across accounts, invisible | Free, no control |
AWS managed (aws/s3, aws/dynamodb, aws/lambda) |
AWS creates in your account, you cannot edit the key policy | Free to hold, automatic rotation every year (cannot change) |
| Customer managed | You: key policy, grants, enable/disable, delete | Monthly fee. Optional automatic rotation (default every year, configurable 90 days to 7 years) or manual rotation with a new key and alias |
- Symmetric keys (AES-256-GCM) never leave KMS. Asymmetric keys (RSA, ECC) support sign/verify and encrypt with a public key you can export. HMAC keys are also available. Multi-Region keys share key material across Regions.
- Key policy is the root of all KMS access. If it does not permit the account, IAM policies alone cannot grant access. The default key policy delegates to IAM. Grants give temporary, narrow permission to a service or principal (used by EBS, RDS and others).
- Cross-account: the key policy must allow the other account, and the other account’s identity policy must allow the KMS actions. An AWS managed key cannot be shared across accounts, so use a customer managed key when sharing encrypted snapshots, S3 objects or secrets.
- Rotation: automatic rotation keeps the key ID, ARN and old key material, so existing ciphertext still decrypts. Enable or disable it per key (
EnableKeyRotation,DisableKeyRotation). Imported key material cannot rotate automatically. - Deletion is scheduled with a 7 to 30 day waiting period (default 30) and the key is disabled during it. Use disable to test the impact first. Deleted keys make data unrecoverable.
- Aliases (
alias/app-key) are friendly names. Moving an alias to a new key is how manual rotation stays transparent. - Encryption context: extra key-value pairs, not secret, that must match on decrypt. They bind ciphertext to its purpose and appear in CloudTrail.
- Limits: KMS has request quotas per Region. Heavy
GenerateDataKey/Decrypttraffic can throttle (ThrottlingException). Use data key caching in the Encryption SDK, S3 bucket keys, and backoff. - Every KMS call is logged in CloudTrail. Services need
kms:GenerateDataKeyandkms:Decrypton the key to read and write encrypted data. A missing KMS permission is a classic cause ofAccessDeniedon S3, SQS, SNS or Lambda that otherwise looks permitted.
S3 encryption options
| Option | Keys |
|---|---|
| SSE-S3 | S3 manages keys (AES-256). Default for all new objects |
| SSE-KMS | KMS key, audit trail, per-key control. Adds KMS request cost and quota. Use bucket keys |
| DSSE-KMS | Two layers of encryption with KMS keys |
| SSE-C | You provide the key on every request over HTTPS. AWS does not store it |
| Client-side | You encrypt before upload |
Enforce encryption with a bucket policy denying PutObject without the right x-amz-server-side-encryption header (S3 now encrypts by default, so this matters mostly to require KMS).
Other services
- DynamoDB encrypts all tables at rest (owned, managed or customer managed key). SQS and SNS support SSE with KMS (producers and consumers need KMS permissions, and for SNS-to-SQS delivery the key policy must allow the SNS service). EBS/RDS encryption is chosen at creation, and you copy to a new encrypted volume or snapshot to encrypt later. Lambda environment variables are encrypted at rest with a KMS key. CloudWatch Logs can use a KMS key per log group.
Certificates
- AWS Certificate Manager (ACM) issues and auto-renews public TLS certificates for ALB, CloudFront, API Gateway and similar. Certificates cannot be exported from ACM for installation on your own EC2 server. A certificate for CloudFront must be in us-east-1. For an API Gateway edge-optimized custom domain also us-east-1, and for a Regional one, the same Region. Validation is by DNS (preferred, enables auto renewal) or email.
- AWS Private CA issues private certificates for internal services, devices and mutual TLS. Pay per CA and per certificate.
- Development key pairs and certificates: EC2 key pairs (
create-key-pair, or import your own public key made withssh-keygen) for SSH. Self-signed certificates (openssl) are for local development and testing only. Prefer Session Manager or EC2 Instance Connect over opening SSH.
Managing sensitive data in code
Data classification sorts data by sensitivity: public, internal, confidential, and regulated types such as PII (name, email, national ID) and PHI (health data, covered by HIPAA). Higher classes need encryption, strict access, minimal retention, and masked logs. Amazon Macie finds PII in S3. Amazon Comprehend can detect and redact PII in text.
Where to keep secrets
| Secrets Manager | SSM Parameter Store | |
|---|---|---|
| Purpose | Credentials and secrets | Configuration and secrets |
| Automatic rotation | Yes, built in with Lambda rotation functions (managed rotation for RDS, Aurora, Redshift, DocumentDB) | No built-in rotation |
| Cost | Per secret per month plus API calls | Free standard tier (4 KB), advanced tier paid (8 KB) |
| Encryption | Always KMS | String and StringList plain, SecureString uses KMS |
| Cross-account sharing | Yes, resource policy, needs a customer managed key | Advanced parameters only (shared through RAM) |
| Versioning | Staging labels AWSCURRENT, AWSPREVIOUS |
Versions and labels |
| Extra | Replicate to other Regions | Hierarchies (/app/prod/db/url), GetParametersByPath, change notifications |
Pick Secrets Manager when you need rotation, cross-Region replication or generated database credentials. Pick Parameter Store for plain config and cheap secrets with no rotation need. AppConfig (see deployment) is for feature flags and gradual configuration rollout.
- Code reads a secret at runtime with
GetSecretValueorGetParameter --with-decryption, then caches it (the Secrets Manager caching client, or the AWS Parameters and Secrets Lambda extension), refreshing after a TTL so rotation is picked up. The role needssecretsmanager:GetSecretValue(orssm:GetParameter) andkms:Decryptif a customer managed key is used. - Lambda environment variables are encrypted at rest by default. For sensitive values, use encryption helpers: encrypt the value with your own KMS key (client-side before storing), and decrypt it in code. Anyone with console access sees ordinary environment variables in plaintext unless the value is encrypted that way, so for real secrets prefer Secrets Manager or Parameter Store and pass only the secret’s name in the variable. CloudFormation can resolve secrets with dynamic references (
{{resolve:secretsmanager:...}},{{resolve:ssm-secure:...}}) so they never appear in templates. - CodeBuild reads secrets as
parameter-storeorsecrets-managerenvironment variables in the buildspec. Do not echo them or pass plaintext environment variables. - Secure credential handling: no secrets in source control (use git-secrets or CodeGuru Security scanning), no secrets in AMIs or container images, no secrets in logs, short-lived credentials, rotation, and least privilege.
- Sanitizing: validate and encode input (prevents injection), mask or tokenize PII before logging or storing, use parameterized queries, and redact sensitive fields in logs. CloudWatch Logs data protection policies can detect and mask sensitive data automatically.
Presigned URLs, signed URLs and MFA
- S3 presigned URL: a URL carrying a signature that grants one operation (GET or PUT) on one object for a limited time, with no AWS credentials on the caller’s side. Generate it in code with the SDK. Maximum lifetime is 7 days with IAM user keys, but it ends when the temporary credentials that signed it expire (a Lambda role or assumed role session may give minutes to hours). It carries the signer’s permissions, so the signer must be allowed the action, and the URL stops working if that permission is removed. For uploads, use a presigned PUT (or presigned POST with conditions on size and type).
- CloudFront signed URLs and signed cookies restrict access to content served from CloudFront. A signed URL protects one file (also for clients that can’t use cookies). Signed cookies protect many files with one sign-in (a whole site or video set). They use a key group with a public key registered in CloudFront (you hold the private key and sign), and an expiry, and optionally IP range and start time. Combine with origin access control (OAC) so the S3 origin accepts requests only from CloudFront. Pick CloudFront signed URLs for paid or private content at the edge, S3 presigned URLs for direct, short-lived access to a bucket.
- MFA: require it with the condition
aws:MultiFactorAuthPresent(oraws:MultiFactorAuthAge) in a policy, and get MFA-backed credentials withGetSessionTokenor by passing the MFA serial and code toAssumeRole. MFA Delete protects S3 object versions. Cognito user pools offer TOTP and SMS MFA for app users. Security tokens (STS session tokens, JWTs) should be short-lived and scoped. - Fine-grained access control: tag-based (ABAC) conditions,
dynamodb:LeadingKeysfor row-level access, S3 prefix conditions, and S3 Access Points with their own policies for per-application access.
Securing AI services in applications
AI features add their own risks: data leaving your boundary, harmful or manipulated model output, over-powerful agents and sensitive text in logs. The exam tests how to use AWS controls for this, not how to design a safety program.
Request and manage access. Access to a foundation model in Amazon Bedrock is granted and controlled through IAM. Give application roles only the needed actions (bedrock:InvokeModel, InvokeModelWithResponseStream, Converse) on the specific model or inference profile ARNs, and use service control policies and permission boundaries to restrict which models a team can use. Some models require you to request access or accept terms first. Use roles (no long-lived keys) and cross-Region inference profiles knowingly, since they route requests across Regions.
Data privacy in transit and use.
- Use an interface VPC endpoint (AWS PrivateLink) for Bedrock, so traffic from your VPC (including Lambda in a VPC) reaches the service without crossing the public internet. Add an endpoint policy and a
aws:SourceVpcecondition to enforce it. - Bedrock does not use your inputs and outputs to train the base models, and does not share them with model providers. Customized models stay private to your account. Encrypt stored artifacts, knowledge base data and agent resources with a customer managed KMS key.
- Minimize what you send: strip or tokenize PII and secrets before the prompt.
Filter and control inputs and outputs: Amazon Bedrock Guardrails. A guardrail is a reusable policy you attach to model calls (the guardrailIdentifier in InvokeModel/Converse, or the standalone ApplyGuardrail API for any model or text). It can apply:
- Content filters for hate, insults, sexual content, violence, misconduct, and prompt attacks (jailbreaks and prompt injection), with adjustable strength.
- Denied topics the application must not discuss.
- Word filters for blocked terms and profanity.
- Sensitive information filters: detect PII (and custom regex patterns) and block or mask it in inputs and outputs.
- Contextual grounding checks that flag answers not supported by the source text, and automated reasoning checks.
Guardrails check both the user input and the model response. When a guardrail intervenes, the call returns a configured blocked message. Prompt injection is also reduced by treating all external text (documents, web pages, emails) as untrusted data, not instructions, by separating system instructions from user content, by validating model output before it triggers any action, and by least-privilege tools.
Secure AI agent interactions. An agent (Bedrock Agents, AgentCore) decides which tools to call, so the danger is that a manipulated agent does something harmful with its permissions.
- Tool-use authorization: each tool (action group Lambda, API, MCP tool) gets its own narrow IAM role or scoped credential. The agent acts with the end user’s permissions where possible (identity propagation, OAuth tokens via AgentCore Identity) instead of a broad shared role, and unlisted tools are denied.
- Session isolation: each user’s session has its own memory and context, so one user’s data never leaks into another’s. AgentCore Runtime runs each session in an isolated environment, and Bedrock Agents use a session ID per conversation.
- Human-in-the-loop approval: require explicit user or operator confirmation before sensitive actions (payments, deletes, sending messages, changing permissions). Bedrock Agents offer user confirmation and return of control, and Step Functions
.waitForTaskTokencan pause a workflow for approval. - Limit the blast radius with spending and rate limits, and log every tool call.
Protect sensitive content in monitoring logs. Model invocation logging in Bedrock sends prompts and responses to CloudWatch Logs or S3, which is useful for audit but stores whatever users typed. Enable it deliberately, encrypt the log group and bucket with KMS, restrict who can read them, set short retention, mask data with CloudWatch Logs data protection policies or guardrail masking before logging, and do not log full prompts and responses in application logs unless needed. Do not put PII in X-Ray annotations or metric dimensions.
Exam checklist
- “Application on AWS needs permissions”: IAM role (execution role, instance profile, task role), never access keys.
- “Access to a bucket in another account”: resource-based policy on the bucket and an identity policy for the caller. Or the caller assumes a role in the bucket’s account.
- “Explicit deny” always wins. Boundaries and SCPs limit but never grant.
- “Users sign in to my app, get a token”: Cognito user pool. “Users need AWS credentials (S3, DynamoDB)”: identity pool. Both: sign in then exchange.
- “Corporate directory SSO”: SAML (
AssumeRoleWithSAML) or IAM Identity Center. “Social or OIDC login”:AssumeRoleWithWebIdentityor Cognito. - “Custom token validation on an API”: Lambda authorizer. “Cognito users only”: user pool authorizer, no code.
- “Encrypt data over 4 KB with KMS”: envelope encryption with
GenerateDataKey. - “Share an encrypted snapshot, object or secret across accounts”: customer managed KMS key with the other account allowed in the key policy.
- “Rotate keys with no re-encryption”: KMS automatic rotation on a customer managed key (old ciphertext still decrypts).
- “Audit who used a key”: CloudTrail logs every KMS call.
- “Database password rotation”: Secrets Manager. “Cheap config and a few secrets”: Parameter Store
SecureString. - “AccessDenied on an encrypted resource that has the right S3/SQS permissions”: check KMS key policy and
kms:Decrypt/GenerateDataKey. - “TLS certificate for ALB, CloudFront or API Gateway”: ACM. “Internal private certificates”: AWS Private CA.
- “Decode an unauthorized error”:
sts:DecodeAuthorizationMessage. - “Never trust the JWT payload before checking signature, issuer, audience and expiry.”
- “Give a browser temporary access to one S3 object”: presigned URL (ends when signing credentials expire). “Private content from CloudFront”: signed URLs or cookies with a key group, plus OAC on the origin.
- “Keep AI traffic off the internet”: interface VPC endpoint (PrivateLink) for Bedrock. “Inputs not used for training”: that is Bedrock’s default.
- “Block harmful content, denied topics, prompt attacks and mask PII on model input and output”: Bedrock Guardrails.
- “Agent must not take a sensitive action alone”: human-in-the-loop confirmation. “One user’s data appearing for another”: session isolation.
- “Prompts and answers in logs contain PII”: encrypt, restrict, shorten retention, mask with data protection policies.