Architecture
The twelve modules as one stack, the path a request takes through them, and every connection between them.
A Kaizen app stack is one Terraform file, main.tf, that calls these modules and passes the outputs of one module into the inputs of the next. Each layer below is a category. Click any box to open that module's page.
Follow one request
A user opens a Kaizen app in a browser. This is the path the request takes and the module that owns each hop.
DNS. Cloudflare DNS points the app's domain, such as my-app.kaizenlabs.tools, at the load balancer's DNS name. An engineer creates that record once, after the first deploy.
Firewall. AWS WAF, attached to the load balancer by the waf module, checks the request against AWS managed rule sets and an optional per IP rate limit. Requests that match a rule stop here.
Load balancer. The alb module ends TLS with the app's ACM certificate, redirects plain HTTP to HTTPS, and forwards the request to a healthy container.
App container. The ecs-service module runs the app on AWS Fargate in private subnets. The containers have no public IP and accept traffic only from the load balancer's security group. The image comes from the app's ecr repository, and the containers run in an ecs-cluster.
Data. The app reads and writes rds-postgres over TLS, redis over TLS, and an s3-bucket through its task role. Each data store accepts connections only from the app's security group.
Logs. The container writes to a CloudWatch log group that ecs-service creates. Stacks that need log search inside the account route the same logs through a Fluent Bit sidecar to openobserve.
Operators never take that public path to reach the database. They open a session on the bastion through AWS Systems Manager Session Manager, which checks their IAM permissions and records the session. The bastion has no SSH key and no open port 22.
All of it sits in one VPC from the networking module. The VPC belongs to the AWS account, not to one app. The first app in an account creates it, and later apps look it up by its Name tag.
Every connection
Solid arrows carry an output from one module into an input of another. Dotted arrows carry a customer managed KMS key, which the app stack creates itself with aws_kms_key when it runs in federal posture.
How the wiring works
Three patterns cover every arrow above.
| Pattern | Example | Why |
|---|---|---|
| Security group handoff | allowed_security_group_ids = [module.ecs_service.security_group_id] on rds-postgres | The database accepts connections from the app's tasks and nothing else. |
| Secrets through SSM | rds-postgres db_host goes into an SSM SecureString DATABASE_URL, which ecs-service injects with container_secrets | Passwords never appear in plain environment variables. |
| Task role policy | An aws_iam_role_policy on module.ecs_service.task_role_name grants access to module.s3_uploads.bucket_arn | The app gets access to its own bucket only. |
One VPC per account
networking runs once per AWS account. Apps in kaizen-ext and kaizen-int look up the shared VPC with data "aws_vpc" by Name tag and find subnets by their tier tag. Each new account claims its own /16 range in the README's CIDR allocation table, so VPCs never overlap.