d1aa5daf2b
---ci--- project: atelier phase: 5 milestone: v0.2 status: complete requirements: covered: [ATELIER-36, ATELIER-37, ATELIER-38, ATELIER-39, ATELIER-40, ATELIER-41, ATELIER-42, ATELIER-43, ATELIER-44, ATELIER-45, ATELIER-46, ATELIER-47, ATELIER-48, ATELIER-49, ATELIER-50, ATELIER-51, ATELIER-52, ATELIER-53, ATELIER-54, ATELIER-55, ATELIER-56, ATELIER-57, ATELIER-58, ATELIER-59] partial: [] ---/ci---
4.0 KiB
4.0 KiB
Good Example: Terraform Module
A reusable Terraform module that follows Atelier's Infrastructure as Code principles. Each aspect cites the principle it satisfies.
The Module
A versioned module that provisions an S3 bucket with logging, versioning, and encryption — the canonical "secure bucket" pattern, composed rather than copy-pasted.
Consumer Call
module "logs_bucket" {
source = "registry.example.com/infra/secure-bucket/aws"
version = "1.2.0"
name = "app-logs"
region = "us-east-1"
force_destroy = false
retention_days = 90
}
Module Structure
secure-bucket/
├── main.tf # the resource
├── variables.tf # typed inputs
├── outputs.tf # the interface to consumers
├── versions.tf # provider pin
└── README.md # the module contract
versions.tf (P5 Version Everything)
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
variables.tf (P1 Declarative Intent, C2 Clarity)
variable "name" {
type = string
description = "Globally unique bucket name."
validation {
condition = can(regex("^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$", var.name))
error_message = "Bucket name must be lowercase, 3-63 chars, DNS-compatible."
}
}
variable "retention_days" {
type = number
default = 30
description = "S3 lifecycle transition age in days."
}
main.tf (P1, P3 State is Truth, P10 Secrets Never in Code)
resource "aws_s3_bucket" "this" {
bucket = var.name
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_lifecycle_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
id = "retention"
status = "Enabled"
filter { prefix = "" }
expiration { days = var.retention_days }
}
}
What Makes It Good
Composition (IaC P6 Modules Compose, C6 Composability)
- The bucket pattern is one module, versioned once, consumed many times. A new consumer does not copy 40 lines of HCL — they call the module with a
nameand aretention_days. - See
domains/infrastructure-as-code/modules.mdfor the module-vs-copy boundary.
Pinning (IaC P5 Version Everything)
- The consumer pins
version = "1.2.0". The module pins its provider (version = "~> 5.0") and the required Terraform version. A commit is a complete, reproducible world. - No
latestanywhere. Seedomains/infrastructure-as-code/terraform.md.
State Discipline (IaC P3 State is Truth, P8 Remote State with Locking)
- The consumer's root configuration declares a remote backend with locking (S3 + DynamoDB, GCS, etc.). The module itself does not declare a backend — the consumer owns state.
- See
domains/infrastructure-as-code/state.mdfor backend selection and locking.
Secrets Hygiene (IaC P10 Secrets Never in Code)
- The bucket is encrypted at rest (SSE-S3 AES256). No secret is hardcoded; encryption is a provider-managed default. If KMS were used, the key would come from a
datasource or a dedicated KMS module — never a literal. - See
domains/security/secrets.mdfor the general secrets principles.
Plan Before Apply (IaC P4 Plan Before Apply)
- The consumer runs
terraform planbeforeapply. The plan shows the new bucket, versioning, encryption, and lifecycle. Every line is reviewed. The plan is the contract review;applyis the signature.
Cross-Domain Links
domains/devops/P1 Reproducibility— the module makes the bucket reproducible from source.domains/devops/P6 Configuration as Code— the bucket is config, not a console click.domains/security/supply-chain— a versioned, signed module from a trusted registry is a supply-chain control.