feat(P56b): author 11 L1 module terraform subdirs + fix adapter output format

EXECUTE stage. Authors the remaining 11 L1 module terraform subdirs with
the full versions/variables/locals/main/outputs split. Defaults previously
hardcoded in the adapter move into locals.tf.

Simple single-resource modules (7):
- kms-key: aws_kms_key + alias (enable_key_rotation, deletion_window defaults)
- ecr: aws_ecr_repository (encryption_configuration from kms_key_arn, image_scanning)
- ecs-cluster: aws_ecs_cluster (name default)
- iam-role: aws_iam_role + inline_policy (assume_role_policy fallback, ECR/logs policy in locals.tf)
- rds: aws_db_instance (storage_encrypted, multi_az, kms_key_arn defaults)
- waf: aws_wafv2_web_acl (default_action, visibility_config, dynamic rules)
- uptime: aws_ecs_task_definition + aws_ecs_service (Fargate compat, container_definitions in locals.tf)

Multi-resource modules with intra-refs (4):
- vpc: aws_vpc + aws_subnet + aws_internet_gateway + aws_route_table (CIDR derivation in locals.tf)
- ecs-service: aws_ecs_task_definition + aws_ecs_service (Fargate compat, container_definitions, network_config in locals.tf)
- alb: aws_lb + aws_lb_target_group + aws_lb_listener (subnet/security_group list derivation in locals.tf)
- cloudfront: aws_cloudfront_distribution + aws_cloudfront_origin_access_control (OAC defaults in locals.tf)

Registry: terraform_dir added to all 11 remaining entries.

Adapter fix: stack output format uses separate 'from' + 'output' fields
(not 'from': 'rid.output'). Fixed _emit_root_output to read both fields.

6 previously-skipped tests unblocked (run_platform.sh --check-only now
resolves static-assets.yml through the new module-assembled adapter).
Removed skip markers. Fixed test assertion (aws_s3_bucket → module).

Regression: 461 passed, 0 skipped, 5 deselected (slow). All 12 modules
pass run_primitive_plan.sh --check-only. All 12 terraform/ subdirs pass
terraform init + validate standalone.

---ci---
project: acdl
phase: P56b
milestone: v1.11
status: execute
---/ci---
This commit is contained in:
Jon Chery
2026-07-28 15:28:57 +00:00
parent 8218734957
commit c80060878a
56 changed files with 1007 additions and 20 deletions
+4
View File
@@ -0,0 +1,4 @@
locals {
subnet_list = split(",", var.subnets)
security_groups = var.security_group != null ? [var.security_group] : []
}
+25
View File
@@ -0,0 +1,25 @@
resource "aws_lb" "this" {
name = var.name
load_balancer_type = var.load_balancer_type
subnets = local.subnet_list
security_groups = local.security_groups
}
resource "aws_lb_target_group" "this" {
name = var.name
port = var.port
protocol = var.protocol
vpc_id = var.vpc_id
target_type = var.target_type
}
resource "aws_lb_listener" "this" {
load_balancer_arn = aws_lb.this.id
port = var.port
protocol = var.protocol
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.this.arn
}
}
+14
View File
@@ -0,0 +1,14 @@
output "lb_arn" {
value = aws_lb.this.id
description = "The load balancer ARN."
}
output "listener_arn" {
value = aws_lb_listener.this.arn
description = "The listener ARN."
}
output "target_group_arn" {
value = aws_lb_target_group.this.arn
description = "The target group ARN."
}
+52
View File
@@ -0,0 +1,52 @@
variable "name" {
type = string
description = "Name tag for the load balancer and child resources."
default = "app"
}
variable "subnets" {
type = string
description = "Comma-separated subnet ids (ref to vpc)."
}
variable "security_group" {
type = string
description = "Security group id for the load balancer."
default = null
}
variable "port" {
type = number
description = "Listener port (default 80)."
default = 80
}
variable "protocol" {
type = string
description = "Listener protocol (default HTTP)."
default = "HTTP"
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "load_balancer_type" {
type = string
description = "Load balancer type (application or network)."
default = "application"
}
variable "target_type" {
type = string
description = "Target group target type (ip or instance)."
default = "ip"
}
variable "vpc_id" {
type = string
description = "VPC ID for the target group (ref to vpc or platform VPC)."
default = null
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
@@ -0,0 +1,7 @@
locals {
# OAC defaults (adapter previously hardcoded these).
oac_name = "acdl-oac"
oac_origin_type = "s3"
oac_signing_behavior = "always"
oac_signing_protocol = "sigv4"
}
+47
View File
@@ -0,0 +1,47 @@
resource "aws_cloudfront_origin_access_control" "this" {
name = local.oac_name
origin_access_control_origin_type = local.oac_origin_type
signing_behavior = local.oac_signing_behavior
signing_protocol = local.oac_signing_protocol
}
resource "aws_cloudfront_distribution" "this" {
origin {
origin_id = "s3-origin"
domain_name = var.bucket_regional_domain_name
origin_access_control_id = aws_cloudfront_origin_access_control.this.id
s3_origin_config {
origin_access_identity = ""
}
}
enabled = true
price_class = var.price_class
default_cache_behavior {
viewer_protocol_policy = var.viewer_protocol_policy
target_origin_id = "s3-origin"
min_ttl = 0
default_ttl = var.default_ttl
max_ttl = var.max_ttl
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
web_acl_id = var.waf_web_acl_arn
}
@@ -0,0 +1,14 @@
output "distribution_arn" {
value = aws_cloudfront_distribution.this.arn
description = "The CloudFront distribution ARN."
}
output "distribution_domain_name" {
value = aws_cloudfront_distribution.this.domain_name
description = "The CloudFront distribution domain name."
}
output "oac_id" {
value = aws_cloudfront_origin_access_control.this.id
description = "The Origin Access Control ID."
}
@@ -0,0 +1,40 @@
variable "bucket_regional_domain_name" {
type = string
description = "The S3 bucket regional domain name (ref to s3 origin)."
}
variable "price_class" {
type = string
description = "CloudFront price class (default PriceClass_100)."
default = "PriceClass_100"
}
variable "viewer_protocol_policy" {
type = string
description = "Viewer protocol policy (default redirect-to-https)."
default = "redirect-to-https"
}
variable "default_ttl" {
type = number
description = "Default TTL in seconds (default 3600)."
default = 3600
}
variable "max_ttl" {
type = number
description = "Max TTL in seconds (default 86400)."
default = 86400
}
variable "waf_web_acl_arn" {
type = string
description = "WAF web ACL ARN to associate (optional, ref to waf)."
default = null
}
variable "region" {
type = string
description = "AWS region (CloudFront is global but the provider region is used for the OAC)."
default = null
}
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+21
View File
@@ -0,0 +1,21 @@
locals {
encryption_config = var.kms_key_arn != null ? {
encryption_type = "KMS"
kms_key = var.kms_key_arn
} : null
}
resource "aws_ecr_repository" "this" {
name = var.name
image_tag_mutability = "MUTABLE"
image_scanning_configuration {
scan_on_push = true
}
dynamic "encryption_configuration" {
for_each = local.encryption_config != null ? [local.encryption_config] : []
content {
encryption_type = encryption_configuration.value.encryption_type
kms_key = encryption_configuration.value.kms_key
}
}
}
+9
View File
@@ -0,0 +1,9 @@
output "repository_url" {
value = aws_ecr_repository.this.repository_url
description = "The ECR repository URL."
}
output "repository_arn" {
value = aws_ecr_repository.this.arn
description = "The ECR repository ARN."
}
+16
View File
@@ -0,0 +1,16 @@
variable "name" {
type = string
description = "ECR repository name."
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "kms_key_arn" {
type = string
description = "ARN of the CMK for ECR encryption; if absent, uses managed key."
default = null
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+3
View File
@@ -0,0 +1,3 @@
resource "aws_ecs_cluster" "this" {
name = var.name
}
@@ -0,0 +1,9 @@
output "cluster_arn" {
value = aws_ecs_cluster.this.arn
description = "The ECS cluster ARN."
}
output "cluster_id" {
value = aws_ecs_cluster.this.id
description = "The ECS cluster ID."
}
@@ -0,0 +1,17 @@
variable "name" {
type = string
description = "ECS cluster name."
default = "acdl-cluster"
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "kms_key_arn" {
type = string
description = "ARN of the CMK for CloudWatch log group encryption; if absent, uses managed key."
default = null
}
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
@@ -0,0 +1,23 @@
locals {
# Fargate compat defaults (adapter previously hardcoded these).
requires_compatibilities = var.launch_type == "FARGATE" ? ["FARGATE"] : ["EC2"]
network_mode = var.launch_type == "FARGATE" ? "awsvpc" : "bridge"
# Container definitions from image/port/env (adapter previously hardcoded this).
container_definitions = jsonencode([{
name = "app"
image = var.image
essential = true
portMappings = [{
containerPort = var.port
hostPort = var.port
protocol = "tcp"
}]
}])
# Subnet list from comma-separated string.
subnet_list = split(",", var.subnets)
# Security groups list.
security_groups = var.security_group != null ? [var.security_group] : []
}
+31
View File
@@ -0,0 +1,31 @@
resource "aws_ecs_task_definition" "this" {
family = var.family
cpu = tostring(var.cpu)
memory = tostring(var.memory)
requires_compatibilities = local.requires_compatibilities
network_mode = local.network_mode
container_definitions = local.container_definitions
}
resource "aws_ecs_service" "this" {
name = "acdl-microservice"
cluster = var.cluster_arn
task_definition = aws_ecs_task_definition.this.arn
desired_count = var.desired_count
launch_type = var.launch_type
network_configuration {
subnets = local.subnet_list
security_groups = local.security_groups
assign_public_ip = var.launch_type == "FARGATE"
}
dynamic "load_balancer" {
for_each = var.lb_target_group_arn != null ? [1] : []
content {
target_group_arn = var.lb_target_group_arn
container_name = "app"
container_port = var.port
}
}
}
@@ -0,0 +1,9 @@
output "service_arn" {
value = aws_ecs_service.this.id
description = "The ECS service ARN."
}
output "task_def_arn" {
value = aws_ecs_task_definition.this.arn
description = "The ECS task definition ARN."
}
@@ -0,0 +1,80 @@
variable "image" {
type = string
description = "ECR image URL for the task container."
}
variable "port" {
type = number
description = "Container port the service listens on."
default = 80
}
variable "cpu" {
type = number
description = "Task CPU units (Fargate)."
default = 256
}
variable "memory" {
type = number
description = "Task memory (MiB, Fargate)."
default = 512
}
variable "env" {
type = string
description = "Environment variables as a JSON map string (optional)."
default = null
}
variable "cluster_arn" {
type = string
description = "ECS cluster ARN (ref to ecs-cluster)."
}
variable "subnets" {
type = string
description = "Comma-separated subnet ids (ref to vpc)."
}
variable "security_group" {
type = string
description = "Security group id for the service ENIs."
default = null
}
variable "lb_target_group_arn" {
type = string
description = "Optional ALB target group ARN (ref to alb)."
default = null
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "kms_key_arn" {
type = string
description = "ARN of the CMK for CloudWatch log group encryption; if absent, uses managed key."
default = null
}
variable "desired_count" {
type = number
description = "Desired number of ECS task replicas (Fargate)."
default = 1
}
variable "launch_type" {
type = string
description = "ECS launch type (FARGATE or EC2)."
default = "FARGATE"
}
variable "family" {
type = string
description = "ECS task definition family name."
default = "app"
}
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+42
View File
@@ -0,0 +1,42 @@
locals {
# Default ECS task trust policy when none is supplied (adapter previously hardcoded this).
assume_role_policy = var.assume_role_policy != null ? var.assume_role_policy : jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
# Default inline ECR+logs policy when no managed_policies supplied (adapter previously hardcoded this).
managed_policy_arns = var.managed_policies != null ? split(",", var.managed_policies) : []
inline_policy = var.managed_policies == null ? {
name = "ecr-logs"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "*"
}
]
})
} : null
}
+11
View File
@@ -0,0 +1,11 @@
resource "aws_iam_role" "this" {
name = var.role_name
assume_role_policy = local.assume_role_policy
}
resource "aws_iam_role_policy" "ecr_logs" {
count = local.inline_policy != null ? 1 : 0
name = local.inline_policy.name
role = aws_iam_role.this.id
policy = local.inline_policy.policy
}
+9
View File
@@ -0,0 +1,9 @@
output "role_arn" {
value = aws_iam_role.this.arn
description = "The IAM role ARN."
}
output "role_id" {
value = aws_iam_role.this.id
description = "The IAM role ID."
}
@@ -0,0 +1,23 @@
variable "role_name" {
type = string
description = "The IAM role name."
default = "acdl-microservice-role"
}
variable "assume_role_policy" {
type = string
description = "Assume-role policy document (JSON string)."
default = null
}
variable "managed_policies" {
type = string
description = "Comma-separated list of managed policy ARNs to attach."
default = null
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+10
View File
@@ -0,0 +1,10 @@
resource "aws_kms_key" "this" {
description = var.description
enable_key_rotation = true
deletion_window_in_days = var.deletion_window_days
}
resource "aws_kms_alias" "this" {
name = "alias/acdl-${var.description != null ? var.description : "default"}"
target_key_id = aws_kms_key.this.key_id
}
+9
View File
@@ -0,0 +1,9 @@
output "kms_key_arn" {
value = aws_kms_key.this.arn
description = "The KMS key ARN."
}
output "kms_key_id" {
value = aws_kms_key.this.key_id
description = "The KMS key ID."
}
+17
View File
@@ -0,0 +1,17 @@
variable "description" {
type = string
description = "Description of the KMS key."
default = "ACDL per-stack CMK"
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "deletion_window_days" {
type = number
description = "Deletion window in days (7-30)."
default = 30
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+13
View File
@@ -0,0 +1,13 @@
resource "aws_db_instance" "this" {
engine = var.engine
engine_version = var.engine_version
instance_class = var.instance_class
allocated_storage = var.allocated_storage
db_name = var.db_name
username = var.username
multi_az = var.multi_az
storage_encrypted = var.storage_encrypted
kms_key_id = var.kms_key_arn
skip_final_snapshot = true
publicly_accessible = false
}
+9
View File
@@ -0,0 +1,9 @@
output "db_endpoint" {
value = aws_db_instance.this.endpoint
description = "The RDS instance endpoint."
}
output "db_arn" {
value = aws_db_instance.this.arn
description = "The RDS instance ARN."
}
+54
View File
@@ -0,0 +1,54 @@
variable "engine" {
type = string
description = "Database engine (postgres, mysql, etc.)."
}
variable "engine_version" {
type = string
description = "Database engine version."
}
variable "instance_class" {
type = string
description = "RDS instance class (e.g. db.t3.micro)."
}
variable "allocated_storage" {
type = number
description = "Allocated storage in GB."
default = 20
}
variable "db_name" {
type = string
description = "Database name."
}
variable "username" {
type = string
description = "Database admin username."
}
variable "multi_az" {
type = bool
description = "Enable Multi-AZ."
default = false
}
variable "storage_encrypted" {
type = bool
description = "Enable storage encryption."
default = true
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "kms_key_arn" {
type = string
description = "ARN of the CMK for storage encryption; if absent, uses managed key."
default = null
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+12
View File
@@ -0,0 +1,12 @@
locals {
container_definitions = jsonencode([{
name = "uptime-kuma"
image = var.container_image
essential = true
portMappings = [{
containerPort = 3001
hostPort = 3001
protocol = "tcp"
}]
}])
}
+16
View File
@@ -0,0 +1,16 @@
resource "aws_ecs_task_definition" "uptime" {
family = "acdl-uptime"
cpu = tostring(var.cpu)
memory = tostring(var.memory)
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
container_definitions = local.container_definitions
}
resource "aws_ecs_service" "uptime" {
name = "acdl-uptime"
cluster = "default"
task_definition = aws_ecs_task_definition.uptime.arn
desired_count = var.feature_flag_enabled ? 1 : 0
launch_type = "FARGATE"
}
+14
View File
@@ -0,0 +1,14 @@
output "uptime_url" {
value = var.uptime_url != null ? var.uptime_url : "http://localhost:3001"
description = "The uptime-kuma URL."
}
output "service_arn" {
value = aws_ecs_service.uptime.id
description = "The uptime ECS service ARN."
}
output "task_definition_arn" {
value = aws_ecs_task_definition.uptime.arn
description = "The uptime task definition ARN."
}
+52
View File
@@ -0,0 +1,52 @@
variable "container_image" {
type = string
description = "Container image for the uptime-kuma service."
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
variable "uptime_url" {
type = string
description = "The uptime-kuma URL (output)."
default = null
}
variable "monitored_endpoints" {
type = any
description = "List of monitored endpoint objects."
default = []
}
variable "static_checks" {
type = any
description = "Static check configuration."
default = null
}
variable "alert_channels" {
type = any
description = "Alert channel configuration."
default = {}
}
variable "feature_flag_enabled" {
type = bool
description = "Feature flag to enable/disable the uptime service."
default = true
}
variable "cpu" {
type = number
description = "Task CPU units (Fargate)."
default = 256
}
variable "memory" {
type = number
description = "Task memory (MiB, Fargate)."
default = 512
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+10
View File
@@ -0,0 +1,10 @@
locals {
cidr_block = var.cidr != null ? var.cidr : "10.0.0.0/16"
az_list = split(",", var.azs)
name_tag = var.name != null ? var.name : "acdl-vpc"
# Derive subnet CIDRs from the VPC CIDR
subnet_cidrs = [
for i in range(length(local.az_list)) : cidrsubnet(local.cidr_block, 8, i + 1)
]
}
+40
View File
@@ -0,0 +1,40 @@
resource "aws_vpc" "this" {
cidr_block = local.cidr_block
tags = {
Name = local.name_tag
}
}
resource "aws_subnet" "this" {
count = length(local.az_list)
vpc_id = aws_vpc.this.id
cidr_block = local.subnet_cidrs[count.index]
availability_zone = local.az_list[count.index]
tags = {
Name = "${local.name_tag}-subnet-${count.index}"
}
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
tags = {
Name = "${local.name_tag}-igw"
}
}
resource "aws_route_table" "this" {
vpc_id = aws_vpc.this.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
tags = {
Name = "${local.name_tag}-rt"
}
}
resource "aws_route_table_association" "this" {
count = length(local.az_list)
subnet_id = aws_subnet.this[count.index].id
route_table_id = aws_route_table.this.id
}
+9
View File
@@ -0,0 +1,9 @@
output "vpc_id" {
value = aws_vpc.this.id
description = "The VPC id."
}
output "subnet_ids" {
value = join(",", aws_subnet.this[*].id)
description = "Comma-separated subnet ids."
}
+23
View File
@@ -0,0 +1,23 @@
variable "cidr" {
type = string
description = "VPC CIDR block, e.g. 10.0.0.0/16."
default = null
}
variable "azs" {
type = string
description = "Comma-separated availability zones, e.g. us-east-1a,us-east-1b."
default = "us-east-1a"
}
variable "name" {
type = string
description = "Name tag for the VPC and child resources."
default = "acdl-vpc"
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
+3
View File
@@ -0,0 +1,3 @@
locals {
action_type = var.default_action == "block" ? "block" : "allow"
}
+52
View File
@@ -0,0 +1,52 @@
resource "aws_wafv2_web_acl" "this" {
name = var.name
scope = var.scope
default_action {
dynamic "allow" {
for_each = local.action_type == "allow" ? [1] : []
content {}
}
dynamic "block" {
for_each = local.action_type == "block" ? [1] : []
content {}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "acdl-waf-metrics"
sampled_requests_enabled = true
}
dynamic "rule" {
for_each = var.rules
content {
name = lookup(rule.value, "name", "custom-rule-${rule.key}")
priority = lookup(rule.value, "priority", rule.key)
override_action {
none {}
}
statement {
byte_match_statement {
search_string = lookup(rule.value, "search_string", "/")
positional_constraint = "CONTAINS"
field_to_match {
single_header {
name = "user-agent"
}
}
text_transformation {
priority = 0
type = "NONE"
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${lookup(rule.value, "name", "custom-rule-${rule.key}")}-metrics"
sampled_requests_enabled = true
}
}
}
}
+4
View File
@@ -0,0 +1,4 @@
output "web_acl_arn" {
value = aws_wafv2_web_acl.this.arn
description = "The WAF Web ACL ARN."
}
+29
View File
@@ -0,0 +1,29 @@
variable "name" {
type = string
description = "WAF Web ACL name."
default = "acdl-waf"
}
variable "scope" {
type = string
description = "WAF scope (CLOUDFRONT or REGIONAL)."
default = "CLOUDFRONT"
}
variable "default_action" {
type = string
description = "Default action (allow or block)."
default = "allow"
}
variable "rules" {
type = any
description = "Custom WAF rules (list of rule objects)."
default = []
}
variable "region" {
type = string
description = "AWS region (provider-level; not a resource arg)."
default = null
}
+9
View File
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.9, < 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}