examlab .net The most efficient path to the most valuable certifications.
In this note ≈ 27 min

IaC for Network Infrastructure — CloudFormation, CDK, and Terraform Patterns

5,400 words · ≈ 27 min read ·

ANS-C01 Domain 2.4 deep dive into infrastructure as code for network resources: CloudFormation StackSets and cross-stack exports, AWS CDK SubnetType enum and L2/L3 networking constructs, Terraform aws_vpc modules, SSM Parameter Store dynamic references.

Do 20 practice questions → Free · No signup · ANS-C01

IaC for network infrastructure on ANS-C01 is the question candidates underestimate at their peril. The Solutions Architect exam treats CloudFormation as "the YAML/JSON tool". The Advanced Networking Specialty exam asks "given an AWS Organisation with 200 accounts, design an IaC pattern that deploys a baseline VPC with TGW attachment, Network Firewall integration, Flow Logs to a central S3 bucket, and Resolver rules conditionally forwarding to on-prem — using StackSets, with auto-remediation on drift, dynamic references for VPC and subnet IDs, and no hardcoded AZ names — and explain the cross-stack vs cross-region limitation when consuming the VPC ID in a separate workload stack". That is production-grade IaC for networking at scale, and ANS-C01 has 3-5 questions on it.

This topic covers the IaC primitive surface for AWS networking: CloudFormation templates for VPC, subnet, route table, security group, NAT GW, IGW, TGW, and Network Firewall; StackSets for multi-account multi-region baseline deployment; cross-stack references (Export/Import) and their region/account limitations; AWS CDK networking constructs with SubnetType enums and higher-level L2/L3 abstractions; Terraform networking modules and patterns; SSM Parameter Store for dynamic VPC/subnet ID references; event-driven automation with EventBridge + Lambda for remediation; AWS Config for drift detection and compliance; and CloudFormation custom resources for resources not natively supported. Mapped to Task Statement 2.4 (Automate and configure network infrastructure).

Why IaC Is the Difference Between Production and Demo on ANS-C01

ANS-C01 explicitly tests Domain 2.4 IaC because AWS sees so many production failures rooted in hardcoded infrastructure templates. A VPC template with hardcoded AMI IDs breaks when reused in a different region. A CloudFormation stack with hardcoded AZ names (us-east-1a, us-east-1b) cannot be redeployed in another region. A CDK app that mutates global state for VPC CIDR allocation creates conflicts at scale. The exam tests recognising these patterns and choosing the right primitives — Mappings, Parameters, Pseudo Parameters, SSM dynamic references, AZ data lookups — to make templates portable.

The framing across this topic is declarative infrastructure with parameterisation. Every template, CDK app, or Terraform module should consume external inputs (CIDR, region, account, environment), produce outputs that other templates can reference, and avoid embedded magic values. This produces reusable building blocks — VPC modules, TGW attachment modules, Network Firewall modules — that compose into multi-account multi-region architectures. ANS-C01 expects you to recognise reusable patterns and refactor templates that violate them.

The exam tests IaC in three distinct flavours. Reusability and portability asks "what makes this template not portable to a new region?" with answer choices including "hardcoded AZ names" and "hardcoded AMI IDs". Multi-account deployment asks "deploy a VPC baseline to 50 accounts — which mechanism?" (StackSets, sometimes CDK Pipelines as a distractor). Event-driven remediation asks "auto-remediate when a security group is opened to 0.0.0.0/0:22 — what triggers and what acts?" (Config rule + EventBridge + Lambda).

Plain-Language Explanation: IaC for Network Infrastructure

IaC combines a few primitives (templates, parameters, exports/imports, custom resources, deployment orchestration) into reusable infrastructure patterns. Three analogies anchor the moving parts.

Analogy 1: The Architectural Blueprints With Standard Component Catalogues

Think of IaC as architectural blueprints for a building. CloudFormation templates are the master blueprints — every wall, door, window, and pipe is specified declaratively. Parameters are the customisable knobs at the top of the blueprint — "this house is 4 bedrooms; this is 5". Mappings are catalogue lookup tables — "for region X use AMI Y, for region Z use AMI W". Pseudo parameters are the standard surveyor's measurements — AWS::Region, AWS::AccountId, AWS::StackName — automatically supplied by the platform without the architect specifying. Cross-stack exports are when one blueprint says "the steel I-beam Joists Stack will provide beam ID 42; we'll bolt to it" — the second blueprint imports the export. CDK is a higher-level architect's program — instead of drafting every nail, it generates the blueprint from a Python or TypeScript description: "build a 4-bedroom house with attached garage". StackSets is the bulk-construction franchise — same blueprint deployed to 200 plots simultaneously. Terraform is the alternative drafting service offering similar blueprints with a slightly different syntax and broader vendor support (multi-cloud).

Analogy 2: The Recipe Book vs Cookbook vs Restaurant Chain

A CloudFormation template is a recipe — declarative, every ingredient and step specified. Parameters are the recipe variants — "for 4 servings use 1 cup; for 8 use 2 cups". CDK is a cookbook generator — you write higher-level instructions ("standard Italian dinner") and it generates the recipe. Terraform is an alternative cookbook publisher offering similar recipes for many cuisines (multi-cloud). StackSets is the restaurant chain franchising — same recipe deployed to 200 restaurants. Cross-stack exports are shared kitchen ingredients — "the prep kitchen makes the stock; the line cooks consume it". Custom resources are the special-order ingredients the standard cookbook doesn't list — you call a Lambda to source them. Drift detection is the food safety inspection that detects when a chef secretly changed the recipe.

Analogy 3: The Auto Manufacturing Production Line

A CloudFormation template is the assembly-line specification for a car model. Every component, every sub-assembly, every wire is declared. Parameters are the trim-level options — "base model with steel wheels vs sport with alloy". Mappings are the regional component variants — "for North America use steel from supplier A; for Europe use supplier B". Cross-stack exports are the parts catalogue — when Engine Stack publishes "engine assembly part #42", the Body Stack imports and bolts on. CDK is the CAD program that generates the assembly spec from higher-level design language. StackSets is the multi-plant rollout — the same model produced at 200 factories with consistent specs. Drift detection is the quality inspection that catches a factory deviating from the spec.

For ANS-C01, the architectural blueprint analogy is the highest-yield mental model when a question asks about template reuse, cross-stack composition, and multi-account deployment. The recipe book image is sharpest for understanding CDK as a higher-level abstraction over CloudFormation. For event-driven remediation and drift detection, the production-line quality inspection sub-analogy maps cleanly. Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html

CloudFormation Networking Resources — The Core Inventory

CloudFormation supports declarative provisioning of every AWS networking resource. The Specialty exam expects fluency in the resource types and their relationships.

Core resource types

  • AWS::EC2::VPC — the VPC itself, with CIDR, dualstack attributes, tenancy.
  • AWS::EC2::Subnet — a subnet, with CIDR, AZ, mapPublicIpOnLaunch flag.
  • AWS::EC2::InternetGateway + AWS::EC2::VPCGatewayAttachment — IGW creation and attachment.
  • AWS::EC2::NatGateway + AWS::EC2::EIP — NAT GW with its Elastic IP.
  • AWS::EC2::RouteTable + AWS::EC2::Route + AWS::EC2::SubnetRouteTableAssociation — route table, individual routes, and subnet associations.
  • AWS::EC2::SecurityGroup + AWS::EC2::SecurityGroupIngress / Egress — SG with rules.
  • AWS::EC2::NetworkAcl + AWS::EC2::NetworkAclEntry + AWS::EC2::SubnetNetworkAclAssociation — NACL and rules.
  • AWS::EC2::TransitGateway + AWS::EC2::TransitGatewayAttachment + AWS::EC2::TransitGatewayRouteTable — TGW family.
  • AWS::EC2::VPCEndpoint — gateway or interface endpoints.
  • AWS::EC2::FlowLog — VPC Flow Logs.
  • AWS::NetworkFirewall::Firewall + FirewallPolicy + RuleGroup — Network Firewall family.

Cross-resource references

CloudFormation uses !Ref and !GetAtt to reference other resources within the same template:

Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
  MySubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']

Note !GetAZs '' returns the list of AZs in the current region — avoiding hardcoded AZ names. !Select [0, ...] picks the first AZ. This is portable across regions.

Pseudo parameters

CloudFormation provides pseudo parameters auto-populated by the service:

  • AWS::Region — current region, e.g., us-east-1.
  • AWS::AccountId — the account this stack is deploying into.
  • AWS::StackName — the name of this stack.
  • AWS::Partitionaws, aws-cn, aws-us-gov.
  • AWS::URLSuffixamazonaws.com or amazonaws.com.cn.

Use these for portability across regions, accounts, and partitions.

Mappings for region-specific values

If a value varies by region (e.g., AMI IDs), use a Mappings section:

Mappings:
  RegionMap:
    us-east-1:
      AMI: ami-0abc1234
    us-west-2:
      AMI: ami-0def5678
Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [RegionMap, !Ref AWS::Region, AMI]

This is portable but requires manual updating when AMIs change. SSM Parameter Store dynamic references (next section) are usually preferred.

  • CloudFormation template: declarative YAML/JSON describing AWS resources.
  • Stack: a deployed instance of a template; a unit of provisioning.
  • StackSet: a multi-account multi-region orchestration construct.
  • CDK (Cloud Development Kit): programmatic IaC framework that synthesises CloudFormation.
  • Constructs: CDK building blocks (L1 = raw CFN; L2 = AWS-curated; L3 = pattern bundles).
  • Cross-stack reference: Export from one stack consumed via Import in another.
  • SSM dynamic reference: {{resolve:ssm:...}} syntax for pulling values from Parameter Store.
  • Custom resource: Lambda-backed resource for unsupported types.
  • Drift detection: CloudFormation feature comparing live state to template state.
  • Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html

CloudFormation StackSets — Multi-Account Multi-Region Networking

CloudFormation StackSets orchestrate template deployment across many accounts and regions from a single operation. It is the canonical ANS-C01 answer for "deploy this VPC baseline across the AWS Organisation".

Architecture

A StackSet has:

  • Template — the CloudFormation template to deploy.
  • Targets — accounts and regions where stacks will be created.
  • Permissions modelSELF_MANAGED (cross-account roles created manually) or SERVICE_MANAGED (uses AWS Organisations + service-linked role).
  • Operation preferences — concurrency limits, failure tolerance.

Each target gets its own stack instance, which is a regular CloudFormation stack tied to the StackSet. Updates to the StackSet propagate to all instances.

Service-managed StackSets with AWS Organisations

The modern pattern: enable trusted access between CloudFormation StackSets and AWS Organisations. The administrator account can deploy StackSets to organisational units (OUs) or the entire org. Stacks auto-deploy to new accounts as they are added to the OU. Auto-deployment + auto-update + auto-removal makes baseline networking governance hands-off.

Common patterns

  • Enable VPC Flow Logs in every account/region — StackSet with a Flow Log resource pointing at a centralised S3 bucket.
  • Create baseline VPC in every account — StackSet creating a VPC, subnets, IGW, NAT GW, route tables.
  • Enable AWS Config in every account/region — StackSet with Config recorder and delivery channel pointing at central S3.
  • Org-wide TGW attachment — StackSet that creates a VPC attachment to the central TGW (shared via RAM).

Limitations

  • StackSets cannot reference resources in another stack via Export/Import across accounts.
  • Region-specific resource availability matters — some services are not in all regions.
  • Update propagation is one direction: StackSet → instance. Drift detection on instances reports differences.

A common ANS-C01 distractor: a multi-account scenario asks how to enforce a VPC baseline (Flow Logs, baseline NACL, baseline SG) across the org. Answer choices include "manually deploy CloudFormation in each account", "use Lambda + EventBridge to auto-create on account creation", and "use CloudFormation StackSets with service-managed permissions". StackSets is the right answer for declarative org-wide deployment. Lambda + EventBridge is the answer for event-driven remediation (a different pattern). Manual deployment is never right for org-wide. Memorise: StackSets for declarative baselines; Lambda + EventBridge for event-driven remediation; Config + Firewall Manager for compliance enforcement. Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html

Cross-Stack References — Export and Import

CloudFormation supports cross-stack references within a single account and region via the Export/Import mechanism. A stack publishes an output as an export; another stack imports it as a value.

Producer stack — exporting a VPC ID

Outputs:
  VpcId:
    Description: VPC ID for shared networking
    Value: !Ref MyVPC
    Export:
      Name: !Sub "${AWS::StackName}-VpcId"

Consumer stack — importing the VPC ID

Resources:
  MySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId:
        Fn::ImportValue: NetworkStack-VpcId
      GroupDescription: Workload SG

Limitations

  • Same account, same region only. Cross-stack exports do not work across accounts or regions.
  • Once an export is consumed by another stack, the producer stack cannot delete or modify the export until the consumer is updated.
  • Updates to the exported value require careful update ordering.

Cross-account/cross-region — use SSM Parameter Store

For multi-account or multi-region sharing, use SSM Parameter Store as the shared registry:

  • Producer stack writes the VPC ID to /network/prod/vpcid (potentially with a cross-account KMS key for encryption).
  • Consumer stacks (in any account, any region with appropriate access) read via SSM dynamic reference: {{resolve:ssm:/network/prod/vpcid}}.
  • Cross-account access via shared parameter (with appropriate IAM policies and KMS key access).

Limitations

  • SSM dynamic references in CloudFormation are resolved at template-deployment time — not later.
  • Updates to the SSM parameter do not auto-trigger stack updates.
  • Cross-account SSM requires careful KMS key sharing and IAM policy.

A scenario describes a multi-region deployment with shared VPC IDs exported from a network stack in us-east-1 and consumed by workload stacks in us-west-2. Candidates accept this as plausible — it is not. Cross-stack Export/Import is single-region single-account only. For cross-region/cross-account sharing, use SSM Parameter Store or Resource Access Manager (RAM) depending on the resource type. The exam tests this exact misconception. Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-crossstackref.html

SSM Parameter Store and Dynamic References

SSM Parameter Store is AWS's managed key-value store for configuration. CloudFormation supports dynamic references to retrieve SSM values at template-resolution time.

Dynamic reference syntax

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}'

The {{resolve:ssm:...}} syntax fetches the SSM parameter value during stack creation/update. AWS publishes managed parameters at /aws/service/ami-amazon-linux-latest/... for current Amazon Linux AMIs — always up-to-date, never hardcoded.

Using SSM for VPC IDs across stacks

Producer stack:

Resources:
  VpcIdParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: /network/prod/vpcid
      Type: String
      Value: !Ref MyVPC

Consumer stack (any account with read access to the parameter):

Resources:
  MySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: '{{resolve:ssm:/network/prod/vpcid}}'

When to use SSM dynamic references vs cross-stack Export

  • Cross-stack Export: same account, same region, tightly coupled stacks where you want CloudFormation to track the dependency.
  • SSM dynamic reference: cross-region, cross-account, or loose coupling. Producer publishes; consumer reads independently.

Limitations

  • Resolution happens at deployment time. Subsequent SSM parameter changes do not retrigger stack updates.
  • Some resource attributes do not support dynamic references (rare for networking; more common for IAM).

AWS CDK — Networking Constructs and Higher-Level Abstractions

AWS CDK (Cloud Development Kit) is a programming-language-based IaC framework that synthesises CloudFormation. It provides L1 constructs (raw CloudFormation), L2 constructs (AWS-curated abstractions), and L3 constructs (pattern bundles).

CDK L2 networking — ec2.Vpc

import * as ec2 from 'aws-cdk-lib/aws-ec2';

const vpc = new ec2.Vpc(this, 'MyVPC', {
  ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
  maxAzs: 3,
  subnetConfiguration: [
    {
      name: 'public',
      subnetType: ec2.SubnetType.PUBLIC,
      cidrMask: 24,
    },
    {
      name: 'private-egress',
      subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      cidrMask: 24,
    },
    {
      name: 'isolated',
      subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
      cidrMask: 28,
    },
  ],
});

This compact code synthesises a full CloudFormation template with VPC, IGW, 9 subnets (3 AZs × 3 types), NAT GWs in each AZ for the egress subnets, and route tables for each subnet type.

SubnetType enum — the canonical CDK abstraction

CDK's ec2.SubnetType enum is the most-tested CDK construct on ANS-C01:

  • PUBLIC — has IGW route, instances can have public IPs.
  • PRIVATE_WITH_EGRESS — no public IPs, but NAT GW route for outbound (formerly PRIVATE).
  • PRIVATE_ISOLATED — no public IPs, no internet route at all (formerly ISOLATED).

Using SubnetType enables CDK to manage NAT GW placement, route tables, and security defaults automatically.

Higher-level CDK patterns

CDK supports L3 patterns like ApplicationLoadBalancedFargateService that bundle ECS, ALB, security groups, and target groups in one construct call. For networking, a typical L3 pattern: deploy a complete VPC + TGW + Network Firewall stack with a few lines.

CDK + Aspects + Tags

CDK supports cross-cutting concerns via Aspects — apply tags or compliance checks to all resources in a tree. Common pattern: Aspect that adds CostCenter and Owner tags to every resource in the stack.

CDK and L3 implicit security groups

A CDK trap: L3 constructs may create implicit security groups that you must understand and configure. For example, ApplicationLoadBalancedFargateService creates an ALB SG and ECS task SG; default rules might be too permissive for production. Always inspect synthesised CloudFormation and override SG rules when necessary.

ANS-C01 frequently tests CDK best practice. Using ec2.SubnetType.PUBLIC / PRIVATE_WITH_EGRESS / PRIVATE_ISOLATED is the canonical pattern; CDK handles route tables, NAT GW placement, and AZ distribution automatically. Anti-pattern: writing raw ec2.CfnSubnet (L1) constructs and managing route tables manually — equivalent to writing CloudFormation in TypeScript without benefit. Memorise: SubnetType enum is the right level of abstraction for typical VPC code; L1 constructs are for resources L2 doesn't yet support. Reference: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SubnetType.html

Terraform for AWS Networking

Terraform is HashiCorp's multi-cloud IaC tool. It uses HCL syntax and a state-based execution model. ANS-C01 expects familiarity with Terraform's networking resources, even though CloudFormation/CDK are AWS-native.

Core Terraform AWS networking resources

  • aws_vpc — the VPC.
  • aws_subnet — subnets.
  • aws_internet_gateway + aws_nat_gateway + aws_eip — gateways.
  • aws_route_table + aws_route + aws_route_table_association — routing.
  • aws_security_group + aws_security_group_rule — security groups.
  • aws_vpc_endpoint — gateway and interface endpoints.
  • aws_ec2_transit_gateway + aws_ec2_transit_gateway_vpc_attachment — TGW.

Terraform modules

Terraform supports modules — reusable HCL bundles. The community-maintained terraform-aws-modules/vpc/aws module is the canonical AWS VPC pattern, abstracting the same concepts as CDK's ec2.Vpc.

Terraform state

Terraform's stateful execution model (state file in S3 with DynamoDB locking) differs from CloudFormation's stateless declarative model. Implications:

  • Terraform requires a backend (S3 + DynamoDB) for team use.
  • State drift requires terraform refresh or terraform plan to detect.
  • Renaming resources or moving them between modules requires terraform state mv or careful refactor.

When to use Terraform vs CloudFormation/CDK

ANS-C01 does not strongly prefer one over the other. Use Terraform when:

  • Multi-cloud (AWS + GCP, AWS + Azure).
  • Existing Terraform expertise and toolchain.
  • Module ecosystem you depend on (e.g., terraform-aws-modules/vpc).

Use CloudFormation/CDK when:

  • AWS-only.
  • StackSets needed for org-wide multi-account multi-region deployment.
  • Native AWS support (e.g., AWS Config rules for CloudFormation, integration with Service Catalog).

Avoiding Hardcoded Values — Portability Anti-Patterns

Hardcoded values are the #1 cause of non-portable IaC. ANS-C01 explicitly tests recognising hardcode anti-patterns.

Anti-pattern: hardcoded AMI IDs

ImageId: ami-0abc1234efgh5678

This breaks when redeploying in another region (different AMI ID) or when AMI is deprecated. Fix: use SSM dynamic reference: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2}}' — always-current AMI for the current region.

Anti-pattern: hardcoded AZ names

AvailabilityZone: us-east-1a

Breaks in any other region. Fix: !Select [0, !GetAZs ''] returns the first AZ in the current region.

Anti-pattern: hardcoded VPC CIDR

CidrBlock: 10.0.0.0/16

Breaks if multiple stacks need different CIDRs to avoid overlap. Fix: Parameter with default + override per environment, or AWS IPAM for centralised CIDR allocation.

Anti-pattern: hardcoded Account IDs

RoleArn: arn:aws:iam::123456789012:role/MyRole

Breaks across accounts. Fix: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/MyRole' using pseudo parameters.

Anti-pattern: hardcoded resource names

RoleName: MyHardcodedRoleName

Breaks when re-deployed in the same account (name conflict). Fix: omit name and let CloudFormation generate, or use !Sub '${AWS::StackName}-MyRole'.

A scenario describes a CloudFormation template with AvailabilityZone: us-east-1a failing when a customer redeploys to eu-west-1. Candidates blame "wrong region" or "service unavailable" — the actual fix is to never hardcode AZ names. Use !Select [0, !GetAZs ''] to pick the first AZ in the current region, or define a Parameter that takes AZ inputs from outside. Memorise the portable patterns: !GetAZs '' for AZ list, !Ref AWS::Region for region, !Ref AWS::AccountId for account, SSM dynamic references for AMIs. Hardcoding any of these is an anti-pattern the exam will flag. Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getavailabilityzones.html

Event-Driven Network Automation

Event-driven automation uses EventBridge rules and Lambda functions to react to network events — security group changes, VPC creation, BGP session state changes — and apply remediation or governance.

EventBridge + Lambda pattern

  1. Source event: a CloudTrail API call (e.g., AuthorizeSecurityGroupIngress), Config rule evaluation result, or AWS Health event.
  2. EventBridge rule: matches the event pattern (e.g., security group with IpRanges = 0.0.0.0/0 on port 22).
  3. Target Lambda: invokes with the event details, executes remediation (e.g., revoke the rule).
  4. Notification: SNS topic for security team awareness.

Common patterns

  • Auto-revoke 0.0.0.0/0:22 — EventBridge rule on AuthorizeSecurityGroupIngress with IpRanges = 0.0.0.0/0 and port 22; Lambda revokes the rule and sends Slack alert.
  • Auto-attach Flow Logs to new VPCs — EventBridge rule on CreateVpc; Lambda adds Flow Log to centralised S3.
  • Auto-update Route 53 health check on instance state change — EventBridge rule on EC2 state change; Lambda updates health check or DNS.
  • BGP session down alerting — CloudWatch metric on Direct Connect BGP state; EventBridge rule on alarm; Lambda paginates on-call.

EventBridge cross-account

For multi-account orgs, EventBridge can have rules in member accounts that forward events to a central security account's EventBridge bus. Centralised remediation Lambda can then act on events from many accounts.

Step Functions for complex remediation

For multi-step remediation (e.g., quarantine instance + capture forensics + notify + create ticket), use Step Functions to orchestrate Lambda invocations with retry, error handling, and human approval steps.

StackSets is for declarative baseline deployment (every account has VPC Flow Logs). Event-driven remediation is for reacting to drift or violations (someone disabled Flow Logs — re-enable it). Use both: StackSets to deploy the baseline, EventBridge + Lambda to detect and reverse violations. Together they form the full governance loop. AWS Config rules can be the detection mechanism, with EventBridge triggering Lambda on rule evaluations of NON_COMPLIANT. Reference: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html

AWS Config for Drift Detection and Compliance

AWS Config records resource configuration changes over time and evaluates them against rules. It is the AWS-native answer to "is this VPC configured correctly?" and "did anyone change the security group at 3am?"

Config recorder + delivery channel

Each region in each account has a Config recorder that captures configuration changes for selected resource types (or all). Changes are delivered to an S3 bucket (typically central) and optionally to SNS for notifications.

Config rules — managed and custom

Managed Config rules are AWS-published evaluators for common compliance:

  • vpc-flow-logs-enabled — every VPC has Flow Logs.
  • restricted-ssh — no SG allows 0.0.0.0/0 on port 22.
  • vpc-sg-open-only-to-authorized-ports — SGs do not allow 0.0.0.0/0 on unauthorized ports.
  • vpc-default-security-group-closed — default SG denies all traffic.

Custom Config rules are Lambda-backed evaluators for organisation-specific compliance.

Config and remediation

Config rules can have automatic remediation via SSM Automation documents. When a rule evaluates NON_COMPLIANT, Config invokes the remediation document — e.g., AWS-EnableVPCFlowLogs to auto-attach Flow Logs to a non-compliant VPC.

CloudFormation drift detection

CloudFormation has its own drift detection feature that compares the deployed stack's actual state to the template's expected state. Detect drift via console or detect-stack-drift API. Drift is reported per-resource. Useful for catching manual changes that bypassed IaC.

Config + Firewall Manager

For org-wide compliance, AWS Firewall Manager depends on AWS Config in every member account. Firewall Manager uses Config to discover resources (security groups, WAF web ACLs, Network Firewall) and enforces policies declared centrally. This is the canonical org-wide network governance pattern.

  • CloudFormation pseudo parameters: AWS::Region, AWS::AccountId, AWS::StackName, AWS::Partition.
  • !GetAZs '': returns AZ list in current region; portable AZ reference.
  • !Select [0, ...]: pick first element from list.
  • SSM dynamic reference: {{resolve:ssm:/path/to/param}}; resolves at deployment time.
  • Cross-stack Export/Import: same account, same region only.
  • StackSets: multi-account multi-region; service-managed permissions integrate with Organisations.
  • CDK SubnetType: PUBLIC, PRIVATE_WITH_EGRESS, PRIVATE_ISOLATED.
  • Config rule evaluation: COMPLIANT, NON_COMPLIANT, NOT_APPLICABLE.
  • Drift detection: CloudFormation compares deployed state to template; per-resource report.
  • Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html

CloudFormation Custom Resources for Unsupported Types

Custom resources in CloudFormation are Lambda-backed (or SNS-backed) resources that fill gaps in CloudFormation's native resource coverage. Used when:

  • A resource type is not yet supported by CloudFormation.
  • A pre-deployment lookup is needed (e.g., "find the latest AMI ID matching tag X").
  • A complex setup requires imperative logic (e.g., "create resource A, then conditionally create B based on result").

Lambda-backed custom resource pattern

The custom resource type is Custom::* (any namespace after Custom::). On stack create/update/delete, CloudFormation sends an event to a Lambda function. The Lambda performs the imperative work and returns success/failure to a CloudFormation pre-signed URL.

Resources:
  MyCustomResource:
    Type: Custom::FindLatestAMI
    Properties:
      ServiceToken: !GetAtt MyLambda.Arn
      ImageNamePattern: amzn2-ami-hvm-*-x86_64-gp2

The Lambda receives ImageNamePattern, calls EC2 DescribeImages, returns the AMI ID. Other resources reference the result via !GetAtt MyCustomResource.AmiId.

Considerations

  • Custom resources add complexity and risk. Prefer native CloudFormation when possible.
  • Lambda must respond to all events (Create, Update, Delete) including failure paths — incomplete implementations cause stuck rollbacks.
  • For CDK, use the Custom::Resource L1 or Provider framework for similar patterns.

Common Traps Recap — IaC for Network Infrastructure on ANS-C01

Trap 1: Cross-stack Export/Import works across regions

Wrong. Same account, same region only.

Trap 2: Hardcoded AZ names are fine in same-region templates

Wrong. Even same-region, AZ names can be remapped per account (e.g., us-east-1a in account A may be a different physical AZ from us-east-1a in account B). Always use !GetAZs.

Trap 3: StackSets is for any multi-resource deployment

Misleading. StackSets is specifically for multi-account multi-region deployment of the same template. For multi-resource deployment in one account, use a single stack or nested stacks.

Trap 4: SSM dynamic references auto-update when parameter changes

Wrong. Resolved at deployment time. Subsequent SSM changes do not retrigger stack updates.

Trap 5: CDK L3 constructs require no security review

Wrong. L3 constructs may create implicit security groups and IAM roles with default rules that are too permissive. Always inspect synthesised CloudFormation.

Trap 6: Terraform state is automatically backed up

Wrong. Terraform state is whatever your backend says it is — typically S3, which you must configure with versioning + encryption + locking.

Trap 7: Custom resources are needed for every gap

Wrong. CloudFormation has caught up significantly; many gaps that previously required custom resources are now native. Check current docs before writing custom logic.

Trap 8: Drift detection auto-remediates

Wrong. Drift detection only detects; you must take action manually or via separate automation (Lambda).

FAQ — IaC for Network Infrastructure

Q1: When should I use CloudFormation StackSets versus AWS CDK Pipelines for multi-account deployment?

StackSets is purpose-built for deploying the same template to many accounts and regions. Service-managed permissions integrate with AWS Organisations for hands-off scaling. Best for: baseline VPC/Flow Logs/Config in every account; standard org-wide network governance. CDK Pipelines is purpose-built for CI/CD pipelines that deploy CDK apps with cross-account stage promotion. Best for: complex multi-stage deployments (dev → test → prod) where each stage is in a different account, with code-driven progression. ANS-C01 expects StackSets as the canonical answer for org-wide baseline networking. CDK Pipelines is more SAP-C02 / DevOps territory. Both can coexist: StackSets for baseline, CDK Pipelines for application deployments on top of the baseline.

Q2: How do I share VPC IDs and subnet IDs across stacks in different accounts?

Cross-stack Export/Import does not work cross-account. Two patterns. Pattern 1 (SSM Parameter Store): producer stack writes VPC ID to a parameter (e.g., /network/prod/vpcid), grants cross-account read access via parameter resource policy + KMS key sharing. Consumer stacks in other accounts use '{{resolve:ssm:/network/prod/vpcid}}' dynamic reference. Pattern 2 (AWS RAM): for resources that support RAM (subnets via VPC sharing, TGW, Resolver rules, License Manager), share via RAM. Consumers reference the shared resource directly (no manual ID copying). Pattern 2 is preferable for RAM-supported resources; Pattern 1 is the general-purpose answer when resource sharing is not natively supported.

Q3: What is the difference between CDK L1, L2, and L3 constructs for networking?

L1 (CloudFormation Resource): 1:1 mapping with CloudFormation resource types. ec2.CfnVpc, ec2.CfnSubnet. Most verbose, most flexible. Use when L2 doesn't yet support a feature. L2 (AWS Construct): AWS-curated abstractions with sensible defaults. ec2.Vpc, ec2.SecurityGroup. Most code is at this level. Use SubnetType enum, default-secure SGs, helper methods. L3 (Pattern Construct): high-level patterns combining many resources. aws-ecs-patterns.ApplicationLoadBalancedFargateService, aws-rds.DatabaseCluster. Use when the pattern matches your architecture; otherwise compose L2 constructs. ANS-C01 expects L2 fluency for VPC, SG, NACL, NAT GW. L3 is more application-tier and less directly tested for networking.

Q4: How do I avoid hardcoding AMI IDs in CloudFormation templates?

Use SSM Parameter Store dynamic references for AWS-managed AMIs:

Parameters:
  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

This declares a CloudFormation parameter typed as an SSM parameter, AWS resolves it at stack creation. AWS publishes managed parameters at /aws/service/ami-amazon-linux-latest/... for current AMIs in every region — the same template works in any region without modification. For custom AMIs, store the AMI ID in a custom SSM parameter (e.g., /myorg/baseline/ami) and reference similarly. The dynamic resolution gets the right AMI for the current region automatically.

Q5: How do I detect when someone manually modifies a resource managed by CloudFormation?

Use CloudFormation drift detection. Run aws cloudformation detect-stack-drift --stack-name MyStack (or via console). CloudFormation compares each resource's actual state to its template-expected state and reports drift per-resource. For continuous detection: schedule a Lambda function that calls detect-stack-drift regularly and alerts on differences. Alternatively, use AWS Config with rules like cloudformation-stack-drift-detection-check for managed compliance evaluation. For automatic remediation, combine drift detection with Lambda that re-runs update-stack to revert manual changes — but be cautious: automatic reversal of manual changes can cause production outages if the manual change was an emergency fix. Best practice: detect drift, alert, manually decide whether to update template or revert.

Q6: When should I use CloudFormation custom resources versus a separate Lambda invocation post-deployment?

Use custom resources when the work must happen as part of the stack lifecycle — create on stack creation, update on stack update, delete on stack deletion, with proper rollback support. The custom resource is part of the dependency graph; other resources can reference its outputs. Use separate Lambda invocations (manual or via EventBridge) when the work is loosely coupled and lifecycle-independent — post-deployment configuration, periodic remediation, event-triggered actions. Custom resources are more powerful but more complex; separate Lambdas are simpler but require additional orchestration. Typical ANS-C01 example: custom resource for "find latest AMI matching tag X" (must happen at stack creation); separate Lambda for "auto-revoke 0.0.0.0/0:22 SG rule" (event-triggered, ongoing).

Q7: How do I use AWS Config to enforce that every VPC has Flow Logs enabled?

Enable AWS Config in every account and region (typically via StackSets). Add the managed Config rule vpc-flow-logs-enabled to evaluate every VPC. The rule reports COMPLIANT or NON_COMPLIANT per VPC. For automatic remediation, attach the SSM Automation document AWS-EnableVPCFlowLogs as the remediation action — Config will invoke it for non-compliant VPCs. Combine with EventBridge rules on compliance change events to alert when NON_COMPLIANT findings appear. For org-wide enforcement, use AWS Firewall Manager to deploy this Config rule + remediation across the entire organisation, with auto-deployment to new accounts. The result: every VPC org-wide gets Flow Logs automatically, with continuous compliance verification.

Q8: What is the right way to handle environment differences (dev/staging/prod) in IaC?

Pattern 1: Parameters with environment input — single template with Environment parameter (dev, staging, prod); use Conditions and Mappings to vary behaviour. Compact but the parameter explosion can become unwieldy. Pattern 2: Separate stacks per environment with shared template and per-environment parameter files. Clean separation but template changes propagate to all environments simultaneously. Pattern 3: CDK with environment-specific app constructs — programmatic differentiation: new MyStack(app, 'Dev', { env: dev }); new MyStack(app, 'Prod', { env: prod, prodOnly: true }). Most flexible because you can use programming logic. Pattern 4: Separate templates per environment — fully decoupled but at the cost of duplication. ANS-C01 expects Pattern 2 or Pattern 3 for serious workloads. Avoid mixing environments in a single stack — blast radius of an accidental update is too large.

Q9: How do I deploy a TGW attachment from a workload account to a TGW shared from a network account?

Architecture: network account creates TGW, shares it via RAM with workload accounts. Workload accounts deploy CloudFormation that creates a AWS::EC2::TransitGatewayAttachment referencing the shared TGW ID. The workload's CloudFormation template needs the TGW ID — pass it as a Parameter, or read from SSM (the network account writes the TGW ID to a shared SSM parameter). For service-managed StackSets: the network account creates a parent stack with the TGW; member accounts have child stacks with attachment resources that reference the parent's outputs via SSM or RAM. Auto-acceptance on the TGW (set in network account) avoids needing manual approval per attachment. The result: workload accounts deploy a stack that brings up TGW connectivity automatically, with the network team retaining centralised TGW route table control.

Q10: How do I integrate event-driven remediation with my IaC baseline?

Layered approach. Layer 1 (Baseline): StackSets deploys baseline resources (VPC Flow Logs, baseline NACLs, baseline SGs, Config rules) to every account/region in the org. Layer 2 (Detection): Config rules continuously evaluate compliance; CloudWatch alarms detect anomalies (e.g., NAT GW packets dropped); CloudTrail captures all API calls. Layer 3 (Eventing): EventBridge rules pattern-match suspicious events (e.g., CreateSecurityGroup with 0.0.0.0/0 rule). Layer 4 (Action): Lambda functions remediate (revoke rule, isolate instance, snapshot for forensics). Layer 5 (Notification): SNS to security team, optional Slack integration. The ANS-C01 expectation: IaC declares the steady state (Layer 1) and the detection rules (Layers 2-3); event-driven Lambdas handle deviations (Layer 4); humans get alerts (Layer 5). This composes into a self-healing network governance platform.

Further Reading

IaC is the automation plane; the next layers on ANS-C01 are VPC architecture and CIDR design for the templates IaC actually deploys; Transit Gateway routing for the multi-account multi-region fabric IaC orchestrates; Route 53 Resolver for the DNS rules IaC must share via RAM; and network monitoring and cost optimisation for the operational concerns IaC must wire up automatically.

Official sources

More ANS-C01 topics