diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index b8f1b8a..adea23e 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -71,6 +71,14 @@ jobs:
id: minMax
uses: clowdhaus/terraform-min-max@v1.0.3
+ - name: Install hcledit (for terraform_wrapper_module_for_each hook)
+ shell: bash
+ run: |
+ curl -L "$(curl -s https://github.com/gitapi/repos/minamijoyo/hcledit/releases/latest | grep -o -E -m 1 "https://.+?_linux_amd64.tar.gz")" > hcledit.tgz
+ sudo tar -xzf hcledit.tgz -C /usr/bin/ hcledit
+ rm -f hcledit.tgz 2> /dev/null
+ hcledit version
+
- name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }}
uses: clowdhaus/terraform-composite-actions/pre-commit@v1.3.0
with:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 19dda01..954c537 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,6 +3,7 @@ repos:
rev: v1.71.0
hooks:
- id: terraform_fmt
+ - id: terraform_wrapper_module_for_each
- id: terraform_validate
- id: terraform_docs
args:
diff --git a/README.md b/README.md
index 4b90900..79dfe5b 100644
--- a/README.md
+++ b/README.md
@@ -294,7 +294,7 @@ module "lb" {
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 0.13.1 |
+| [terraform](#requirement\_terraform) | >= 1.0.0 |
| [aws](#requirement\_aws) | >= 3.67 |
## Providers
diff --git a/examples/complete-alb/README.md b/examples/complete-alb/README.md
index ead2e9a..8611ebe 100644
--- a/examples/complete-alb/README.md
+++ b/examples/complete-alb/README.md
@@ -19,7 +19,7 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 0.13.1 |
+| [terraform](#requirement\_terraform) | >= 1.0.0 |
| [aws](#requirement\_aws) | >= 3.40 |
| [null](#requirement\_null) | >= 2.0 |
| [random](#requirement\_random) | >= 2.0 |
diff --git a/examples/complete-alb/versions.tf b/examples/complete-alb/versions.tf
index 7dd3807..8317cb9 100644
--- a/examples/complete-alb/versions.tf
+++ b/examples/complete-alb/versions.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 0.13.1"
+ required_version = ">= 1.0.0"
required_providers {
aws = {
diff --git a/examples/complete-nlb/README.md b/examples/complete-nlb/README.md
index e54a154..88aefba 100644
--- a/examples/complete-nlb/README.md
+++ b/examples/complete-nlb/README.md
@@ -19,7 +19,7 @@ Note that this example may create resources which cost money. Run `terraform des
| Name | Version |
|------|---------|
-| [terraform](#requirement\_terraform) | >= 0.13.1 |
+| [terraform](#requirement\_terraform) | >= 1.0.0 |
| [aws](#requirement\_aws) | >= 3.40 |
| [random](#requirement\_random) | >= 2.0 |
diff --git a/examples/complete-nlb/versions.tf b/examples/complete-nlb/versions.tf
index 2fc3eef..45d645c 100644
--- a/examples/complete-nlb/versions.tf
+++ b/examples/complete-nlb/versions.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 0.13.1"
+ required_version = ">= 1.0.0"
required_providers {
aws = {
diff --git a/main.tf b/main.tf
index 6c0a168..59a2510 100644
--- a/main.tf
+++ b/main.tf
@@ -144,7 +144,7 @@ locals {
}
resource "aws_lambda_permission" "lb" {
- for_each = var.create_lb && local.target_group_attachments_lambda != null ? local.target_group_attachments_lambda : {}
+ for_each = { for k, v in local.target_group_attachments_lambda : k => v if local.create_lb }
function_name = each.value.lambda_function_name
qualifier = try(each.value.lambda_qualifier, null)
@@ -158,7 +158,7 @@ resource "aws_lambda_permission" "lb" {
}
resource "aws_lb_target_group_attachment" "this" {
- for_each = local.create_lb && local.target_group_attachments != null ? local.target_group_attachments : {}
+ for_each = { for k, v in local.target_group_attachments : k => v if local.create_lb }
target_group_arn = aws_lb_target_group.main[each.value.tg_index].arn
target_id = each.value.target_id
diff --git a/versions.tf b/versions.tf
index ef030ea..5f49438 100644
--- a/versions.tf
+++ b/versions.tf
@@ -1,5 +1,5 @@
terraform {
- required_version = ">= 0.13.1"
+ required_version = ">= 1.0.0"
required_providers {
aws = {
diff --git a/wrappers/README.md b/wrappers/README.md
new file mode 100644
index 0000000..909f5ab
--- /dev/null
+++ b/wrappers/README.md
@@ -0,0 +1,100 @@
+# Wrapper for the root module
+
+The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt).
+
+You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module.
+
+This wrapper does not implement any extra functionality.
+
+## Usage with Terragrunt
+
+`terragrunt.hcl`:
+
+```hcl
+terraform {
+ source = "tfr:///terraform-aws-modules/alb/aws//wrappers"
+ # Alternative source:
+ # source = "git::git@github.com:terraform-aws-modules/terraform-aws-alb.git?ref=master//wrappers"
+}
+
+inputs = {
+ defaults = { # Default values
+ create = true
+ tags = {
+ Terraform = "true"
+ Environment = "dev"
+ }
+ }
+
+ items = {
+ my-item = {
+ # omitted... can be any argument supported by the module
+ }
+ my-second-item = {
+ # omitted... can be any argument supported by the module
+ }
+ # omitted...
+ }
+}
+```
+
+## Usage with Terraform
+
+```hcl
+module "wrapper" {
+ source = "terraform-aws-modules/alb/aws//wrappers"
+
+ defaults = { # Default values
+ create = true
+ tags = {
+ Terraform = "true"
+ Environment = "dev"
+ }
+ }
+
+ items = {
+ my-item = {
+ # omitted... can be any argument supported by the module
+ }
+ my-second-item = {
+ # omitted... can be any argument supported by the module
+ }
+ # omitted...
+ }
+}
+```
+
+## Example: Manage multiple S3 buckets in one Terragrunt layer
+
+`eu-west-1/s3-buckets/terragrunt.hcl`:
+
+```hcl
+terraform {
+ source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers"
+ # Alternative source:
+ # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git?ref=master//wrappers"
+}
+
+inputs = {
+ defaults = {
+ force_destroy = true
+
+ attach_elb_log_delivery_policy = true
+ attach_lb_log_delivery_policy = true
+ attach_deny_insecure_transport_policy = true
+ attach_require_latest_tls_policy = true
+ }
+
+ items = {
+ bucket1 = {
+ bucket = "my-random-bucket-1"
+ }
+ bucket2 = {
+ bucket = "my-random-bucket-2"
+ tags = {
+ Secure = "probably"
+ }
+ }
+ }
+}
+```
diff --git a/wrappers/main.tf b/wrappers/main.tf
new file mode 100644
index 0000000..a05a3cd
--- /dev/null
+++ b/wrappers/main.tf
@@ -0,0 +1,42 @@
+module "wrapper" {
+ source = "../"
+
+ for_each = var.items
+
+ create_lb = try(each.value.create_lb, var.defaults.create_lb, true)
+ drop_invalid_header_fields = try(each.value.drop_invalid_header_fields, var.defaults.drop_invalid_header_fields, false)
+ enable_deletion_protection = try(each.value.enable_deletion_protection, var.defaults.enable_deletion_protection, false)
+ enable_http2 = try(each.value.enable_http2, var.defaults.enable_http2, true)
+ enable_cross_zone_load_balancing = try(each.value.enable_cross_zone_load_balancing, var.defaults.enable_cross_zone_load_balancing, false)
+ extra_ssl_certs = try(each.value.extra_ssl_certs, var.defaults.extra_ssl_certs, [])
+ https_listeners = try(each.value.https_listeners, var.defaults.https_listeners, [])
+ http_tcp_listeners = try(each.value.http_tcp_listeners, var.defaults.http_tcp_listeners, [])
+ https_listener_rules = try(each.value.https_listener_rules, var.defaults.https_listener_rules, [])
+ http_tcp_listener_rules = try(each.value.http_tcp_listener_rules, var.defaults.http_tcp_listener_rules, [])
+ idle_timeout = try(each.value.idle_timeout, var.defaults.idle_timeout, 60)
+ ip_address_type = try(each.value.ip_address_type, var.defaults.ip_address_type, "ipv4")
+ listener_ssl_policy_default = try(each.value.listener_ssl_policy_default, var.defaults.listener_ssl_policy_default, "ELBSecurityPolicy-2016-08")
+ internal = try(each.value.internal, var.defaults.internal, false)
+ load_balancer_create_timeout = try(each.value.load_balancer_create_timeout, var.defaults.load_balancer_create_timeout, "10m")
+ load_balancer_delete_timeout = try(each.value.load_balancer_delete_timeout, var.defaults.load_balancer_delete_timeout, "10m")
+ name = try(each.value.name, var.defaults.name, null)
+ name_prefix = try(each.value.name_prefix, var.defaults.name_prefix, null)
+ load_balancer_type = try(each.value.load_balancer_type, var.defaults.load_balancer_type, "application")
+ load_balancer_update_timeout = try(each.value.load_balancer_update_timeout, var.defaults.load_balancer_update_timeout, "10m")
+ access_logs = try(each.value.access_logs, var.defaults.access_logs, {})
+ subnets = try(each.value.subnets, var.defaults.subnets, null)
+ subnet_mapping = try(each.value.subnet_mapping, var.defaults.subnet_mapping, [])
+ tags = try(each.value.tags, var.defaults.tags, {})
+ lb_tags = try(each.value.lb_tags, var.defaults.lb_tags, {})
+ target_group_tags = try(each.value.target_group_tags, var.defaults.target_group_tags, {})
+ https_listener_rules_tags = try(each.value.https_listener_rules_tags, var.defaults.https_listener_rules_tags, {})
+ http_tcp_listener_rules_tags = try(each.value.http_tcp_listener_rules_tags, var.defaults.http_tcp_listener_rules_tags, {})
+ https_listeners_tags = try(each.value.https_listeners_tags, var.defaults.https_listeners_tags, {})
+ http_tcp_listeners_tags = try(each.value.http_tcp_listeners_tags, var.defaults.http_tcp_listeners_tags, {})
+ security_groups = try(each.value.security_groups, var.defaults.security_groups, [])
+ target_groups = try(each.value.target_groups, var.defaults.target_groups, [])
+ vpc_id = try(each.value.vpc_id, var.defaults.vpc_id, null)
+ enable_waf_fail_open = try(each.value.enable_waf_fail_open, var.defaults.enable_waf_fail_open, false)
+ desync_mitigation_mode = try(each.value.desync_mitigation_mode, var.defaults.desync_mitigation_mode, "defensive")
+ putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true)
+}
diff --git a/wrappers/outputs.tf b/wrappers/outputs.tf
new file mode 100644
index 0000000..5da7c09
--- /dev/null
+++ b/wrappers/outputs.tf
@@ -0,0 +1,5 @@
+output "wrapper" {
+ description = "Map of outputs of a wrapper."
+ value = module.wrapper
+ # sensitive = false # No sensitive module output found
+}
diff --git a/wrappers/variables.tf b/wrappers/variables.tf
new file mode 100644
index 0000000..a6ea096
--- /dev/null
+++ b/wrappers/variables.tf
@@ -0,0 +1,11 @@
+variable "defaults" {
+ description = "Map of default values which will be used for each item."
+ type = any
+ default = {}
+}
+
+variable "items" {
+ description = "Maps of items to create a wrapper from. Values are passed through to the module."
+ type = any
+ default = {}
+}
diff --git a/wrappers/versions.tf b/wrappers/versions.tf
new file mode 100644
index 0000000..51cad10
--- /dev/null
+++ b/wrappers/versions.tf
@@ -0,0 +1,3 @@
+terraform {
+ required_version = ">= 0.13.1"
+}