Skip to content

Commit 898448e

Browse files
committed
Rather than fix them, allow certain configurations to produce errors
1 parent e584396 commit 898448e

File tree

9 files changed

+97
-69
lines changed

9 files changed

+97
-69
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,8 @@ Available targets:
350350
| <a name="input_ipv6_cidrs"></a> [ipv6\_cidrs](#input\_ipv6\_cidrs) | Lists of CIDRs to assign to subnets. Order of CIDRs in the lists must not change over time.<br>Lists may contain more CIDRs than needed. | <pre>list(object({<br> private = list(string)<br> public = list(string)<br> }))</pre> | `[]` | no |
351351
| <a name="input_ipv6_egress_only_igw_id"></a> [ipv6\_egress\_only\_igw\_id](#input\_ipv6\_egress\_only\_igw\_id) | The Egress Only Internet Gateway ID the private IPv6 subnets will route traffic to.<br>Used if `private_route_table_enabled` is `true` and `ipv6_enabled` is `true`, ignored otherwise. | `list(string)` | `[]` | no |
352352
| <a name="input_ipv6_enabled"></a> [ipv6\_enabled](#input\_ipv6\_enabled) | Set true to enable IPv6 addresses in the subnets | `bool` | `false` | no |
353-
| <a name="input_ipv6_private_instance_hostnames_enabled"></a> [ipv6\_private\_instance\_hostnames\_enabled](#input\_ipv6\_private\_instance\_hostnames\_enabled) | If `true`, DNS queries for instance hostnames in the private subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
354-
| <a name="input_ipv6_public_instance_hostnames_enabled"></a> [ipv6\_public\_instance\_hostnames\_enabled](#input\_ipv6\_public\_instance\_hostnames\_enabled) | If `true`, DNS queries for instance hostnames in the public subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
353+
| <a name="input_ipv6_private_instance_hostnames_enabled"></a> [ipv6\_private\_instance\_hostnames\_enabled](#input\_ipv6\_private\_instance\_hostnames\_enabled) | If `true` (or if `ipv4_enabled` is false), DNS queries for instance hostnames in the private subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
354+
| <a name="input_ipv6_public_instance_hostnames_enabled"></a> [ipv6\_public\_instance\_hostnames\_enabled](#input\_ipv6\_public\_instance\_hostnames\_enabled) | If `true` (or if `ipv4_enabled` is false), DNS queries for instance hostnames in the public subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
355355
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br>Does not affect keys of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
356356
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
357357
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br>set as tag values, and output by this module individually.<br>Does not affect values of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br>Default value: `lower`. | `string` | `null` | no |
@@ -374,7 +374,7 @@ Available targets:
374374
| <a name="input_open_network_acl_ipv4_rule_number"></a> [open\_network\_acl\_ipv4\_rule\_number](#input\_open\_network\_acl\_ipv4\_rule\_number) | The `rule_no` assigned to the network ACL rules for IPv4 traffic generated by this module | `number` | `100` | no |
375375
| <a name="input_open_network_acl_ipv6_rule_number"></a> [open\_network\_acl\_ipv6\_rule\_number](#input\_open\_network\_acl\_ipv6\_rule\_number) | The `rule_no` assigned to the network ACL rules for IPv6 traffic generated by this module | `number` | `111` | no |
376376
| <a name="input_private_assign_ipv6_address_on_creation"></a> [private\_assign\_ipv6\_address\_on\_creation](#input\_private\_assign\_ipv6\_address\_on\_creation) | If `true`, network interfaces created in a private subnet will be assigned an IPv6 address | `bool` | `true` | no |
377-
| <a name="input_private_dns64_nat64_enabled"></a> [private\_dns64\_nat64\_enabled](#input\_private\_dns64\_nat64\_enabled) | If `true` and IPv6 is enabled, DNS queries made to the Amazon-provided DNS Resolver in private subnets will return synthetic<br>IPv6 addresses for IPv4-only destinations, and these addresses will be routed to the NAT Gateway.<br>Requires `public_subnets_enabled`, `nat_gateway_enabled`, and `private_route_table_enabled` to be `true` to be fully operational. | `bool` | `true` | no |
377+
| <a name="input_private_dns64_nat64_enabled"></a> [private\_dns64\_nat64\_enabled](#input\_private\_dns64\_nat64\_enabled) | If `true` and IPv6 is enabled, DNS queries made to the Amazon-provided DNS Resolver in private subnets will return synthetic<br>IPv6 addresses for IPv4-only destinations, and these addresses will be routed to the NAT Gateway.<br>Requires `public_subnets_enabled`, `nat_gateway_enabled`, and `private_route_table_enabled` to be `true` to be fully operational.<br>Defaults to `true` unless there is no public IPv4 subnet for egress, in which case it defaults to false. | `bool` | `null` | no |
378378
| <a name="input_private_label"></a> [private\_label](#input\_private\_label) | The string to use in IDs and elsewhere to distinguish resources for the private subnets from resources for the public subnets | `string` | `"private"` | no |
379379
| <a name="input_private_open_network_acl_enabled"></a> [private\_open\_network\_acl\_enabled](#input\_private\_open\_network\_acl\_enabled) | If `true`, a single network ACL be created and it will be associated with every private subnet, and a rule (number 100)<br>will be created allowing all ingress and all egress. You can add additional rules to this network ACL<br>using the `aws_network_acl_rule` resource.<br>If `false`, you will will need to manage the network ACL external to this module. | `bool` | `true` | no |
380380
| <a name="input_private_route_table_enabled"></a> [private\_route\_table\_enabled](#input\_private\_route\_table\_enabled) | If true, a network route table and default route to the NAT gateway, NAT instance, or egress-only gateway<br>will be created for each private subnet (1:1). If false, you will need to create your own route table(s) and route(s). | `bool` | `true` | no |

docs/terraform.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@
9191
| <a name="input_ipv6_cidrs"></a> [ipv6\_cidrs](#input\_ipv6\_cidrs) | Lists of CIDRs to assign to subnets. Order of CIDRs in the lists must not change over time.<br>Lists may contain more CIDRs than needed. | <pre>list(object({<br> private = list(string)<br> public = list(string)<br> }))</pre> | `[]` | no |
9292
| <a name="input_ipv6_egress_only_igw_id"></a> [ipv6\_egress\_only\_igw\_id](#input\_ipv6\_egress\_only\_igw\_id) | The Egress Only Internet Gateway ID the private IPv6 subnets will route traffic to.<br>Used if `private_route_table_enabled` is `true` and `ipv6_enabled` is `true`, ignored otherwise. | `list(string)` | `[]` | no |
9393
| <a name="input_ipv6_enabled"></a> [ipv6\_enabled](#input\_ipv6\_enabled) | Set true to enable IPv6 addresses in the subnets | `bool` | `false` | no |
94-
| <a name="input_ipv6_private_instance_hostnames_enabled"></a> [ipv6\_private\_instance\_hostnames\_enabled](#input\_ipv6\_private\_instance\_hostnames\_enabled) | If `true`, DNS queries for instance hostnames in the private subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
95-
| <a name="input_ipv6_public_instance_hostnames_enabled"></a> [ipv6\_public\_instance\_hostnames\_enabled](#input\_ipv6\_public\_instance\_hostnames\_enabled) | If `true`, DNS queries for instance hostnames in the public subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
94+
| <a name="input_ipv6_private_instance_hostnames_enabled"></a> [ipv6\_private\_instance\_hostnames\_enabled](#input\_ipv6\_private\_instance\_hostnames\_enabled) | If `true` (or if `ipv4_enabled` is false), DNS queries for instance hostnames in the private subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
95+
| <a name="input_ipv6_public_instance_hostnames_enabled"></a> [ipv6\_public\_instance\_hostnames\_enabled](#input\_ipv6\_public\_instance\_hostnames\_enabled) | If `true` (or if `ipv4_enabled` is false), DNS queries for instance hostnames in the public subnets will be answered with AAAA (IPv6) records. | `bool` | `false` | no |
9696
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br>Does not affect keys of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
9797
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
9898
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br>set as tag values, and output by this module individually.<br>Does not affect values of tags passed in via the `tags` input.<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br>Default value: `lower`. | `string` | `null` | no |
@@ -115,7 +115,7 @@
115115
| <a name="input_open_network_acl_ipv4_rule_number"></a> [open\_network\_acl\_ipv4\_rule\_number](#input\_open\_network\_acl\_ipv4\_rule\_number) | The `rule_no` assigned to the network ACL rules for IPv4 traffic generated by this module | `number` | `100` | no |
116116
| <a name="input_open_network_acl_ipv6_rule_number"></a> [open\_network\_acl\_ipv6\_rule\_number](#input\_open\_network\_acl\_ipv6\_rule\_number) | The `rule_no` assigned to the network ACL rules for IPv6 traffic generated by this module | `number` | `111` | no |
117117
| <a name="input_private_assign_ipv6_address_on_creation"></a> [private\_assign\_ipv6\_address\_on\_creation](#input\_private\_assign\_ipv6\_address\_on\_creation) | If `true`, network interfaces created in a private subnet will be assigned an IPv6 address | `bool` | `true` | no |
118-
| <a name="input_private_dns64_nat64_enabled"></a> [private\_dns64\_nat64\_enabled](#input\_private\_dns64\_nat64\_enabled) | If `true` and IPv6 is enabled, DNS queries made to the Amazon-provided DNS Resolver in private subnets will return synthetic<br>IPv6 addresses for IPv4-only destinations, and these addresses will be routed to the NAT Gateway.<br>Requires `public_subnets_enabled`, `nat_gateway_enabled`, and `private_route_table_enabled` to be `true` to be fully operational. | `bool` | `true` | no |
118+
| <a name="input_private_dns64_nat64_enabled"></a> [private\_dns64\_nat64\_enabled](#input\_private\_dns64\_nat64\_enabled) | If `true` and IPv6 is enabled, DNS queries made to the Amazon-provided DNS Resolver in private subnets will return synthetic<br>IPv6 addresses for IPv4-only destinations, and these addresses will be routed to the NAT Gateway.<br>Requires `public_subnets_enabled`, `nat_gateway_enabled`, and `private_route_table_enabled` to be `true` to be fully operational.<br>Defaults to `true` unless there is no public IPv4 subnet for egress, in which case it defaults to false. | `bool` | `null` | no |
119119
| <a name="input_private_label"></a> [private\_label](#input\_private\_label) | The string to use in IDs and elsewhere to distinguish resources for the private subnets from resources for the public subnets | `string` | `"private"` | no |
120120
| <a name="input_private_open_network_acl_enabled"></a> [private\_open\_network\_acl\_enabled](#input\_private\_open\_network\_acl\_enabled) | If `true`, a single network ACL be created and it will be associated with every private subnet, and a rule (number 100)<br>will be created allowing all ingress and all egress. You can add additional rules to this network ACL<br>using the `aws_network_acl_rule` resource.<br>If `false`, you will will need to manage the network ACL external to this module. | `bool` | `true` | no |
121121
| <a name="input_private_route_table_enabled"></a> [private\_route\_table\_enabled](#input\_private\_route\_table\_enabled) | If true, a network route table and default route to the NAT gateway, NAT instance, or egress-only gateway<br>will be created for each private subnet (1:1). If false, you will need to create your own route table(s) and route(s). | `bool` | `true` | no |

examples/existing-ips/outputs.tf

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
output "existing_ips" {
2-
value = aws_eip.nat_ips.*.public_ip
2+
description = "IP Addresses created by this module for use by NAT"
3+
value = aws_eip.nat_ips.*.public_ip
34
}
45

56
output "nat_ips" {
6-
value = module.subnets.nat_ips
7-
}
7+
description = "IP Addresses in use by NAT"
8+
value = module.subnets.nat_ips
9+
}

main.tf

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,11 @@ locals {
134134
private4_enabled = local.private_enabled && local.ipv4_enabled
135135
private6_enabled = local.private_enabled && local.ipv6_enabled
136136

137-
public_dns64_enabled = local.public6_enabled && var.public_dns64_nat64_enabled
138-
private_dns64_enabled = local.private6_enabled && var.private_dns64_nat64_enabled
137+
public_dns64_enabled = local.public6_enabled && var.public_dns64_nat64_enabled
138+
# Set the default for private_dns64_enabled to true unless there is no IPv4 egress to enable it.
139+
private_dns64_enabled = local.private6_enabled && (
140+
var.private_dns64_nat64_enabled == null ? local.public4_enabled : var.private_dns64_nat64_enabled
141+
)
139142

140143
public_route_table_enabled = local.public_enabled && var.public_route_table_enabled
141144
# Use `coalesce` to pick the highest priority value (null means go to next test)
@@ -165,12 +168,12 @@ locals {
165168
# Support deprecated var.private_network_acl_id
166169
private_open_network_acl_enabled = local.private_enabled && var.private_open_network_acl_enabled
167170

168-
# A NAT device is needed to NAT from private IPv4 to public IPv4 or to perform NAT64 for IPv6,
169-
# but since it must be placed in a public subnet, we consider it not required if we are not creating public subnets.
170-
nat_required = local.public_enabled && (local.private4_enabled || local.public_dns64_enabled)
171-
nat_count = min(local.subnet_az_count, var.max_nats)
172-
171+
# A NAT device is needed to NAT from private IPv4 to public IPv4 or to perform NAT64 for IPv6.
173172
# An AWS NAT instance does not perform NAT64, and we choose not to try to support NAT64 via NAT instances at this time.
173+
nat_instance_useful = local.private4_enabled
174+
nat_gateway_useful = local.nat_instance_useful || local.public_dns64_enabled || local.private_dns64_enabled
175+
nat_count = min(local.subnet_az_count, var.max_nats)
176+
174177
# It does not make sense to create both a NAT Gateway and a NAT instance, since they perform the same function
175178
# and occupy the same slot in a network routing table. Rather than try to create both,
176179
# we favor the more powerful NAT Gateway over the deprecated NAT Instance.
@@ -181,8 +184,11 @@ locals {
181184
)
182185
nat_instance_setting = local.nat_gateway_setting ? false : var.nat_instance_enabled == true # not false or null
183186

184-
nat_gateway_enabled = local.nat_required && local.nat_gateway_setting
185-
nat_instance_enabled = local.public_enabled && local.private4_enabled && local.nat_instance_setting
187+
# We suppress creating NATs if not useful, but choose to attempt to create NATs
188+
# when useful even if we know they will fail (e.g. due to no public subnets)
189+
# to provide useful feedback to users.
190+
nat_gateway_enabled = local.nat_gateway_useful && local.nat_gateway_setting
191+
nat_instance_enabled = local.nat_instance_useful && local.nat_instance_setting
186192
nat_enabled = local.nat_gateway_enabled || local.nat_instance_enabled
187193
need_nat_eips = local.nat_enabled && length(var.nat_elastic_ips) == 0
188194
need_nat_eip_data = local.nat_enabled && length(var.nat_elastic_ips) > 0

nat-gateway.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ resource "aws_nat_gateway" "default" {
2424
}
2525

2626
resource "aws_route" "nat4" {
27-
count = local.nat_gateway_enabled && local.ipv4_enabled ? local.private_route_table_count : 0
27+
count = local.nat_gateway_enabled && local.private4_enabled ? local.private_route_table_count : 0
2828

2929
route_table_id = local.private_route_table_ids[count.index]
3030
nat_gateway_id = element(aws_nat_gateway.default.*.id, count.index)

outputs.tf

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,27 @@ output "private_subnet_ids" {
2020
value = aws_subnet.private.*.id
2121
}
2222

23+
# Provide some consistency in CDIR outputs by always returning a list.
24+
# Avoid (or at least reduce) `count` problems by toggling the return
25+
# value via configuration rather than computing it via `compact()`.
2326
output "public_subnet_cidrs" {
2427
description = "IPv4 CIDR blocks of the created public subnets"
25-
value = aws_subnet.public.*.cidr_block
28+
value = local.public4_enabled ? aws_subnet.public.*.cidr_block : []
2629
}
2730

2831
output "public_subnet_ipv6_cidrs" {
2932
description = "IPv6 CIDR blocks of the created public subnets"
30-
value = aws_subnet.public.*.ipv6_cidr_block
33+
value = local.public6_enabled ? aws_subnet.public.*.ipv6_cidr_block : []
3134
}
3235

3336
output "private_subnet_cidrs" {
3437
description = "IPv4 CIDR blocks of the created private subnets"
35-
value = aws_subnet.private.*.cidr_block
38+
value = local.private4_enabled ? aws_subnet.private.*.cidr_block : []
3639
}
3740

3841
output "private_subnet_ipv6_cidrs" {
3942
description = "IPv6 CIDR blocks of the created private subnets"
40-
value = aws_subnet.private.*.ipv6_cidr_block
43+
value = local.private6_enabled ? aws_subnet.private.*.ipv6_cidr_block : []
4144
}
4245

4346
output "public_route_table_ids" {

0 commit comments

Comments
 (0)