/AWS SAM & CloudFormation
Concept
Hard

AWS SAM & CloudFormation

13 min read·SAMCloudFormationIaCServerlessDVA-C02

A comprehensive deep dive into AWS SAM and CloudFormation — SAM resource types, CLI workflows, local testing, CloudFormation intrinsic functions, change sets, stack policies, StackSets, drift detection, and IaC patterns for the DVA-C02 exam.


Mental Model

Both SAM and CloudFormation are Infrastructure-as-Code tools — you declare the desired state, AWS figures out how to make it real.

Core mental model: CloudFormation is the general-purpose IaC engine that manages any AWS resource as a stack. SAM is a shorthand layer on top of CloudFormation specifically for serverless — one SAM function declaration expands into a Lambda function, IAM execution role, log group, and optional event source mappings automatically.

Rendering diagram…

Part 1 — AWS SAM

SAM Transform & Resource Types

Every SAM template must declare the transform at the top. The CloudFormation macro expands SAM shorthand into full CloudFormation resources at deploy time.

yaml
1AWSTemplateFormatVersion: '2010-09-09'
2Transform: AWS::Serverless-2016-10-31
3Description: My serverless application
SAM ResourceExpands into
AWS::Serverless::FunctionLambda function + IAM execution role + CloudWatch log group + optional event source mappings
AWS::Serverless::ApiAPI Gateway REST API + deployment + stage
AWS::Serverless::HttpApiAPI Gateway HTTP API (v2) + stage
AWS::Serverless::SimpleTableDynamoDB table with a single hash key
AWS::Serverless::LayerVersionLambda layer version
AWS::Serverless::ApplicationNested SAR (Serverless Application Repository) application
AWS::Serverless::StateMachineStep Functions state machine + IAM role
AWS::Serverless::ConnectorAuto-generates IAM policies for resource-to-resource access

Full SAM Template Example

yaml
1AWSTemplateFormatVersion: '2010-09-09'
2Transform: AWS::Serverless-2016-10-31
3
4Globals:
5  Function:
6    Runtime: nodejs20.x
7    MemorySize: 512
8    Timeout: 10
9    Tracing: Active           # X-Ray tracing on all functions
10    Environment:
11      Variables:
12        NODE_ENV: !Ref Stage
13    Layers:
14      - !Ref SharedUtilsLayer
15
16Parameters:
17  Stage:
18    Type: String
19    Default: dev
20    AllowedValues: [dev, staging, prod]
21
22Resources:
23
24  # ── Lambda Function ──────────────────────────────────────────────────────────
25  GetOrdersFunction:
26    Type: AWS::Serverless::Function
27    Properties:
28      CodeUri: src/handlers/getOrders/
29      Handler: index.handler
30      Description: Returns paginated order list for a user
31      ReservedConcurrentExecutions: 50
32      Policies:
33        - DynamoDBReadPolicy:
34            TableName: !Ref OrdersTable
35        - SSMParameterReadPolicy:
36            ParameterName: /myapp/prod/db-url
37      Events:
38        GetOrders:
39          Type: HttpApi
40          Properties:
41            ApiId: !Ref HttpApi
42            Path: /orders
43            Method: GET
44            Auth:
45              Authorizer: CognitoAuthorizer
46
47  # ── HTTP API (v2) ─────────────────────────────────────────────────────────────
48  HttpApi:
49    Type: AWS::Serverless::HttpApi
50    Properties:
51      StageName: !Ref Stage
52      Auth:
53        Authorizers:
54          CognitoAuthorizer:
55            IdentitySource: $request.header.Authorization
56            JwtConfiguration:
57              issuer: !Sub https://cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}
58              audience:
59                - !Ref UserPoolClient
60        DefaultAuthorizer: CognitoAuthorizer
61
62  # ── DynamoDB Table ────────────────────────────────────────────────────────────
63  OrdersTable:
64    Type: AWS::Serverless::SimpleTable
65    Properties:
66      PrimaryKey:
67        Name: orderId
68        Type: String
69      ProvisionedThroughput:
70        ReadCapacityUnits: 5
71        WriteCapacityUnits: 5
72      SSESpecification:
73        SSEEnabled: true
74
75  # ── Lambda Layer ──────────────────────────────────────────────────────────────
76  SharedUtilsLayer:
77    Type: AWS::Serverless::LayerVersion
78    Properties:
79      LayerName: shared-utils
80      ContentUri: src/layers/shared/
81      CompatibleRuntimes:
82        - nodejs20.x
83      RetentionPolicy: Retain
84
85Outputs:
86  ApiUrl:
87    Description: HTTP API endpoint URL
88    Value: !Sub https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/${Stage}
89    Export:
90      Name: !Sub ${AWS::StackName}-ApiUrl

SAM Policy Templates (Shorthand IAM)

SAM provides ~50 pre-built policy templates so you don't write raw IAM:

Policy TemplateGrants
DynamoDBReadPolicyGetItem, Query, Scan, BatchGetItem
DynamoDBCrudPolicyRead + PutItem, UpdateItem, DeleteItem
DynamoDBStreamReadPolicyRead DynamoDB stream
S3ReadPolicyGetObject, ListBucket
S3CrudPolicyFull S3 CRUD
SQSPollerPolicyReceiveMessage, DeleteMessage, GetQueueAttributes
SQSSendMessagePolicySendMessage
SNSPublishMessagePolicysns:Publish
SSMParameterReadPolicyGetParameter, GetParameters
SecretsManagerRotationPolicyRotation Lambda permissions
StepFunctionsExecutionPolicyStartExecution
VPCAccessPolicyCreateNetworkInterface, DeleteNetworkInterface
KinesisStreamReadPolicyGetRecords, GetShardIterator, DescribeStream

SAM CLI Commands

CommandWhat it does
sam initScaffold a new SAM project from a template
sam validateLint and validate the SAM template
sam buildCompile code, install dependencies, output to .aws-sam/build/
sam local invokeRun a single Lambda invocation locally (Docker)
sam local start-apiStart a local HTTP server emulating API Gateway
sam local start-lambdaExpose Lambda invoke endpoint for SDK testing
sam local generate-eventGenerate a sample event payload (S3, SQS, API GW…)
sam deploy --guidedInteractive deploy with parameter prompts
sam deployDeploy using samconfig.toml saved values
sam syncHot-sync code changes to AWS without full deploy (dev only)
sam logs -n FunctionNameTail CloudWatch logs for a function
sam tracesView X-Ray traces
sam deleteDelete the stack

Local Testing Workflow

bash
1# Generate a test event payload
2sam local generate-event apigateway http-api-proxy > events/get-orders.json
3
4# Invoke a single function locally with the event
5sam local invoke GetOrdersFunction   --event events/get-orders.json   --env-vars env.json           # override environment variables locally
6
7# Start a local API server (hot-reloads on code change)
8sam local start-api --port 3001
9
10# Pass environment variable overrides
11cat env.json
12# {
13#   "GetOrdersFunction": {
14#     "NODE_ENV": "local",
15#     "TABLE_NAME": "orders-dev"
16#   }
17# }

samconfig.toml — Persist Deploy Settings

toml
1version = 0.1
2
3[default.build.parameters]
4cached = true
5parallel = true
6
7[default.deploy.parameters]
8stack_name = "my-app-dev"
9s3_bucket = "my-deploy-bucket"
10s3_prefix = "my-app"
11region = "us-east-1"
12confirm_changeset = true
13capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"
14parameter_overrides = "Stage=dev"
15
16[prod.deploy.parameters]
17stack_name = "my-app-prod"
18parameter_overrides = "Stage=prod"
19confirm_changeset = true
bash
1# Deploy to prod profile
2sam deploy --config-env prod

SAM Connectors (Auto IAM)

Connectors automatically generate the least-privilege IAM policy between two resources:

yaml
1MyConnector:
2  Type: AWS::Serverless::Connector
3  Properties:
4    Source:
5      Id: GetOrdersFunction
6    Destination:
7      Id: OrdersTable
8    Permissions:
9      - Read
10      - Write

SAM resolves the resource types and generates the correct IAM actions — no hand-crafted policies needed.


Part 2 — AWS CloudFormation

Template Structure

yaml
1AWSTemplateFormatVersion: '2010-09-09'   # always this value
2Description: Optional stack description
3
4Metadata: {}                 # arbitrary key-value metadata
5
6Parameters: {}               # inputs — override at deploy time
7
8Mappings: {}                 # static lookup tables (region → AMI, etc.)
9
10Conditions: {}               # boolean expressions based on parameters
11
12Transform: []                # macros (SAM, AWS::Include, etc.)
13
14Resources: {}                # REQUIRED — actual AWS resources
15
16Outputs: {}                  # export values to other stacks or console

Intrinsic Functions

FunctionSyntaxUse case
Ref!Ref LogicalIdGet the primary identifier of a resource or parameter value
Fn::GetAtt!GetAtt Resource.AttributeGet a specific attribute (e.g., ARN, DNS name)
Fn::Sub!Sub 'Hello ${Name}'String interpolation with resource/parameter values
Fn::Join!Join [',', [a, b, c]]Concatenate values with a delimiter
Fn::Select!Select [0, !GetAZs '']Pick an item from a list by index
Fn::Split!Split [',', !Ref Csv]Split a string into a list
Fn::ImportValue!ImportValue StackName-OutputKeyImport an exported output from another stack
Fn::FindInMap!FindInMap [Map, Key1, Key2]Lookup a value in the Mappings section
Fn::If!If [Condition, IfTrue, IfFalse]Conditional value based on a Condition
Fn::Equals!Equals [!Ref Env, prod]Boolean equality check
Fn::Not!Not [!Equals [...]]Boolean NOT
Fn::And / Fn::Or!And [...]Boolean AND / OR
Fn::Base64!Base64 !Sub '...'Encode string as Base64 (EC2 UserData)
Fn::Cidr!Cidr [ipBlock, count, mask]Generate CIDR block list

Practical Intrinsic Function Examples

yaml
1Resources:
2  MyBucket:
3    Type: AWS::S3::Bucket
4    Properties:
5      BucketName: !Sub '${AWS::StackName}-data-${AWS::AccountId}'
6
7  MyFunction:
8    Type: AWS::Lambda::Function
9    Properties:
10      FunctionName: !Sub '${AWS::StackName}-processor'
11      # Reference another resource's attribute
12      Environment:
13        Variables:
14          BUCKET_ARN: !GetAtt MyBucket.Arn
15          BUCKET_NAME: !Ref MyBucket
16          REGION: !Ref AWS::Region
17          ACCOUNT: !Ref AWS::AccountId
18
19  MyQueuePolicy:
20    Type: AWS::SQS::QueuePolicy
21    Properties:
22      Queues:
23        - !Ref MyQueue
24      PolicyDocument:
25        Statement:
26          - Effect: Allow
27            Principal: '*'
28            Action: sqs:SendMessage
29            # Fn::Join to build complex strings
30            Resource: !Join ['', ['arn:aws:sqs:', !Ref AWS::Region, ':', !Ref AWS::AccountId, ':*']]
31
32Mappings:
33  RegionAMI:
34    us-east-1:
35      AMI: ami-0abcdef1234567890
36    eu-west-1:
37      AMI: ami-0fedcba9876543210
38
39# Usage: !FindInMap [RegionAMI, !Ref AWS::Region, AMI]
40
41Conditions:
42  IsProd: !Equals [!Ref Stage, prod]
43
44# Usage: !If [IsProd, t3.large, t3.micro]

Pseudo Parameters

Pseudo ParameterValue
AWS::AccountIdCurrent account ID
AWS::RegionDeployment region
AWS::StackNameName of the current stack
AWS::StackIdFull ARN of the current stack
AWS::NoValueRemove a property entirely (use in !If)
AWS::URLSuffixDomain suffix (amazonaws.com)
AWS::Partitionaws, aws-cn, aws-us-gov

Resource Attributes

yaml
1Resources:
2  MyDB:
3    Type: AWS::RDS::DBInstance
4    DependsOn: MySecurityGroup          # explicit ordering
5    DeletionPolicy: Snapshot            # Retain | Snapshot | Delete
6    UpdateReplacePolicy: Snapshot       # what to do when resource is replaced
7    UpdatePolicy:                       # ASG rolling update behavior
8      AutoScalingRollingUpdate:
9        MinInstancesInService: 1
10    CreationPolicy:                     # wait for signal before marking CREATE_COMPLETE
11      ResourceSignal:
12        Count: 1
13        Timeout: PT10M
14    Metadata:
15      AWS::CloudFormation::Init:        # cfn-init config sets
16        config:
17          packages:
18            yum:
19              httpd: []
DeletionPolicyOn stack delete
Delete (default)Resource is deleted
RetainResource persists after stack deletion
SnapshotSnapshot created then resource deleted (RDS, EBS, ElastiCache)

Change Sets

Change sets let you preview what CloudFormation will do before executing — critical for production stacks.

bash
1# Create a change set
2aws cloudformation create-change-set   --stack-name my-stack   --template-body file://template.yaml   --parameters ParameterKey=Stage,ParameterValue=prod   --change-set-name my-changes   --capabilities CAPABILITY_IAM
3
4# Review what will change
5aws cloudformation describe-change-set   --stack-name my-stack   --change-set-name my-changes
6
7# Execute (deploy the changes)
8aws cloudformation execute-change-set   --stack-name my-stack   --change-set-name my-changes
9
10# Delete (cancel without deploying)
11aws cloudformation delete-change-set   --stack-name my-stack   --change-set-name my-changes

Change set action types:

ActionMeaning
AddNew resource will be created
ModifyExisting resource will be updated
RemoveExisting resource will be deleted
ImportExisting resource being brought under stack management

Replacement column: True means the resource will be deleted and recreated (causes downtime for stateful resources).

Stack Policies

Stack policies protect specific resources from accidental updates or deletes:

json
1{
2  "Statement": [
3    {
4      "Effect": "Deny",
5      "Action": "Update:Replace",
6      "Principal": "*",
7      "Resource": "LogicalResourceId/ProductionDatabase"
8    },
9    {
10      "Effect": "Allow",
11      "Action": "Update:*",
12      "Principal": "*",
13      "Resource": "*"
14    }
15  ]
16}
bash
1# Apply a stack policy
2aws cloudformation set-stack-policy   --stack-name my-stack   --stack-policy-body file://stack-policy.json
3
4# Override temporarily during an update (one-time bypass)
5aws cloudformation update-stack   --stack-name my-stack   --template-body file://template.yaml   --stack-policy-during-update-body file://override-policy.json

Nested Stacks

Large templates are split into nested stacks for reuse and to stay under CloudFormation's resource limit per stack (500 resources).

yaml
1Resources:
2  VpcStack:
3    Type: AWS::CloudFormation::Stack
4    Properties:
5      TemplateURL: https://s3.amazonaws.com/my-bucket/vpc.yaml
6      Parameters:
7        VpcCidr: 10.0.0.0/16
8      TimeoutInMinutes: 10
9
10  AppStack:
11    Type: AWS::CloudFormation::Stack
12    DependsOn: VpcStack
13    Properties:
14      TemplateURL: https://s3.amazonaws.com/my-bucket/app.yaml
15      Parameters:
16        VpcId: !GetAtt VpcStack.Outputs.VpcId
17        SubnetIds: !GetAtt VpcStack.Outputs.PrivateSubnetIds

Cross-Stack References

yaml
1# Stack A — export a value
2Outputs:
3  VpcId:
4    Value: !Ref MyVPC
5    Export:
6      Name: !Sub ${AWS::StackName}-VpcId   # must be globally unique in the region
7
8# Stack B — import it
9Resources:
10  SecurityGroup:
11    Type: AWS::EC2::SecurityGroup
12    Properties:
13      VpcId: !ImportValue NetworkStack-VpcId

Limitation: You cannot delete Stack A while Stack B imports from it. Circular imports between stacks are not allowed.

StackSets — Multi-Account / Multi-Region Deployment

Rendering diagram…
bash
1# Create a StackSet (deploy to multiple accounts and regions)
2aws cloudformation create-stack-set   --stack-set-name security-baseline   --template-body file://security.yaml   --capabilities CAPABILITY_NAMED_IAM   --permission-model SERVICE_MANAGED   # for AWS Organizations
3
4# Deploy instances to accounts in an OU
5aws cloudformation create-stack-instances   --stack-set-name security-baseline   --deployment-targets OrganizationalUnitIds=ou-xxxx-yyyyyyy   --regions us-east-1 eu-west-1   --operation-preferences MaxConcurrentPercentage=25,FailureTolerancePercentage=10
Permission ModelHow admin role is created
SELF_MANAGEDYou create AWSCloudFormationStackSetAdministrationRole manually
SERVICE_MANAGEDAWS Organizations manages trusted access automatically

Drift Detection

Drift occurs when a resource's actual configuration differs from its CloudFormation template (someone changed it manually via console or CLI).

bash
1# Start drift detection on a stack
2aws cloudformation detect-stack-drift --stack-name my-stack
3
4# Check drift status
5aws cloudformation describe-stack-drift-detection-status   --stack-drift-detection-id <id>
6
7# List drifted resources
8aws cloudformation describe-stack-resource-drifts   --stack-name my-stack   --stack-resource-drift-status-filters MODIFIED DELETED
Drift StatusMeaning
IN_SYNCMatches template
MODIFIEDActual config differs from expected
DELETEDResource no longer exists
NOT_CHECKEDResource type not supported for drift

cfn-init & cfn-signal (EC2 Bootstrap)

yaml
1Resources:
2  WebServer:
3    Type: AWS::EC2::Instance
4    Metadata:
5      AWS::CloudFormation::Init:
6        config:
7          packages:
8            yum:
9              httpd: []
10              nodejs: []
11          files:
12            /var/www/html/index.html:
13              content: !Sub '<h1>Hello from ${AWS::StackName}</h1>'
14              mode: '000644'
15          services:
16            sysvinit:
17              httpd:
18                enabled: true
19                ensureRunning: true
20    CreationPolicy:
21      ResourceSignal:
22        Count: 1
23        Timeout: PT15M      # wait up to 15 minutes for the signal
24    Properties:
25      UserData:
26        Fn::Base64: !Sub |
27          #!/bin/bash -xe
28          yum update -y aws-cfn-bootstrap
29          # Run cfn-init to apply Metadata::AWS::CloudFormation::Init
30          /opt/aws/bin/cfn-init -v             --stack ${AWS::StackName}             --resource WebServer             --region ${AWS::Region}
31          # Signal success/failure back to CloudFormation
32          /opt/aws/bin/cfn-signal -e $?             --stack ${AWS::StackName}             --resource WebServer             --region ${AWS::Region}

CloudFormation Capabilities

Some templates require explicit capabilities to avoid accidental privilege escalation:

CapabilityRequired when
CAPABILITY_IAMTemplate creates IAM roles, policies, or instance profiles
CAPABILITY_NAMED_IAMTemplate creates IAM resources with custom names
CAPABILITY_AUTO_EXPANDTemplate uses macros (SAM transform, AWS::Include)

SAM vs CloudFormation — When to Use Each

SAMCloudFormation
Best forServerless (Lambda, API GW, DynamoDB, Step Functions)Any AWS resource
Template verbosityLow — shorthand resource typesHigh — full resource declarations
Local testingsam local invoke
Hot syncsam sync
Policy templates✅ 50+ shorthand policies❌ manual IAM
Connectors (auto IAM)
StackSets❌ (use CFN)
Nested stacks✅ (via CFN)
Drift detection❌ (use CFN)
Change sets✅ (via CFN)

DVA-C02 Quick Reference

TopicKey Fact
SAM transform declarationTransform: AWS::Serverless-2016-10-31
SAM Function expands toLambda + IAM role + CloudWatch log group
SAM local invokeRuns Lambda locally using Docker
SAM policy templatesShorthand IAM — e.g., DynamoDBReadPolicy, S3CrudPolicy
SAM syncHot-deploys code changes without full CloudFormation stack update
samconfig.tomlPersists sam deploy settings so you don't need --guided every time
CloudFormation only required sectionResources
!Ref on a resourceReturns primary identifier (e.g., bucket name, queue URL)
!GetAttReturns a specific attribute (ARN, DNS name, etc.)
!SubString interpolation — replaces ${LogicalId} with resolved value
!ImportValueReads exported output from another stack
!FindInMapLooks up value in Mappings section
DeletionPolicy RetainResource persists after stack delete
DeletionPolicy SnapshotSnapshot created before resource deleted (RDS, EBS)
Change set Replace=TrueResource will be deleted and recreated
Stack policyPrevents specific resources from accidental update/delete
Stack policy override--stack-policy-during-update-body (one-time bypass)
Cross-stack export deleteCannot delete exporting stack while another stack imports from it
StackSets SERVICE_MANAGEDUses AWS Organizations — no manual role creation
cfn-signal purposeEC2 tells CloudFormation bootstrap is complete (CreationPolicy)
CAPABILITY_NAMED_IAMRequired when IAM resources have custom names
CAPABILITY_AUTO_EXPANDRequired when template uses macros (SAM, AWS::Include)
Drift detection findsResources manually changed outside CloudFormation

Practice Questions3

medium

Q1. A developer writes an AWS SAM template with an `AWS::Serverless::Function` resource. After running `sam deploy`, a reviewer inspects the CloudFormation stack and sees additional resources not in the SAM template. Why?


Select one answer before revealing.

medium

Q2. A developer uses a CloudFormation template with hardcoded AMI IDs. The team deploys to multiple regions, but AMI IDs differ per region. How should the developer handle region-specific values without duplicating templates?


Select one answer before revealing.

medium

Q3. A developer needs to share an S3 bucket ARN created in a "common-infrastructure" CloudFormation stack with a "web-app" stack. What is the correct CloudFormation mechanism?


Select one answer before revealing.