A compact, deliberately readable Terraform template for a blog post. It has been migrated to use HashiCorp Terraform Stacks, preserving a strict direction of responsibility natively:
Deployments (.tfdeploy.hcl) → Components (.tfcomponent.hcl) → modules/*
It is an architecture example, not a ready-to-run production deployment. No application code, OAuth secrets, VPC, DNS zone, or real values are included.
The authorizer receives oauth_issuer_url and oauth_audience directly from the native Cognito component. It does not store a client secret; its ZIP package owns token-verification code.
.
├── .terraform-version # Required Terraform version (1.14.5+)
├── components.tfcomponent.hcl # Defines components connecting the building blocks
├── deployments.tfdeploy.hcl # Defines deployments (e.g., 'dev', 'prod') and inputs
├── outputs.tfcomponent.hcl # Values published by the Stack
├── providers.tfcomponent.hcl # Global provider configuration for all components
├── variables.tfcomponent.hcl # Stack input variables
└── modules/
├── cognito/ # Amazon Cognito User Pool and Client
├── certificate/ # ACM certificate contract
├── static_site/ # Private S3 origin + CloudFront + OAC policy
├── http_api/ # HTTP API, Lambda authorizer, and three integrations
├── lambda_function/ # Lambda, scoped execution role, and log group
├── dynamodb_table/ # On-demand encrypted single-key table
├── cache/ # ElastiCache contract using supplied VPC IDs
└── private_bucket/ # Private encrypted S3 bucket for /info data
Each local module contains main.tf, variables.tf, and outputs.tf. The small contracts make dependencies visible: modules expose ARNs, names, endpoints, or domain names; the Stack's components decide which output becomes another module's input.
- Deployments (
deployments.tfdeploy.hcl) replace the need for separate environment directories andterraform.tfvars. You can define multiple deployments (dev, staging, prod) in one place, and HCP Terraform orchestrates them automatically. - Components (
components.tfcomponent.hcl) replace the traditional "composition" module pattern. HCP Terraform natively understands the dependency graph between components and deploys them in the correct order. - Providers (
providers.tfcomponent.hcl) are configured once at the Stack level and explicitly passed to the components that need them (e.g., theaws.us_east_1alias required by the certificate component for CloudFront).
- Both S3 buckets block public access, enforce bucket ownership, and enable
aws:kmsmanaged encryption with key rotation. - CloudFront reads site objects through Origin Access Control; the origin bucket has no public website access.
- Every Lambda gets a dedicated execution role and a pre-created log group. DynamoDB and S3 permissions are scoped to ARNs Terraform knows.
- The shows Lambda receives VPC configuration only because it needs ElastiCache. Its necessary EC2 network-interface permissions remain wildcarded because these EC2 actions do not support a practical resource-level restriction in this context.
- API Gateway applies the Lambda authorizer to all three example routes and restricts CORS to the static site's custom HTTPS origin.
This repository cannot be deployed unchanged. Before any real deployment, supply:
- Lambda ZIPs. Set each
lambda_*_package_pathto a real ZIP containing the configured runtime and handler. Terraform intentionally does not build or package application code. - A real domain and DNS control. Replace the fictional
example.comnames in the deployment inputs. ACM creates a pending certificate; publish its DNS validation record (or complete email validation) before CloudFront can serve your custom domain. Create a DNS alias/CNAME to thecloudfront_domain_nameoutput afterward. - Existing network infrastructure. Supply real private subnet and security-group IDs for ElastiCache and the shows Lambda. The Lambda security group must be allowed to reach the cache security group on port
6379. The private path used by/showsmust also reach DynamoDB through a VPC endpoint or a NAT route. This template never invents a VPC, subnets, routes, endpoints, NAT gateways, or security groups. - Production decisions. Add lifecycle, observability, WAF, cache policy, route methods, backup, cost, and availability choices appropriate to the actual workload.
The deployment configuration contains fictional placeholder identifiers, URLs, domains, and paths. Replace every placeholder before triggering a deployment in HCP Terraform.
