Application Load Balancer
The HTTPS front door. Redirects HTTP, ends TLS, and routes to healthy containers.
GovCloudFIPSView source
- Module
- alb
- Layer
- Edge
- Interface
- 18 inputs, 10 outputs
- Used by
- 11 Kaizen apps
Why it matters
The load balancer is the one public address users reach. It upgrades every plain HTTP request to HTTPS, sends traffic only to copies of the app that pass a health check, and drops malformed headers before they reach the code. Federal stacks change one setting to get a FIPS 140-3 TLS policy, and that policy exists in both commercial AWS and GovCloud.
Use it when
- An app on ecs-service needs a public HTTPS endpoint with an ACM certificate.
- An internal tool needs a private HTTPS endpoint. Set internal = true and pass private subnets.
Reach for something else when
- The app is a static site with no server. Serve it from S3 behind CloudFront instead. Use s3-bucket.
- You need request filtering, rate limits, or IP allowlists. Add a web ACL on top of this load balancer. Use waf.
What it creates
aws_security_group(ports 80 and 443 from allowed_cidr_blocks, 443 from allowed_security_group_ids)aws_lb(application type, deletion protection on)aws_lb_target_group(ip targets, health check on health_check_path)aws_lb_listener(HTTP on 80, 301 redirect to HTTPS)aws_lb_listener(HTTPS on 443 with ssl_policy and certificate_arn)
Secure by default
- HTTP on port 80 always answers with a 301 redirect to HTTPS.
- Deletion protection is on (enable_deletion_protection = true).
- Invalid HTTP header fields are dropped (drop_invalid_header_fields = true, not configurable).
- The HTTPS listener uses ELBSecurityPolicy-TLS13-1-2-Res-2021-06, which allows TLS 1.2 and TLS 1.3 only.
Commercial and GovCloud
module "alb" {
source = "git::ssh://git@github.com/the-kaizen-labs/terraform-modules.git//alb?ref=v1.7.0"
app_name = local.app_name
vpc_id = module.networking.vpc_id
public_subnet_ids = module.networking.public_subnet_ids
certificate_arn = local.certificate_arn
container_port = 3000
health_check_path = "/api/health"
tags = local.tags
}| Setting | Commercial default | Federal setting | Note |
|---|---|---|---|
ssl_policy | ELBSecurityPolicy-TLS13-1-2-Res-2021-06 | ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04 | FIPS 140-3 TLS on the listener. The policy exists in both partitions. |
internal | false | true for tools that only staff reach | Pass private subnets in public_subnet_ids when internal is true. |
access_logs_bucket | null (off) | an s3-bucket name that grants PutObject to the regional ELB account | |
allowed_cidr_blocks | ["0.0.0.0/0"] | agency or Cloudflare ranges, or [] with allowed_security_group_ids |
How it connects
- From networking: vpc_id, public_subnet_ids
- From s3-bucket: bucket_name (as access_logs_bucket)
- To ecs-service: target_group_arn, alb_security_group_id
- To waf: alb_arn
- To bastion: alb_dns_name (as tls_passthrough_target)
Inputs
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
app_name | string | yes | Application name used in resource naming | |
certificate_arn | string | yes | ACM certificate ARN for HTTPS | |
public_subnet_ids | list(string) | yes | Subnet IDs for the ALB. Pass public subnets for an internet-facing ALB; pass private subnets when internal = true. Variable name kept for backward compatibility. | |
vpc_id | string | yes | VPC ID | |
access_logs_bucket | string | null | no | S3 bucket name to receive ALB access logs. Bucket must already grant PutObject to the regional ELB service account. Set to null to disable. |
access_logs_prefix | string | null | no | Key prefix within access_logs_bucket |
allowed_cidr_blocks | list(string) | ["0.0.0.0/0"] | no | CIDR blocks allowed to reach the ALB on ports 80/443. Override to restrict to Cloudflare IPs etc. Set to [] when using allowed_security_group_ids exclusively. |
allowed_security_group_ids | list(string) | [] | no | Security group IDs allowed to reach the ALB on 443. Use this when callers come from a known SG (e.g. a transit/VPN ENI SG) rather than a CIDR range. |
container_port | number | 3000 | no | Port the container listens on (used for the target group) |
enable_deletion_protection | bool | true | no | Protect the ALB from accidental deletion |
health_check_matcher | string | "200" | no | HTTP status code(s) considered healthy. Override when the backend returns a non-200 (e.g. Grafana returns 302 from / when unauthenticated). |
health_check_path | string | "/" | no | Health check path |
idle_timeout | number | 60 | no | ALB idle connection timeout in seconds. Increase for SSE or long-lived connections. |
internal | bool | false | no | Whether the ALB is internal-only (private subnets, no public IP). Federal/internal observability deployments set this to true. |
security_group_description | string | null | no | Description for the ALB security group. Set this when adopting an existing SG - AWS does not allow editing SG descriptions in place, so a mismatch forces replacement. |
ssl_policy | string | "ELBSecurityPolicy-TLS13-1-2-Res-2021-06" | no | ALB SSL policy. Default is the modern TLS 1.3 policy. Federal callers should override to ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04. |
stickiness_enabled | bool | false | no | Enable lb_cookie stickiness (useful during rolling deployments) |
tags | map(string) | {} | no | Tags to apply to all resources |
Outputs
| Name | Description |
|---|---|
alb_arn | Value: aws_lb.main.arn |
alb_arn_suffix | Value: aws_lb.main.arn_suffix |
alb_dns_name | Value: aws_lb.main.dns_name |
alb_id | Value: aws_lb.main.id |
alb_security_group_id | Value: aws_security_group.alb.id |
alb_zone_id | Value: aws_lb.main.zone_id |
http_listener_arn | Value: aws_lb_listener.http.arn |
https_listener_arn | Value: aws_lb_listener.https.arn |
target_group_arn | Value: aws_lb_target_group.app.arn |
target_group_arn_suffix | Value: aws_lb_target_group.app.arn_suffix |
Used by
| App | Pinned ref |
|---|---|
| BidBuddy | v1.0.0 |
| castle | v1.6.0 |
| evergreen | v1.0.0 |
| forager | v1.1.0 |
| ginkgo | v1.3.0 |
| juniper | v1.1.0 |
| magnolia | v1.1.0 |
| meridian | v1.0.0 |
| oak | v1.1.0 |
| saplings | v1.3.0 |
| test-health-dashboard | v1.4.0 |