Modular IaC Patterns
Overview
Modular IaC promotes reusability, consistency, and maintainability through well-designed, versioned modules and constructs. This skill covers best practices for creating and consuming infrastructure modules.
mermaid
graph TB
subgraph "Module Registry"
VPC[VPC Module v1.2.0]
EKS[EKS Module v2.0.0]
RDS[RDS Module v1.5.0]
end
subgraph "Consumer Stacks"
Dev[Development Stack]
Staging[Staging Stack]
Prod[Production Stack]
end
VPC --> Dev
VPC --> Staging
VPC --> Prod
EKS --> Dev
EKS --> Prod
Module Design Principles
| Principle | Description |
|---|---|
| Single Responsibility | One module = one resource group |
| Sensible Defaults | Works out-of-box, customize as needed |
| Minimal Interface | Few required variables, many optional |
| Version Pinning | Explicit versions, semantic versioning |
| Documentation | README, examples, variable descriptions |
Best Practices
- •Version everything - Semantic versioning (major.minor.patch)
- •Use remote sources - Git tags, Terraform Registry, npm
- •Validate inputs - Variable validations, type constraints
- •Limit outputs - Only expose what consumers need
- •Include examples - Ready-to-run example configurations
- •Test modules - Terratest, CDK assertions
Example 1: Terraform - Reusable VPC Module
Production-ready VPC module with IPAM, IPv6, and multi-tier subnets.
📁 Location: terraform/modules/vpc/
Module Structure
code
terraform/modules/vpc/
├── main.tf # Primary resources
├── variables.tf # Input variables with validations
├── outputs.tf # Module outputs
├── versions.tf # Provider constraints
├── README.md # Usage documentation
└── examples/
└── complete/ # Full example
Usage
hcl
module "vpc" {
source = "git::https://github.com/org/terraform-modules.git//vpc?ref=v1.2.0"
# Required
name = "myapp"
environment = "prod"
vpc_cidr = "10.0.0.0/16"
# Optional - sensible defaults
enable_ipv6 = true
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
enable_nat_gateway = true
single_nat_gateway = false
}
Example 2: CDK - L3 Construct for Secure Application
Reusable construct that bundles VPC, EKS, and security best practices.
📁 Location: cdk/constructs/secure-application/
Construct Pattern
typescript
export interface SecureApplicationProps {
readonly environment: 'dev' | 'staging' | 'prod';
readonly vpcCidr?: string;
readonly enableEks?: boolean;
}
export class SecureApplication extends Construct {
public readonly vpc: ec2.Vpc;
public readonly cluster?: eks.Cluster;
constructor(scope: Construct, id: string, props: SecureApplicationProps) {
super(scope, id);
// VPC with best practices baked in
this.vpc = new ec2.Vpc(this, 'Vpc', {
ipAddresses: ec2.IpAddresses.cidr(props.vpcCidr ?? '10.0.0.0/16'),
maxAzs: props.environment === 'prod' ? 3 : 2,
subnetConfiguration: [
{ name: 'Public', subnetType: ec2.SubnetType.PUBLIC },
{ name: 'Private', subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
{ name: 'Isolated', subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
],
});
// Optional EKS cluster
if (props.enableEks) {
this.cluster = new eks.Cluster(this, 'Cluster', {
vpc: this.vpc,
vpcSubnets: [{ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }],
});
}
}
}
Module Versioning Strategy
| Change Type | Version Bump | Example |
|---|---|---|
| Breaking change | Major | 1.0.0 → 2.0.0 |
| New feature (backwards compatible) | Minor | 1.0.0 → 1.1.0 |
| Bug fix | Patch | 1.0.0 → 1.0.1 |
Validation Checklist
- • Module has clear README with examples
- • All variables have descriptions and types
- • Sensible defaults provided
- • Version pinned in consumer code
- • Outputs documented
- • Examples directory included
Related Skills
- •Layered Stacks - Using modules in layers
- •Environment Parity - Same modules across envs
- •Network Segmentation - VPC module example