Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
10ed599
conditional dns resolution binding
rajatagarwal-ibm Jun 26, 2025
d54cc06
conditional dns resolution binding
rajatagarwal-ibm Jun 26, 2025
f466278
conditional dns resolution binding
rajatagarwal-ibm Jun 26, 2025
55dd671
conditional dns resolution binding
rajatagarwal-ibm Jun 26, 2025
4d08eb8
conditional dns resolution binding
rajatagarwal-ibm Jun 27, 2025
06558a5
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jun 27, 2025
e3c05ed
conditional dns resolution binding
rajatagarwal-ibm Jun 27, 2025
e7cc328
Merge branch 'conditional-dns-resolution-binding' of github.com:terra…
rajatagarwal-ibm Jun 27, 2025
f5fc4d2
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jul 1, 2025
ace186b
conditional dns resolution binding
rajatagarwal-ibm Jul 14, 2025
8644cec
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jul 14, 2025
f9ade8a
conditional dns resolution binding
rajatagarwal-ibm Jul 14, 2025
152ab39
Merge branch 'main' of github.com:terraform-ibm-modules/terraform-ibm…
rajatagarwal-ibm Jul 14, 2025
f1b57ac
Merge branch 'conditional-dns-resolution-binding' of github.com:terra…
rajatagarwal-ibm Jul 14, 2025
e7fcfab
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jul 18, 2025
7507775
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jul 21, 2025
f34a1ee
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Jul 22, 2025
e8a8c1f
conditional dns resolution binding
rajatagarwal-ibm Jul 22, 2025
11e385c
conditional dns resolution binding
rajatagarwal-ibm Jul 22, 2025
5ee0e63
Merge branch 'main' into conditional-dns-resolution-binding
vburckhardt Jul 28, 2025
63bc7a8
conditional dns resolution binding
rajatagarwal-ibm Jul 31, 2025
49d565e
Merge branch 'conditional-dns-resolution-binding' of github.com:terra…
rajatagarwal-ibm Jul 31, 2025
ea603d3
conditional dns resolution binding
rajatagarwal-ibm Jul 31, 2025
8f980a6
conditional dns resolution binding
rajatagarwal-ibm Aug 1, 2025
e1592db
conditional dns resolution binding
rajatagarwal-ibm Aug 1, 2025
7c359d1
conditional dns resolution binding
rajatagarwal-ibm Aug 1, 2025
1350e3c
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Aug 1, 2025
8923faa
Merge branch 'main' into conditional-dns-resolution-binding
rajatagarwal-ibm Aug 5, 2025
85d0c66
conditional dns resolution binding
rajatagarwal-ibm Aug 6, 2025
ecf5243
Merge branch 'conditional-dns-resolution-binding' of github.com:terra…
rajatagarwal-ibm Aug 6, 2025
a526830
conditional dns resolution binding
rajatagarwal-ibm Aug 6, 2025
56d8cfd
Merge branch 'main' into conditional-dns-resolution-binding
vburckhardt Aug 11, 2025
3e662e1
conditional dns resolution binding
rajatagarwal-ibm Aug 12, 2025
7435314
Merge branch 'conditional-dns-resolution-binding' of github.com:terra…
rajatagarwal-ibm Aug 12, 2025
2efc708
docs: improve message
vburckhardt Aug 12, 2025
73f1237
docs: improve message
vburckhardt Aug 12, 2025
3870b2d
docs: improve message
vburckhardt Aug 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ This module creates the following IBM Cloud® Virtual Private Cloud (VPC) net

![vpc-module](https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/.docs/vpc-module.png)



### Upgrade notice for Hub-and-Spoke topology users (version 8.0.0 and above)

> **Note:** This upgrade notice applies **only** to users of the advanced Hub-and-Spoke VPC topology who are upgrading from a previous version of this module to v8.0.0 or later. If you are using the standard topology, or a new user starting with v8.0.0 or above, you can safely ignore this section.

If you are upgrading, note that the `ibm_is_vpc_dns_resolution_binding` resources are no longer used for DNS resolution binding with the `Delegated` resolver type.

- Upgrade to the latest module (>= `v8.0.0`).
- Set `update_delegated_resolver = true` in your Terraform configuration (along with any other input parameters you previously used) and run `terraform apply` to re-create the DNS resolution binding with the `Delegated` resolver type. For example:

```bash
terraform apply -var="update_delegated_resolver=true"
```

Expected network connectivity downtime of typically around 20 seconds.

<!-- Below content is automatically populated via pre-commit hook -->
<!-- BEGIN OVERVIEW HOOK -->
## Overview
Expand Down Expand Up @@ -177,6 +194,7 @@ To attach access management tags to resources in this module, you need the follo
| [ibm_is_subnet.subnet](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_subnet) | data source |
| [ibm_is_vpc.vpc](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc) | data source |
| [ibm_is_vpc_address_prefixes.get_address_prefixes](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc_address_prefixes) | data source |
| [ibm_is_vpc_dns_resolution_bindings.dns_bindings](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_vpc_dns_resolution_bindings) | data source |

### Inputs

Expand Down Expand Up @@ -220,7 +238,7 @@ To attach access management tags to resources in this module, you need the follo
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The value that you would like to prefix to the name of the resources provisioned by this module. Explicitly set to null if you do not wish to use a prefix. This value is ignored if using one of the optional variables for explicit control over naming. | `string` | `null` | no |
| <a name="input_public_gateway_name"></a> [public\_gateway\_name](#input\_public\_gateway\_name) | The name to give the provisioned VPC public gateways. If not set, the module generates a name based on the `prefix` and `name` variables. | `string` | `null` | no |
| <a name="input_region"></a> [region](#input\_region) | The region to which to deploy the VPC | `string` | n/a | yes |
| <a name="input_resolver_type"></a> [resolver\_type](#input\_resolver\_type) | Resolver type. Can be system or manual. For delegated resolver type, see the update\_delegated\_resolver variable instead. | `string` | `null` | no |
| <a name="input_resolver_type"></a> [resolver\_type](#input\_resolver\_type) | Resolver type. Can be system or manual or delegated. | `string` | `null` | no |
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the VPC to be created | `string` | n/a | yes |
| <a name="input_routes"></a> [routes](#input\_routes) | OPTIONAL - Allows you to specify the next hop for packets based on their destination address | <pre>list(<br/> object({<br/> name = string<br/> route_direct_link_ingress = optional(bool)<br/> route_transit_gateway_ingress = optional(bool)<br/> route_vpc_zone_ingress = optional(bool)<br/> routes = optional(<br/> list(<br/> object({<br/> action = optional(string)<br/> zone = number<br/> destination = string<br/> next_hop = string<br/> })<br/> ))<br/> })<br/> )</pre> | `[]` | no |
| <a name="input_routing_table_name"></a> [routing\_table\_name](#input\_routing\_table\_name) | The name to give the provisioned routing tables. If not set, the module generates a name based on the `prefix` and `name` variables. | `string` | `null` | no |
Expand All @@ -242,8 +260,8 @@ To attach access management tags to resources in this module, you need the follo
| <a name="output_cidr_blocks"></a> [cidr\_blocks](#output\_cidr\_blocks) | List of CIDR blocks present in VPC stack |
| <a name="output_custom_resolver_hub"></a> [custom\_resolver\_hub](#output\_custom\_resolver\_hub) | The custom resolver created for the hub vpc. Only set if enable\_hub is set and skip\_custom\_resolver\_hub\_creation is false. |
| <a name="output_dns_custom_resolver_id"></a> [dns\_custom\_resolver\_id](#output\_dns\_custom\_resolver\_id) | The ID of the DNS Custom Resolver. |
| <a name="output_dns_endpoint_gateways_by_crn"></a> [dns\_endpoint\_gateways\_by\_crn](#output\_dns\_endpoint\_gateways\_by\_crn) | The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id are true. |
| <a name="output_dns_endpoint_gateways_by_id"></a> [dns\_endpoint\_gateways\_by\_id](#output\_dns\_endpoint\_gateways\_by\_id) | The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id are true. |
| <a name="output_dns_endpoint_gateways_by_crn"></a> [dns\_endpoint\_gateways\_by\_crn](#output\_dns\_endpoint\_gateways\_by\_crn) | The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id OR enable\_hub\_vpc\_crn are true. |
| <a name="output_dns_endpoint_gateways_by_id"></a> [dns\_endpoint\_gateways\_by\_id](#output\_dns\_endpoint\_gateways\_by\_id) | The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable\_hub is false and enable\_hub\_vpc\_id OR enable\_hub\_vpc\_crn are true. |
| <a name="output_dns_instance_id"></a> [dns\_instance\_id](#output\_dns\_instance\_id) | The ID of the DNS instance. |
| <a name="output_dns_record_ids"></a> [dns\_record\_ids](#output\_dns\_record\_ids) | List of all the domain resource records. |
| <a name="output_dns_zone"></a> [dns\_zone](#output\_dns\_zone) | A map representing DNS zone information. |
Expand Down
2 changes: 0 additions & 2 deletions examples/hub-spoke-delegated-resolver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@ This example demonstrates how to deploy hub and spoke VPCs, inclusive of enablin
1. The first terraform apply lay down all of the topology, but does not configure the DNS resolver to delegated in the spoke
2. The second terraform apply should have the update_delegated_resolver variable to true to configure the DNS resolver to be delegated ```terraform apply -var=update_delegated_resolver=true```

In order to perform a successful destroy, please set to the resolver to "system" in the spoke VPC through the UI before issuing the terraform destroy - see https://cloud.ibm.com/docs/solution-tutorials?topic=solution-tutorials-vpc-transit2

You may also be interested in the [Hub and Spoke VPC with manual DNS resolver Example](../hub-spoke-manual-resolver/) which does not exhibit those issues.
1 change: 1 addition & 0 deletions examples/hub-spoke-delegated-resolver/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ module "spoke_vpc" {
hub_account_id = data.ibm_iam_account_settings.iam_account_settings.account_id
hub_vpc_crn = module.hub_vpc.vpc_crn
enable_hub_vpc_crn = true
resolver_type = "delegated"
update_delegated_resolver = var.update_delegated_resolver
subnets = {
zone-1 = [
Expand Down
18 changes: 14 additions & 4 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,15 @@ resource "ibm_is_vpc" "vpc" {

# Delegated resolver
dynamic "resolver" {
for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver ? [1] : []
for_each = (var.enable_hub_vpc_id || var.enable_hub_vpc_crn) && var.update_delegated_resolver && var.resolver_type == "delegated" ? [1] : []
content {
type = "delegated"
vpc_id = var.hub_vpc_id != null ? var.hub_vpc_id : null
vpc_crn = var.hub_vpc_crn != null ? var.hub_vpc_crn : null
dns_binding_name = coalesce(
var.dns_binding_name,
"${var.prefix != null ? "${var.prefix}-${var.name}" : var.name}-dns-binding"
)
}
}

Expand Down Expand Up @@ -78,6 +82,11 @@ resource "ibm_is_vpc" "vpc" {
}
}

data "ibm_is_vpc_dns_resolution_bindings" "dns_bindings" {
count = (!var.enable_hub && (var.enable_hub_vpc_id || var.enable_hub_vpc_crn)) ? 1 : 0
vpc_id = local.vpc_id
}

###############################################################################

##############################################################################
Expand Down Expand Up @@ -124,9 +133,9 @@ resource "ibm_iam_authorization_policy" "vpc_dns_resolution_auth_policy" {
}
}

# Enable Hub to dns resolve in spoke VPC
# Set up separate DNS resolution binding in case the resolver type is NOT delegated.
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
count = (var.enable_hub == false && var.enable_hub_vpc_id) ? 1 : 0
count = (var.enable_hub == false && var.enable_hub_vpc_id) && var.resolver_type != "delegated" ? 1 : 0
# Depends on required as the authorization policy cannot be directly referenced
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]

Expand All @@ -141,8 +150,9 @@ resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_id" {
}
}

# Set up separate DNS resolution binding in case the resolver type is NOT delegated.
resource "ibm_is_vpc_dns_resolution_binding" "vpc_dns_resolution_binding_crn" {
count = (var.enable_hub == false && var.enable_hub_vpc_crn) ? 1 : 0
count = (var.enable_hub == false && var.enable_hub_vpc_crn) && var.resolver_type != "delegated" ? 1 : 0
# Depends on required as the authorization policy cannot be directly referenced
depends_on = [ibm_iam_authorization_policy.vpc_dns_resolution_auth_policy]

Expand Down
8 changes: 4 additions & 4 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ output "custom_resolver_hub" {
}

output "dns_endpoint_gateways_by_id" {
description = "The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable_hub is false and enable_hub_vpc_id are true."
value = length(ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_id) == 1 ? ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_id[0] : null
description = "The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable_hub is false and enable_hub_vpc_id OR enable_hub_vpc_crn are true."
value = try(length(data.ibm_is_vpc_dns_resolution_bindings.dns_bindings) == 1 ? data.ibm_is_vpc_dns_resolution_bindings.dns_bindings[0].dns_resolution_bindings[0].vpc[0].id : null, null)
}

output "dns_endpoint_gateways_by_crn" {
description = "The list of VPEs that are made available for DNS resolution in the created VPC. Only set if enable_hub is false and enable_hub_vpc_id are true."
value = length(ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_crn) == 1 ? ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_crn[0] : null
description = "The list of VPEs that are made available for DNS resolution in the created Spoke VPC. Only set if enable_hub is false and enable_hub_vpc_id OR enable_hub_vpc_crn are true."
value = try(length(data.ibm_is_vpc_dns_resolution_bindings.dns_bindings) == 1 ? data.ibm_is_vpc_dns_resolution_bindings.dns_bindings[0].dns_resolution_bindings[0].vpc[0].crn : null, null)
}

output "dns_instance_id" {
Expand Down
16 changes: 0 additions & 16 deletions tests/other_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,6 @@ func TestRunBasicExample(t *testing.T) {
assert.NotNil(t, output, "Expected some output")
}

func TestRunHubAndSpokeDelegatedExample(t *testing.T) {
t.Parallel()

options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
Testing: t,
TerraformDir: hubAndSpokeDelegatedExampleTerraformDir,
Prefix: "has-slz",
ResourceGroup: resourceGroup,
Region: "us-south",
})

output, err := options.RunTestConsistency()
assert.Nil(t, err, "This should not have errored")
assert.NotNil(t, output, "Expected some output")
}

func TestRunSpecificZoneExample(t *testing.T) {
t.Parallel()

Expand Down
22 changes: 22 additions & 0 deletions tests/pr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,25 @@ func TestRunUpgradeFullyConfigurable(t *testing.T) {
assert.Nil(t, err, "This should not have errored")
}
}

func TestRunHubAndSpokeDelegatedExample(t *testing.T) {
t.Parallel()

options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
Testing: t,
TerraformDir: hubAndSpokeDelegatedExampleTerraformDir,
Prefix: "has-slz",
ResourceGroup: resourceGroup,
Region: "us-south",
PostApplyHook: func(options *testhelper.TestOptions) error {
terraformOptions := options.TerraformOptions
terraformOptions.Vars["update_delegated_resolver"] = true
_, err := terraform.ApplyE(options.Testing, terraformOptions)
return err
},
})

output, err := options.RunTestConsistency()
assert.Nil(t, err, "This should not have errored")
assert.NotNil(t, output, "Expected some output")
}
9 changes: 5 additions & 4 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,8 @@ variable "update_delegated_resolver" {
default = false

validation {
condition = !(var.update_delegated_resolver == true && var.resolver_type != null)
error_message = "var.resolver_type cannot be set if var.update_delegated_resolver is true. Only one type of resolver can be created by VPC."
condition = !(var.update_delegated_resolver == true && var.resolver_type != "delegated")
error_message = "If var.update_delegated_resolver is true then var.resolver_type must be set to 'delegated'."
}
}

Expand All @@ -665,16 +665,17 @@ variable "use_existing_dns_instance" {
}

variable "resolver_type" {
description = "Resolver type. Can be system or manual. For delegated resolver type, see the update_delegated_resolver variable instead. "
description = "Resolver type. Can be system or manual or delegated."
type = string
default = null
validation {
condition = anytrue([
var.resolver_type == null,
var.resolver_type == "system",
var.resolver_type == "manual",
var.resolver_type == "delegated"
])
error_message = "`resolver_type` can either be null, or set to the string 'system' or 'manual'."
error_message = "`resolver_type` can either be null, or set to the string 'system', 'delegated' or 'manual'."
}
}

Expand Down