Infrastructure as Code · Field Guide

AWS IaC
with Python

Understand CloudFormation. Use AWS CDK safely. Build and operate reproducible infrastructure.

FocusAWS CDK v2 · Python
FoundationCloudFormation · YAML
VersionVersion 1.2 · 15 August 2026
Module 01 · topics 02–05 Foundations

Tool selection, the mental model and a reproducible local working environment.

OeXYZ.Orientation

00 · Start

How to use this guide

This guide is both a learning path and a reference. Read topics 02 through 05 first, then build a small project and use the remaining topics while you work.

01Tool selection03
02The mental model04
03Set up your workstation05
04CDK project with Python06
05Secure CDK stack07
06Constructs and tokens08
07Compose stacks09
08Tests and policy as code10
09CloudFormation anatomy11
10Intrinsic functions and conditions12
11Deployments and drift13
12IAM and secrets14
13Lifecycle and refactoring15
14Multi-account and regions16
15CI/CD17
16Operations and cost18
17AAWS SAM19
17BTerraform and tool selection20
18AFailure patterns21
18BDiagnostic workflow22
19CDK commands23
20CloudFormation commands25
2130-day learning path27
22Glossary and sources28
i

Practice rule

Every change follows the same loop: Code → synthesis → test → diff → deployment → verification. Do not make parallel console changes to the same resources.

Getting started

Topics 03 through 13, followed by exercise 1 in topic 27.

Practice

Topics 14 through 22 for security, operations and failures.

Reference

Keep topics 23 through 26 and 28 open beside your terminal.

Independent learning resource · not an official AWS publication02 / 24
OeXYZ.Tool selection

01 · Decide

Choose a tool by operating model

For an AWS-only project using Python, CDK v2 is usually the best starting point. CloudFormation remains the execution and state foundation.

ToolStrengthsSuitable forTrade-off
AWS CDK v2
Recommended
Python, abstractions, reuse, tests, native AWS integrationAWS-only environments, more complex systems, development teamsThe synthesis and token model must be understood
CloudFormationDeclarative, AWS-native, no external state backendSmall stacks, existing YAML/JSON templates, platform teamsMore repetition; large templates become difficult to read
AWS SAMConcise serverless syntax, local test and deployment commandsLambda, API Gateway, event-driven applicationsFocused on serverless; CloudFormation remains underneath
TerraformMulti-cloud, broad provider ecosystemHybrid and multi-cloud environments, established Terraform teamsSeparate state management and HCL instead of Python

How the layers relate

Python CDK code
your constructs and rules
↓ synth
CloudFormation template
declarative target state
↓ deploy
AWS resources
actual state in the account

Choose CDK when ...

  • Python is your working language.
  • you want to encapsulate secure standards.
  • you need reusable constructs.
  • you want to test infrastructure with unit tests.

Use CloudFormation directly when ...

  • an existing template estate already exists.
  • the stack stays small and declarative.
  • no programming logic is required.
!

Do not mix tools without a boundary

A resource has exactly one IaC owner. CDK, Terraform and manual changes must not manage the same resource at the same time.

Working definition: IaC describes a versioned and verifiable target state. A provisioning script by itself does not meet that requirement.
Choose tools based on team, scope and state model03 / 24
OeXYZ.Mental model

02 · Foundations

From source code to actual AWS state

01

Author

Change Python or YAML in the repository.

02

Validate

Check syntax, tests, security and policies.

03

Plan

Read the CDK diff or change set.

04

Apply

CloudFormation applies changes in a controlled order.

05

Operate

Check status, drift, logs, cost and backups.

The five states you compare

SourceCode in the Git commit
Synthesisgenerated CloudFormation template
Change Setplanned operations
Stack StateCloudFormation managed state
Actual Stateactual resource properties

Differences between the stack definition and actual state are called Drift.

CloudFormation reasons about resources

  • Logical ID: Identity in the template. Changing it can trigger replacement.
  • Physical ID: actual name or ARN in AWS.
  • Dependency: determines creation and deletion order.
  • Update behavior: in place, interruption or replacement.
  • Rollback: attempts to return to the previous state after a failure.

Terms to understand early

Stack

Deployment and lifecycle boundary.

Construct

CDK building block made from one or more resources.

Asset

File, Lambda code or container image used for deployment.

Bootstrap

CDK support resources for each account and region.

Token

A value resolved only during synthesis or deployment.

Context

Lookup or configuration value used for deterministic synthesis.

Change Set

Preview of planned CloudFormation changes.

Drift

Manual or external deviation from the IaC target state.

✓

Completion criteria

Code committed, tests green, diff reviewed, deployment successful, application verified, alarms quiet and no unexpected drift.

Always distinguish desired state, plan and actual state04 / 24
OeXYZ.Workstation

03 · Preparation

Local tools, profile and target environment

Prerequisites

  • Python 3.11 or a newer version defined by the project
  • Node.js for the CDK CLI
  • AWS CLI v2
  • AWS CDK CLI v2
  • Git and an editor with Python and YAML support
  • SSO, OIDC or short-lived roles instead of static keys

Verify identity before every change

aws sts get-caller-identity
aws configure list
aws configure get region

# Explicitly set values when using multiple environments:
$env:AWS_PROFILE = "sandbox-admin"
$env:AWS_REGION  = "eu-central-1"

Never guess: Explicitly confirm the account ID, role and region before a deployment.

PowerShell · new Python CDK projectlocal
# Create the working directory and initialise the CDK app
New-Item -ItemType Directory aws-iac-lab
Set-Location aws-iac-lab
cdk init app --language python

# Activate the virtual environment
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

# Bootstrap the target environment once for CDK
cdk bootstrap aws://123456789012/eu-central-1

# Check early
cdk doctor
cdk synth

Pin versions

requirements.txt or commit a lockfile. Keep the CLI and library compatible.

Commit context

cdk.context.json when lookups are used. This keeps synthesis reproducible.

Ignore generated artifacts

.venv/, cdk.out/, caches and local secrets do not belong in Git.

!

Bootstrap is infrastructure

The bootstrap stack contains asset storage and roles, among other resources. Use trusted accounts, suitable permissions boundaries and consistent qualifiers.

Explicitly verify account, role and region05 / 24
Module 02 · topics 06–10 CDK with Python

Project structure, secure constructs, stack boundaries, tests and policy as code.

OeXYZ.CDK project

04 · Structure

Project structure for maintainable CDK stacks

Recommended structure

aws-iac-lab/
├─ app.py
├─ cdk.json
├─ cdk.context.json
├─ requirements.txt
├─ requirements-dev.txt
├─ pytest.ini
├─ src/
│  ├─ network_stack.py
│  ├─ data_stack.py
│  ├─ app_stack.py
│  └─ constructs/
│     └─ secure_bucket.py
├─ tests/
│  ├─ test_data_stack.py
│  └─ test_app_stack.py
└─ README.md

app.py

Composition, environments, global tags and stack dependencies. Keep extensive resource logic elsewhere.

src/*_stack.py

Divide stacks by lifecycle and ownership: network, data, application and observability.

src/constructs/

Reusable secure building blocks with a clear API and tests.

tests/

Template assertions and rules. Test outcomes, not implementation details.

Minimal entry point

app.pyPython
import os
import aws_cdk as cdk
from src.data_stack import DataStack

app = cdk.App()
environment = cdk.Environment(
    account=os.getenv("CDK_DEFAULT_ACCOUNT"),
    region=os.getenv("CDK_DEFAULT_REGION", "eu-central-1"),
)

stack = DataStack(
    app,
    "LabData",
    env=environment,
    termination_protection=True,
    description="OeXYZ AWS IaC learning data stack",
)
cdk.Tags.of(stack).add("Project", "aws-iac-lab")
cdk.Tags.of(stack).add("ManagedBy", "cdk")

app.synth()
✓

Deterministic

The same commit and context produce the same template.

!

No runtime logic

CDK code runs before deployment. It does not respond to later AWS events.

Split stacks by lifecycle and ownership06 / 24
OeXYZ.Secure CDK stack

05 · Python

Example: encrypted S3 data stack

src/data_stack.pyAWS CDK v2 · Python
from aws_cdk import (
    CfnOutput, RemovalPolicy, Stack,
    aws_kms as kms,
    aws_s3 as s3,
)
from constructs import Construct


class DataStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        key = kms.Key(
            self,
            "DataKey",
            alias="alias/aws-iac-lab-data",
            description="KMS key for the AWS IaC learning data stack",
            enable_key_rotation=True,
            removal_policy=RemovalPolicy.RETAIN,
        )

        bucket = s3.Bucket(
            self,
            "DataBucket",
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            encryption=s3.BucketEncryption.KMS,
            encryption_key=key,
            enforce_ssl=True,
            versioned=True,
            removal_policy=RemovalPolicy.RETAIN,
        )

        CfnOutput(
            self,
            "BucketArn",
            value=bucket.bucket_arn,
            description="ARN of the encrypted data bucket",
        )

No fixed bucket name

CloudFormation generates a unique physical name. This improves portability and prevents collisions.

Data is retained

RETAIN protects data when the stack is deleted or the resource is replaced. Deletion then becomes a deliberate separate operation.

Key rotation enabled

The KMS key and bucket encryption are explicit. Access is granted later with grant_* .

i

Development versus production

For short-lived learning resources, you may deliberately use RemovalPolicy.DESTROY . For S3, you must also understand auto_delete_objects=True and the cost impact. In production data stacks, RETAIN is the safe baseline.

Verification steps for this example

python -m pytest
cdk synth --strict
cdk diff LabData
cdk deploy LabData --require-approval broadening
Encapsulate secure defaults and make them visible in the diff07 / 24
OeXYZ.Constructs

06 · Abstraction

Construct levels and deployment tokens

L1

Close to CloudFormation

CfnBucket, CfnRole. Direct representation of the resource specification. Maximum control, little convenience.

L2

Intent-based

Bucket, Function, Vpc. Safe helpers, grants and useful APIs. The default choice.

L3

Pattern

Multiple resources for one use case. Fast, but more opinionated and broader in scope.

Tokens: values from the future

bucket = s3.Bucket(self, "Data")

# No physical name exists while the Python code runs:
name = bucket.bucket_name

CfnOutput(self, "Name", value=name)

The bucket name is a token. CDK serializes a reference into the template, so string output during synthesis may show placeholders.

Escape hatch

cfn_bucket = bucket.node.default_child
cfn_bucket.add_property_override(
    "Metadata.Owner", "platform"
)

Use only when the L2 construct does not yet expose a new property. Test the override and remove it later.

Design the construct API

Inputs

  • domain options instead of raw property collections
  • secure defaults
  • small, typed props

Outputs

  • interfaces such as IBucket
  • ARNs and tokens only when needed
  • no secrets in outputs

Boundaries

  • one clear responsibility
  • no hidden cross-account side effects
  • documented cost and deletion impact
!

A construct ID is identity

Renaming or moving a construct can change its logical ID and replace a resource. Before refactoring, always read cdk diff .

Review note: An abstraction may encapsulate repetition. Its cost, deletion and permission impact must remain visible.
Prefer L2 and review every escape hatch08 / 24
OeXYZ.Composition

07 · Architecture

Stack boundaries and coupling

Network

VPC, subnets, endpoints and central security groups.

rarely changed

Data

KMS, S3, databases and backups.

stateful

App

Compute, API, queues and roles.

frequently changed

Ops

Logs, alarms, dashboards and topics.

observed

Strong, typed reference

app.pysame account and region
data = DataStack(app, "Data", env=env)

api = ApiStack(
    app,
    "Api",
    data_bucket=data.bucket,
    env=env,
)

# CDK creates the required export/import relationship.
api_stack.pyLeast privilege
def __init__(..., data_bucket: s3.IBucket, **kwargs):
    super().__init__(..., **kwargs)
    fn = lambda_.Function(...)
    data_bucket.grant_read(fn)

Choose coupling deliberately

Direct referenceTyped and convenient, but creates deployment coupling.
SSM parameterLoose coupling through a name or ARN. Useful for independent deployments.
CloudFormation exportNative, but the export cannot be removed while imports still exist.
LookupFor existing resources; commit context and refresh changes deliberately.
!

Cross-stack deadlock

An export reference in use cannot be deleted directly. Decouple and deploy the consumer first, then remove the export.

Dependency rules

Automatic

Resource attributes and grants usually create the appropriate dependency.

Explicit

stack.add_dependency(other) only for genuine ordering requirements without a reference.

Avoid

Cycles. Move a shared resource into a third stack or couple it loosely.

Coupling is a deliberate architecture decision09 / 24
OeXYZ.Quality

08 · Tests

Template assertions with pytest

tests/test_data_stack.pypytest
import aws_cdk as cdk
from aws_cdk.assertions import Match, Template
from src.data_stack import DataStack


def test_bucket_is_encrypted_and_versioned():
    app = cdk.App()
    stack = DataStack(app, "TestData")
    template = Template.from_stack(stack)

    template.has_resource_properties(
        "AWS::S3::Bucket",
        {
            "VersioningConfiguration": {
                "Status": "Enabled"
            },
            "PublicAccessBlockConfiguration":
                Match.object_like({
                    "BlockPublicAcls": True,
                    "BlockPublicPolicy": True,
                }),
        },
    )
    template.resource_count_is("AWS::S3::Bucket", 1)

IaC test pyramid

UnitTemplate assertions, fast, on every commit
Policycfn-guard, cdk-nag and organization rules
Snapshotdetect broad changes; never update blindly
Integrationdeploy to a sandbox and verify AWS behavior
Smokeverify the endpoint or resource after deployment

Enable cdk-nag

from aws_cdk import Aspects
from cdk_nag import AwsSolutionsChecks

Aspects.of(app).add(AwsSolutionsChecks())

Pin the dependency separately. Use suppressions only with a specific justification and the smallest possible scope.

Validation gates

01

Format

ruff / black

02

Types

mypy

03

Tests

pytest

04

Synth

strict

05

Policy

nag / guard

06

Diff

review

✓

Test the desired properties

“The bucket is encrypted and not public” is more stable than “The logical ID is exactly DataBucketE3889A50.”

Test objectives describe behaviour, not incidental details10 / 24
Module 03 · topics 11–14 CloudFormation

Template anatomy, intrinsic functions, change sets, drift, IAM and safe secret references.

OeXYZ.CloudFormation

09 · Template

Anatomy of a CloudFormation template

template.yamlCloudFormation
AWSTemplateFormatVersion: "2010-09-09"
Description: OeXYZ AWS IaC learning storage stack

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, stage, prod]
    Default: dev

Conditions:
  IsProduction: !Equals [!Ref Environment, prod]

Resources:
  DataBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      Tags:
        - Key: Environment
          Value: !Ref Environment
        - Key: ManagedBy
          Value: cloudformation

Outputs:
  DataBucketArn:
    Description: ARN of the encrypted data bucket
    Value: !GetAtt DataBucket.Arn
    Export:
      Name: !Sub "${AWS::StackName}-DataBucketArn"

Parameters

Actual deployment inputs. Use constraints instead of unrestricted values.

Mappings

Static mapping, such as a region to an AMI or configuration.

Conditions

Create resources or properties conditionally.

Resources

The only required section. Keep logical IDs stable.

Outputs

Non-sensitive results and optional exports.

Metadata

Tool metadata, never secrets.

Rules

Validate parameter combinations before creation.

Transform

Apply SAM, Include or macros before processing.

Keep logical IDs stable and protect stateful resources11 / 24
OeXYZ.Intrinsic functions

10 · Language

Intrinsic functions, pseudo parameters and conditions

Short formMeaningExample
!RefParameter value or primary value of a resource!Ref Environment
!GetAttResource attribute!GetAtt DataBucket.Arn
!SubBuild a string from variables!Sub "${AWS::StackName}-logs"
!JoinJoin a list with a delimiter!Join [":", [a, b]]
!FindInMapRead a value from a mapping!FindInMap [Config, !Ref AWS::Region, Size]
!ImportValueImport an export from another stack!ImportValue shared-vpc-id
!IfSet a property value conditionally!If [IsProd, 3, 1]
!SelectSelect an item from a list!Select [0, !GetAZs ""]
!GetAZsAvailability Zones in a region!GetAZs !Ref AWS::Region
!Base64Base64-encode text!Base64 "#!/bin/bash"

Pseudo parameters

AWS::AccountId
AWS::Region
AWS::Partition
AWS::StackId
AWS::StackName
AWS::URLSuffix
AWS::NoValue
AWS::NotificationARNs

AWS::Partition instead of a hard-coded aws when templates must work across partitions.

Conditional property

Conditions:
  IsProd: !Equals [!Ref Environment, prod]

Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      ReservedConcurrentExecutions: !If
        - IsProd
        - 50
        - !Ref AWS::NoValue

AWS::NoValue removes the property completely instead of setting an empty value.

!

Do not nest YAML short forms arbitrarily

For complex intrinsic functions, use the long form or a mapping. Readability matters more than the shortest syntax.

Portability through references, parameters and pseudo parameters12 / 24
OeXYZ.Deployments

11 · Control

Deployment with a change set and drift check

01

Lint

cfn-lint

02

Validate

Syntax and schema

03

Change Set

Review replacement and IAM changes

04

Execute

apply in a controlled way

05

Verify

status and function

Direct development workflow

cfn-lint template.yaml

aws cloudformation validate-template \
  --template-body file://template.yaml

aws cloudformation deploy \
  --template-file template.yaml \
  --stack-name lab-data \
  --parameter-overrides Environment=dev \
  --capabilities CAPABILITY_NAMED_IAM \
  --no-fail-on-empty-changeset

In PowerShell, use a backtick for line continuation or enter the command on one line. The example uses backslashes to save space.

Explicit change set

aws cloudformation create-change-set \
  --stack-name lab-data \
  --change-set-name review-001 \
  --change-set-type UPDATE \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_NAMED_IAM

aws cloudformation describe-change-set \
  --stack-name lab-data \
  --change-set-name review-001

aws cloudformation execute-change-set \
  --stack-name lab-data \
  --change-set-name review-001

For a new stack, use --change-set-type CREATE .

Detect drift

aws cloudformation detect-stack-drift \
  --stack-name lab-data

aws cloudformation describe-stack-resource-drifts \
  --stack-name lab-data

Find the root cause

aws cloudformation describe-events \
  --stack-name lab-data \
  --filters FailedEvents=true

Investigate specific failures before “Resource creation cancelled.”

Review the change set and replacement operations before execution13 / 24
OeXYZ.Security

12 · IAM and secrets

IAM grants and secret references

CDK: grants instead of hand-written policies

secret = secretsmanager.Secret.from_secret_name_v2(
    self, "DbSecret", "prod/app/database"
)

fn = lambda_.Function(...)
bucket.grant_read(fn)
queue.grant_send_messages(fn)
secret.grant_read(fn)

Grants create targeted identity or resource policies. The secret is not read during synthesis.

CloudFormation: dynamic reference

MasterUserPassword:
  '{{resolve:secretsmanager:prod/app/database:
    SecretString:password}}'

The value remains outside the template. No output, logging or plaintext parameter.

Least-privilege check

  • Which specific action is required?
  • Which ARN can it be restricted to?
  • Can a condition be used?
  • Who may assume the role?
  • Who may iam:PassRole use it?
  • Is the KMS key policy also correct?
!

Prohibited patterns

  • Action: "*" and Resource: "*" without a demonstrated need
  • Access keys in the repository or in parameters
  • Secrets in outputs, user data, logs or stack names
  • broad trust policies

Review areas for each stack

AreaSecure baselineReview
IdentitySSO/OIDC, short-lived sessions, separate rolessts get-caller-identity, CloudTrail
DataEncryption, retention, backups and versioningTemplate tests and a restore test
Networkprivate paths, minimal ingress rules and VPC endpointsSecurity group review and reachability
DeploymentService role, permissions boundary and approval gatesChange set and Access Analyzer
DetectionLogs, alarms, CloudTrail, Config or drift checksAlarm test and periodic review
i

Secret safety

Do not use commands that retrieve secret values. For local processes, resolve dynamic Secrets Manager references with asm-exec at runtime so values never enter the working context.

Reference secrets; do not read or forward them14 / 24
Module 04 · topics 15–18 Changes and scale

Replacement, import, refactoring, multi-account, CI/CD and operational readiness.

OeXYZ.Lifecycle

13 · Changes

Replacement, import and safe refactoring

ChangePossible impactSafe approach
Change a construct ID or pathNew logical ID; the resource is recreatedcdk diff, with refactoring separated from property changes
Change an immutable propertyReplacement, potentially causing data loss or downtimeReview the change set; plan migration and rollback
Remove a stateful resourceDeletion or retention depending on policyRETAIN, backup and document the ownership transition
Remove a cross-stack exportDeployment is blocked while an import existsDecouple the consumer first and deploy separately
Make a manual change in AWSDrift; later updates may overwrite the changeBring the emergency change back into IaC and resolve the drift

Protection layers

  • Termination Protection: protects against stack deletion.
  • Removal Policy: behavior when removed from the stack.
  • UpdateReplacePolicy: behavior during replacement.
  • Stack Policy: protects selected resources from updates.
  • Backup: protects data independently of the stack.

Import existing resources

  1. Document the current state and owner.
  2. Model the resource with matching properties.
  3. Do not include any other changes in the same step.
  4. cdk diff and review the import mapping.
  5. cdk import run it.
  6. Normalize it separately afterward.

Three-deployment rule for risky changes

Deploy 1

Compatibility

Support the old and new structures at the same time. Provide a backup and migration path.

Deploy 2

Switch over

Move the consumer to the new resource or reference. Verify function.

Deploy 3

Clean up

Remove the old reference or resource. Handle retained data separately.

!

cdk destroy is not a cleanup script

First review the diff, protection policies, dependencies, data retention and cost of remaining retained resources.

Decouple risky changes into separate deployments15 / 24
OeXYZ.Environments

14 · Multi-account

Account and region boundaries

Management

Organizations and governance. No workloads.

Security

Central logs, security and audit functions.

Non-Prod

Development, tests and experiments with budgets.

Prod

Strict roles, approvals, backups and alarms.

CDK for each target environment

targets = {
    "dev": cdk.Environment(
        account="111111111111",
        region="eu-central-1",
    ),
    "prod": cdk.Environment(
        account="222222222222",
        region="eu-central-1",
    ),
}

for stage, env in targets.items():
    AppStage(
        app,
        f"App-{stage}",
        env=env,
        stage_name=stage,
    )

Account IDs are configuration, not secrets. Still keep roles and regions central and verifiable.

Boundaries and mechanisms

AccountBlast radius, billing, quotas and IAM boundary
RegionLatency, data residency and service availability
StackDeployment and lifecycle
Stagerelated stacks in one environment
StackSetsstandardized rollout across accounts and regions
SCPmaximum permitted actions in Organizations

Deployment principles

Same artifact version

A tested commit moves through environments. Do not rebuild it for each environment.

Treat differences as data

Make capacity, domains and features configurable. Do not fork the architecture by copy and paste.

Treat production deliberately

Manual approval, maintenance window, rollback plan and observability before deployment.

i

Bootstrap each account and region

Every CDK target environment needs the appropriate bootstrap resources. Keep trust relationships and permissions boundaries narrow.

Represent environment boundaries explicitly in architecture and pipeline16 / 24
OeXYZ.CI/CD

15 · Pipeline

CI/CD gates for Infrastructure as Code

01

Install

pinned dependencies

02

Lint

Python + CFN

03

Test

assertions

04

Synth

artifact

05

Scan

policy

06

Approve

production diff

07

Deploy

verify

Pipeline gates

Pull requestFormatting, linting, types, unit tests, synthesis, policy and diff artifact
Mergecreate an immutable artifact and record its signature and provenance
Devdeploy automatically, integration test and smoke test
Stagesame build, realistic data flows, load tests and restore tests
Proddiff approval, change window, deployment, alarms and verification

OIDC instead of static keys

The CI system obtains short-lived AWS credentials through a trusted identity provider.

  • Restrict trust to the repository, branch and workflow.
  • Use separate roles for synthesis, diff and deployment.
  • iam:PassRole only for defined roles.
  • Use the session name and tags for auditing.
  • Do not use long-lived access keys as CI secrets.

Artifacts

cdk.out, template, asset hashes, test reports, policy results and diff in a traceable form.

Concurrency

Allow only one writer per stack. Pipeline concurrency controls or locking prevent colliding deployments.

Rollback

CloudFormation rollback is not a complete application rollback. Plan data migrations separately.

!

Use self-mutation deliberately

A pipeline that changes its own infrastructure needs especially narrow permissions, staging, version control and a documented recovery path.

One validated artefact moves unchanged through to production17 / 24
OeXYZ.Operations

16 · Well-Architected

Operational requirements after deployment

Operational Excellence

Runbooks, small reversible changes, automated verification and drift checks.

Security

Least privilege, encryption, auditing, separate accounts and secret references.

Reliability

Backups, restore tests, Multi-AZ where needed, quotas and failure modes.

Performance

Measurable requirements, appropriate services, load tests and scaling limits.

Cost Optimization

Tags, budgets, right-sizing, retention, development shutdowns and ownership.

Sustainability

Demand-based capacity, managed services, efficient regions and architectures.

Required tags

Project       = aws-iac-lab
Environment   = dev | stage | prod
Owner         = platform-team
CostCenter    = learning
ManagedBy     = cdk
DataClass     = internal
Criticality   = low | medium | high

Define tag policies centrally. Tagging matters for cost and ownership, but does not replace an IAM or account boundary.

Operational readiness

  • Dashboards and alarms exist.
  • Log retention and data classification are defined.
  • A backup has been restored successfully.
  • Service quotas match the load.
  • The error budget and SLO are known.
  • The runbook covers diagnosis and escalation.
  • A cost alarm and budget are active.
  • Ownership and the on-call path are clear.
  • Drift checks run periodically.
i

A diff is not a cost forecast

A small template difference can have a large cost impact. Evaluate pricing, data volume, requests, logs, NAT traffic and retention separately.

Operational approval: The system is observable, recoverable, understood in cost terms and assigned to a responsible team.
Operational requirements belong in the same version control18 / 24
Module 05 · topics 19–20 SAM and Terraform

Serverless shortcuts, Terraform state and clear tool boundaries.

OeXYZ.AWS SAM

17 · Serverless

When AWS SAM makes sense

SAM extends CloudFormation for Lambda, API Gateway, events and related services. Its transform produces regular CloudFormation resources.

template.yamlAWS SAM
Transform: AWS::Serverless-2016-10-31
Resources:
  ApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.13
      Handler: app.handler
      CodeUri: src/
      Timeout: 10
      Events:
        Api:
          Type: Api
          Properties:
            Path: /health
            Method: get

SAM fits here

  • Lambda and events form the core.
  • Local builds and emulation are important.
  • The team prefers declarative YAML.
  • Only a few general infrastructure components are needed.

CDK fits here

  • Many services are composed.
  • Python abstractions and unit tests are central.
  • Multiple stacks and accounts belong together.

Local workflow

sam validate --lint
sam build
sam local start-api
sam deploy --guided

Read the transform

Inspect the generated CloudFormation template, especially IAM, APIs and implicit resources.

Check the runtime

The example runtime is version-dependent. Verify the currently supported Lambda runtimes before use.

Limits of local testing

Emulation does not replace integration tests in a real AWS sandbox.

i

Documentation-dependent reference

SAM is presented for context in this CDK-centred guide. Commands and runtimes must be checked against the installed SAM CLI and current AWS documentation.

SAM simplifies serverless; CloudFormation remains the foundation19 / 29
OeXYZ.Terraform

17 · Multi-provider

When Terraform makes sense

Terraform makes sense when multi-cloud, hybrid infrastructure or an existing platform standard matters more than native Python CDK integration.

The core workflow

terraform fmt -check
terraform init
terraform validate
terraform plan -out=tfplan
terraform apply tfplan

The saved plan is reviewed, and that exact plan is applied.

State is operational infrastructure

Backendremote, encrypted and available
Lockingonly one writer per state
Accesssmallest possible group, auditable
Backupversioning and recovery tested
Secretsa sensitive marker is not a substitute for encryption

Decide in 30 seconds

QuestionAnswerStarting point
Only AWS and Python expertise?YesAWS CDK v2
Almost exclusively Lambda, API Gateway and events?YesAWS SAM
Small existing YAML template?YesCloudFormation
Multiple clouds or providers?YesTerraform
Already using a standardised platform tool?YesImprove the existing standard

Pin providers

Plan upgrades separately and commit the lock file.

Version modules

Keep APIs small, defaults safe and migrations documented.

Separate ownership

Terraform and CloudFormation must never manage the same resource at the same time.

One tool per resource, with clear hand-offs between systems20 / 29
Module 06 · topics 21–22 Troubleshooting

Classify failures, evaluate events and create robust evidence packs.

OeXYZ.Failure patterns

18 · Troubleshooting

Common failure patterns

SymptomTypical causeNext step
NoCredentials
ExpiredToken
SSO session expired, wrong profile or roleaws sts get-caller-identity, check the profile and region
AccessDeniedmissing action, resource, condition, trust or KMS key policyread the exact API action and ARN; correlate with CloudTrail
AlreadyExistsphysical name conflicts or the resource exists outside the stacklet AWS generate the name or import the resource in a controlled way
ROLLBACK_COMPLETEcreation failed and was rolled backinspect failure events; deliberately prepare a new create
UPDATE_ROLLBACK_FAILEDrollback could not restore the resourcerepair the affected resource, then continue the rollback
Export cannot be deletedanother stack imports the exportdecouple and deploy the consumer first
Dependency cyclemutual references between resources or stacksextract the shared resource or use loose coupling
Asset publish failedbootstrap, Docker, path or permission issuecdk doctor, check the bootstrap and asset path
Unexpected replacementlogical ID or immutable property changedstop the deployment; read the diff and specification
Stack driftedmanual change or external controllerclarify ownership; correct the IaC or actual state
S3 remains after destroyRETAIN or a non-empty or versioned buckethandle data and the resource separately and deliberately

Template level

Incorrect property, dependency, IAM definition or incompatible change in the IaC code.

Environment level

Quota, missing permission, name collision, service state or existing resource.

Application level

The deployment succeeds, but a health check, data migration or application test fails.

!

Do not change the template for a purely environmental problem

Classify the failure first. Otherwise, a code change can mask quotas, role errors or inconsistent state.

Classify failures before correcting them21 / 29
OeXYZ.Diagnostic workflow

18 · Troubleshooting

Diagnostic workflow for failed deployments

Diagnostic sequence

  1. Confirm the account, role, region and stack.
  2. Find the first specific failure event.
  3. Collect every specific failure that occurred in parallel.
  4. Classify the issue at template, environment or application level.
  5. Design the smallest safe correction.
  6. Read the diff, deploy again and verify.
read-only diagnosticsAWS CLI v2
aws sts get-caller-identity

aws cloudformation describe-events \
  --stack-name LabData \
  --filters FailedEvents=true

aws cloudformation describe-stack-resources \
  --stack-name LabData

aws cloudtrail lookup-events \
  --lookup-attributes \
  AttributeKey=EventName,AttributeValue=CreateBucket
!

“Resource creation cancelled” is usually an effect, not the cause

Look for an event with a specific error message. When several genuine failures exist, capture all permission or quota gaps together.

Evidence pack for a clean handover

Context

Time, account, region, stack, commit and pipeline run.

Plan

CDK diff or change set, expected replacements and IAM changes.

Events

All specific failure events, not just the final message.

Audit

Relevant CloudTrail events and invoked API actions.

Impact

Affected users, data, regions and running resources.

Next step

Smallest reversible correction plus verification.

i

CLI prerequisite

describe-events is the current CloudFormation API with flexible filters. Older AWS CLI versions may not support this command yet.

Collect evidence, isolate the cause, apply the smallest correction22 / 29
Module 07 · topics 23–26 Command reference

CDK and CloudFormation commands for daily work, import, drift and recovery.

OeXYZ.Core CDK commands

19 · Reference

AWS CDK v2: daily workflow

# Project and version
$ cdk init app --language python
$ cdk doctor
$ cdk --version

# Environment
$ cdk bootstrap aws://ACCOUNT/REGION
$ cdk bootstrap --show-template

# Explore
$ cdk list
$ cdk context
$ cdk metadata StackName
# Quality and plan
$ python -m pytest
$ cdk synth --strict
$ cdk diff StackName
$ cdk diff --security-only

# Deployment
$ cdk deploy StackName
$ cdk deploy --all
$ cdk deploy --require-approval broadening
$ cdk deploy --outputs-file outputs.json

Production approval sequence

01

Test

pytest

02

Synth

strict

03

Diff

replacement

04

Approve

review

05

Deploy

CloudFormation

06

Verify

smoke test

Before every deployment

aws sts get-caller-identity run this and visibly confirm the account, role and region.

Validated baseline

For version 1.2, these commands were validated using AWS CDK CLI 2.1136.0 as the reference.

Verify identity, review the diff, verify the result23 / 29
OeXYZ.Specialised CDK commands

19 · Reference

CDK commands for import, drift and recovery

# Fast local development
$ cdk watch StackName

# Existing resources
$ cdk import StackName
$ cdk import --resource-mapping mapping.json

# Drift
$ cdk drift StackName
$ cdk drift StackName --fail
# Diagnostics and recovery
$ cdk deploy StackName --verbose
$ cdk rollback StackName
$ cdk rollback StackName --orphan LogicalId

# Remove
$ cdk destroy StackName
OptionWhen to use itBoundary
--profile NAMEexplicit AWS profilestill verify identity with STS
--context k=vset CDK contextnever use it for secrets
--exclusivelydeploy only the selected stackdependencies must already be compatible
--concurrency Nindependent stacks in parallelconsider quotas and shared resources
--hotswapfast local developmentbypasses the regular CloudFormation path; never use in production
--no-rollbacktargeted diagnosticsleaves partial state; not the default
!

An import contains only the import

When using cdk import do not mix updates or deletions into the same diff. Model the resource exactly first and normalise it only after a successful import.

Use specialised commands with narrow scope and validated state24 / 29
OeXYZ.Core CloudFormation commands

20 · Reference

CloudFormation: validation and state

# Optional local tools
$ cfn-lint template.yaml
$ cfn-guard validate -r rules -d template.yaml

# AWS syntax validation
$ aws cloudformation validate-template
  --template-body file://template.yaml


# Direct development deployment
$ aws cloudformation deploy
  --template-file template.yaml
  --stack-name NAME
  --capabilities CAPABILITY_NAMED_IAM
  --no-fail-on-empty-changeset
# Inventory and status
$ aws cloudformation list-stacks
$ aws cloudformation describe-stacks
  --stack-name NAME

$ aws cloudformation describe-stack-resources
  --stack-name NAME


# Drift
$ aws cloudformation detect-stack-drift
  --stack-name NAME

$ aws cloudformation describe-stack-resource-drifts
  --stack-name NAME

CREATE

The stack does not exist yet. A failure can leave it in state ROLLBACK_COMPLETE as its final status.

UPDATE

The template and parameters are compared with the managed state.

DELETE

Policies and dependencies determine which resources remain.

i

Validated baseline

For version 1.2, the AWS commands were validated using AWS CLI 2.36.19 as the reference. cfn-lint and cfn-guard remain optional tools that must be installed separately.

Validate syntax, schema, policy and actual state separately25 / 29
OeXYZ.CloudFormation changes

20 · Reference

CloudFormation: change sets and recovery

explicit change setAWS CLI v2
aws cloudformation create-change-set \
  --stack-name NAME \
  --change-set-name review-001 \
  --change-set-type UPDATE \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_NAMED_IAM

aws cloudformation describe-change-set \
  --stack-name NAME \
  --change-set-name review-001

aws cloudformation execute-change-set \
  --stack-name NAME \
  --change-set-name review-001
Failures and recoveryread first
aws cloudformation describe-events \
  --stack-name NAME \
  --filters FailedEvents=true

aws cloudformation cancel-update-stack \
  --stack-name NAME

aws cloudformation continue-update-rollback \
  --stack-name NAME
!

Recover only after identifying the cause

Before running continue-update-rollback understand the blocking resource and its actual state.

Capabilities

CAPABILITY_IAMIAM resources with generated names
CAPABILITY_NAMED_IAMIAM resources with explicit names
CAPABILITY_AUTO_EXPANDmacros may expand the template before deployment

Review

Review replacements, IAM, networking, data storage and tags.

Execute

Execute only the change set that was reviewed.

Verify

Check stack status, the application, alarms and drift.

Review the change set, execute deliberately, verify the result26 / 29
Module 08 · topics 27–29 Practice, glossary and sources

Four-week plan, working rules, glossary, primary sources and release evidence.

OeXYZ.Learning path

21 · Practice

Four-week practice plan

Week 1

Stack foundations

Build: an encrypted, versioned S3 bucket with a KMS key, tags and outputs.

  • Read the CloudFormation template after synthesis
  • Write template assertions
  • Be able to explain the diff
  • Verify deployment and retention
Week 2

Event-driven application

Build: S3 → SQS → Lambda with a DLQ, alarm and minimal grants.

  • Explain the timeout and visibility timeout
  • Create a failure scenario
  • Check the DLQ and alarm
  • Inspect logs without exposing secrets
Week 3

Multiple stacks

Build: data, application and operations stacks in development and production configurations.

  • Draw the dependencies
  • Separate stateful and stateless resources
  • Practise removing a cross-stack reference
  • Detect and correct drift
Week 4

Pipeline and recovery

Build: pull-request checks, a sandbox deployment, approval and a smoke test.

  • Constrain the OIDC role
  • Intentionally break a policy gate
  • Identify a replacement in the diff
  • Demonstrate backup and restore

Questions for the technical review

Problem

What specific problem does the stack solve, and for whom?

Boundary

What is this version explicitly unable to do?

Evidence

Which tests and metrics show that it works?

Risk

Which change could cause data loss, downtime or high costs?

Recovery

How is the system restored from a backup or previous state?

Operations

Who sees failures, and who responds to them?

✓

Capstone project

Document the architecture, IaC code, tests, threats, cost assumptions, deployment, rollback, restore process and known limitations in a public or private repository.

Learn through small, verifiable systems23 / 24
OeXYZ.Glossary

22 · Reference

Compact glossary

ARNglobal AWS resource identifier
Assetfile, code bundle or container image used in a deployment
Blast Radiusmaximum impact of a failure
BootstrapCDK support resources for each account and region
Change SetCloudFormation preview of planned changes
ConstructCDK building block made from one or more resources
ContextCDK values used for synthesis and lookups
Driftdifference between expected and actual state
Idempotencyrepeated execution leads to the same target state
Logical IDidentity of a resource in the template
Physical IDactual name or identifier in AWS
Replacementan old resource is replaced by a new one
Rollbackreturn to the last stable stack state
Statefulresource contains data worth retaining
SynthesisCDK generates CloudFormation and assets
Tokendeployment value that has not yet been resolved

Working rules

  • One IaC owner per resource.
  • No production deployment without a reviewed diff.
  • Backups count only after a successful restore.
  • Reference secrets; do not read them.
  • Protect stateful resources separately.
  • Manual changes are drift, not documentation.

Release check

  • Account, role and region confirmed
  • Tests and policy gates successful
  • Replacement and IAM reviewed in the diff
  • Rollback and restore understood
  • Smoke test and alarms verified
  • Drift and cost impact assessed
Understand systems. Reduce complexity. Build things that last.
Use precise terms and state risks explicitly28 / 29
OeXYZ.Primary sources

22 · Reference

Primary sources and release validation

Release validation

AWS CLI 2.36.19 and pinned AWS CDK CLI 2.1136.0. The generated validation-report.md documents every validated command and expected option.

Portable build

Relative font assets, the Inter licence, Python build, overflow check, PDF page check and release ZIP are part of the source package.

i

Version and responsibility

Version 1.2 was created on 15 August 2026. Before making production changes, review the current resource specification, API reference, permissions, quotas and generated change set.

Independent learning resource · AWS is a trademark of Amazon.com, Inc.

Field Guide · AWS IaC with Python · Version 1.229 / 29