diff --git a/README.md b/README.md index 849f3b8..91a9937 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This module includes the `terraform-ibm-transit-gateway-action` [approval action * [terraform-ibm-transit-gateway-action](./modules/terraform-ibm-transit-gateway-action) * [Examples](./examples) * [ Example transit gateway that connects two VPCs in two accounts](./examples/crossaccounts) + * [ Example transit gateway that connects two VPCs with prefix filtering](./examples/add-prefix-filter) * [ Example transit gateway that connects two VPCs](./examples/two-vpcs) * [Example basic transit gateway](./examples/basic) * [Contributing](#contributing) @@ -65,7 +66,7 @@ You need the following permissions to run this module. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0 | -| [ibm](#requirement\_ibm) | >= 1.52.0, < 2.0.0 | +| [ibm](#requirement\_ibm) | >= 1.69.0, < 2.0.0 | ### Modules @@ -77,6 +78,7 @@ No modules. |------|------| | [ibm_tg_connection.classic_connections](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/tg_connection) | resource | | [ibm_tg_connection.vpc_connections](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/tg_connection) | resource | +| [ibm_tg_connection_prefix_filter.add_prefix_filter](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/tg_connection_prefix_filter) | resource | | [ibm_tg_gateway.tg_gw_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/tg_gateway) | resource | | [ibm_tg_gateway.existing_tg_gw_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/tg_gateway) | data source | @@ -84,6 +86,7 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [add\_prefix\_filters](#input\_add\_prefix\_filters) | Map of VPC CRN to optionally add prefix filter to set an ordered list of filters that determine the routes that transit gateway should accept or deny. Connections are denied or permitted based on the order of the filters passed. See https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui |
list(object({
action = string
prefix = string
le = optional(number)
ge = optional(number)
before = optional(string)
connection = string
}))
| `[]` | no | | [classic\_connections\_count](#input\_classic\_connections\_count) | Number of classic connections to add. | `number` | n/a | yes | | [delete\_timeout](#input\_delete\_timeout) | Deleting timeout value of the ibm\_tg\_gateway | `string` | `"45m"` | no | | [existing\_transit\_gateway\_name](#input\_existing\_transit\_gateway\_name) | Name of an existing transit gateway to connect VPCs. If null a new Transit Gateway will be created (transit\_gateway\_name and region required) | `string` | `null` | no | @@ -92,13 +95,14 @@ No modules. | [resource\_group\_id](#input\_resource\_group\_id) | Resource group ID where the transit gateway to be created. | `string` | `null` | no | | [resource\_tags](#input\_resource\_tags) | List of tags | `list(string)` | `null` | no | | [transit\_gateway\_name](#input\_transit\_gateway\_name) | Name of the transit gateway to create. It can be null if existing\_transit\_gateway\_name is not null | `string` | `null` | no | -| [vpc\_connections](#input\_vpc\_connections) | The list of vpc instance resource\_crn to add network connections for. | `list(string)` | n/a | yes | +| [vpc\_connections](#input\_vpc\_connections) | The list of VPC instance connections with their associated default prefix filter. Customise the default filter setting for each VPC connections to `permit` or `deny` specifiv IP ranges. `permit` makes it to accept all prefixes after processing all the entries in the prefix filters list. `deny` makes it to deny all prefixes after processing all the entries in the prefix filters list. By default it is set to `permit`. Refer to https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui for more details. |
list(object({
vpc_crn = string
default_prefix_filter = optional(string)
}))
| n/a | yes | ### Outputs | Name | Description | |------|-------------| | [classic\_conn\_ids](#output\_classic\_conn\_ids) | List of classic connection IDs | +| [filter\_ids](#output\_filter\_ids) | Prefix filter IDs | | [tg\_crn](#output\_tg\_crn) | CRN of the gateway | | [tg\_id](#output\_tg\_id) | The ID of the transit gateway | | [vpc\_conn\_ids](#output\_vpc\_conn\_ids) | List of VPC connection IDs | diff --git a/examples/add-prefix-filter/README.md b/examples/add-prefix-filter/README.md new file mode 100644 index 0000000..18b406e --- /dev/null +++ b/examples/add-prefix-filter/README.md @@ -0,0 +1,13 @@ +# Example transit gateway that connects two VPCs with prefix filtering + +This example provisions two VPCs and a transit gateway that configures connectivity between them. + +Add prefix filtering that determine the routes that transit gateway should accept or deny. + +**Explanation:** +- Prefix filters can be used to permit or deny specific specific IP address ranges (called prefixes) on specific network connections. +- This helps to allow only traffic from trusted networks and block unwanted traffic from certain ranges. +- In this example, once deployed- + - For both VPC connections vpc_conn_inst1 and vpc_conn_inst2, prefix filter will be created. + - For VPC connection vpc_conn_inst1, default_prefix_filter is set to `permit` and prefix filters are `allow` 10.10.10.0/24 but `deny` 10.20.10.0/24. This means after processing the entries in the prefix filter list (allow 10.10.10.0/24 and deny 10.20.10.0/24) it accepts rest of the IP addresses. + - For VPC connection vpc_conn_inst2, default_prefix_filter is set to `deny` and prefix filters is `allow` 10.20.10.0/24. This means after processing the entries in the prefix filter list (allow 10.20.10.0/24) it denies rest of the IP addresses. diff --git a/examples/add-prefix-filter/main.tf b/examples/add-prefix-filter/main.tf new file mode 100644 index 0000000..6a5eacd --- /dev/null +++ b/examples/add-prefix-filter/main.tf @@ -0,0 +1,92 @@ +############################################################################## +# Resource Group +############################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +############################################################################## +# 2 VPCs +############################################################################## + +module "vpc_1" { + source = "terraform-ibm-modules/landing-zone-vpc/ibm" + version = "7.19.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + prefix = var.prefix + tags = var.resource_tags + name = "${var.prefix}-vpc1" + use_public_gateways = { + zone-1 = false + zone-2 = false + zone-3 = false + } +} + +module "vpc_2" { + source = "terraform-ibm-modules/landing-zone-vpc/ibm" + version = "7.19.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + prefix = var.prefix + tags = var.resource_tags + name = "${var.prefix}-vpc2" + use_public_gateways = { + zone-1 = false + zone-2 = false + zone-3 = false + } +} + +############################################################################## +# Transit Gateway connects the 2 VPCs with prefix filters +############################################################################## + +module "tg_gateway_connection" { + source = "../.." + transit_gateway_name = var.transit_gateway_name + region = var.region + global_routing = false + resource_tags = var.resource_tags + resource_group_id = module.resource_group.resource_group_id + classic_connections_count = 0 + vpc_connections = [ + { + vpc_crn = module.vpc_1.vpc_crn + default_prefix_filter = "permit" + }, + { + vpc_crn = module.vpc_2.vpc_crn + default_prefix_filter = "deny" + } + ] + add_prefix_filters = [ + { + action = "permit" + prefix = "10.10.10.0/24" + le = 24 + ge = 24 + connection = module.vpc_1.vpc_crn + }, + { + action = "deny" + prefix = "10.20.10.0/24" + le = 24 + ge = 24 + connection = module.vpc_1.vpc_crn + }, + { + action = "permit" + prefix = "10.20.10.0/24" + le = 24 + ge = 24 + connection = module.vpc_2.vpc_crn + } + ] +} diff --git a/examples/add-prefix-filter/outputs.tf b/examples/add-prefix-filter/outputs.tf new file mode 100644 index 0000000..1ea53d1 --- /dev/null +++ b/examples/add-prefix-filter/outputs.tf @@ -0,0 +1,13 @@ +############################################################################## +# Outputs +############################################################################## + +output "tg_id" { + description = "The ID of the transit gateway" + value = module.tg_gateway_connection.tg_id +} + +output "filter_ids" { + description = "Prefix filter IDs" + value = module.tg_gateway_connection.filter_ids +} diff --git a/examples/add-prefix-filter/provider.tf b/examples/add-prefix-filter/provider.tf new file mode 100644 index 0000000..df45ef5 --- /dev/null +++ b/examples/add-prefix-filter/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/examples/add-prefix-filter/variables.tf b/examples/add-prefix-filter/variables.tf new file mode 100644 index 0000000..f193ab4 --- /dev/null +++ b/examples/add-prefix-filter/variables.tf @@ -0,0 +1,32 @@ +variable "ibmcloud_api_key" { + description = "API key that is associated with the account to provision resources to" + type = string + sensitive = true +} + +variable "prefix" { + description = "The prefix to append to your resources" + type = string +} + +variable "transit_gateway_name" { + description = "Name of the transit gateway" + type = string +} + +variable "region" { + description = "Location of the transit gateway." + type = string +} + +variable "resource_group" { + type = string + description = "An existing resource group name to use for this example. If not set, a new resource group is created." + default = null +} + +variable "resource_tags" { + type = list(string) + description = "List of tags" + default = null +} diff --git a/examples/add-prefix-filter/versions.tf b/examples/add-prefix-filter/versions.tf new file mode 100644 index 0000000..ef3a884 --- /dev/null +++ b/examples/add-prefix-filter/versions.tf @@ -0,0 +1,11 @@ +terraform { + required_version = ">= 1.0.0" + # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (basic), and 1 example that will always use the latest provider version. + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.69.0" + } + } +} diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index d1a953c..57a2bab 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -32,8 +32,11 @@ variable "global_routing" { } variable "vpc_connections" { - type = list(string) - description = "The list of vpc instance resource_crn to add network connections for." + type = list(object({ + vpc_crn = string + default_prefix_filter = string + })) + description = "The list of VPC instance connections with their associated default prefix filter. Customise the default filter setting for each VPC connections to `permit` or `deny` specifiv IP ranges. `permit` makes it to accept all prefixes after processing all the entries in the prefix filters list. `deny` makes it to deny all prefixes after processing all the entries in the prefix filters list. By default it is set to `permit`. Refer to https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui for more details." } variable "classic_connections_count" { diff --git a/examples/basic/versions.tf b/examples/basic/versions.tf index 3ca3293..8be80ba 100644 --- a/examples/basic/versions.tf +++ b/examples/basic/versions.tf @@ -5,7 +5,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.52.0" + version = "1.69.0" } } } diff --git a/examples/crossaccounts/versions.tf b/examples/crossaccounts/versions.tf index 20dadb1..ef3a884 100644 --- a/examples/crossaccounts/versions.tf +++ b/examples/crossaccounts/versions.tf @@ -5,7 +5,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.52.0" + version = ">= 1.69.0" } } } diff --git a/examples/two-vpcs/main.tf b/examples/two-vpcs/main.tf index 7d37ebc..ee9af0b 100644 --- a/examples/two-vpcs/main.tf +++ b/examples/two-vpcs/main.tf @@ -55,6 +55,13 @@ module "tg_gateway_connection" { global_routing = false resource_tags = var.resource_tags resource_group_id = module.resource_group.resource_group_id - vpc_connections = [module.vpc_1.vpc_crn, module.vpc_2.vpc_crn] classic_connections_count = 0 + vpc_connections = [ + { + vpc_crn = module.vpc_1.vpc_crn + }, + { + vpc_crn = module.vpc_2.vpc_crn + } + ] } diff --git a/examples/two-vpcs/versions.tf b/examples/two-vpcs/versions.tf index 20dadb1..ef3a884 100644 --- a/examples/two-vpcs/versions.tf +++ b/examples/two-vpcs/versions.tf @@ -5,7 +5,7 @@ terraform { required_providers { ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.52.0" + version = ">= 1.69.0" } } } diff --git a/main.tf b/main.tf index 78b9344..5d61110 100644 --- a/main.tf +++ b/main.tf @@ -21,18 +21,36 @@ resource "ibm_tg_gateway" "tg_gw_instance" { } resource "ibm_tg_connection" "vpc_connections" { - count = length(var.vpc_connections) - - gateway = local.transit_gateway_id - network_type = "vpc" - name = "vpc_conn_inst${count.index}" - network_id = var.vpc_connections[count.index] + count = length(var.vpc_connections) + gateway = local.transit_gateway_id + network_type = "vpc" + name = "vpc_conn_inst${count.index + 1}" + network_id = var.vpc_connections[count.index].vpc_crn + default_prefix_filter = var.vpc_connections[count.index].default_prefix_filter +} +locals { + filter_list = flatten([ + for conn in ibm_tg_connection.vpc_connections : + [ + for filter in var.add_prefix_filters : + merge(filter, { connection_id = conn.connection_id + gateway = conn.gateway }) if filter.connection == conn.network_id + ] + ]) } - resource "ibm_tg_connection" "classic_connections" { - count = var.classic_connections_count - + count = var.classic_connections_count gateway = local.transit_gateway_id network_type = "classic" name = "classic_conn_inst${count.index}" } + +resource "ibm_tg_connection_prefix_filter" "add_prefix_filter" { + count = length(var.add_prefix_filters) > 0 ? length(var.add_prefix_filters) : 0 + gateway = local.filter_list[count.index].gateway + connection_id = local.filter_list[count.index].connection_id + action = local.filter_list[count.index].action + prefix = local.filter_list[count.index].prefix + le = local.filter_list[count.index].le + ge = local.filter_list[count.index].ge +} diff --git a/modules/terraform-ibm-transit-gateway-action/README.md b/modules/terraform-ibm-transit-gateway-action/README.md index e581037..a8579bf 100644 --- a/modules/terraform-ibm-transit-gateway-action/README.md +++ b/modules/terraform-ibm-transit-gateway-action/README.md @@ -40,7 +40,7 @@ module "tg_gateway_connection_crossaccounts_approve" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0 | -| [ibm](#requirement\_ibm) | >= 1.52.0, < 2.0.0 | +| [ibm](#requirement\_ibm) | >= 1.69.0, < 2.0.0 | ### Modules diff --git a/modules/terraform-ibm-transit-gateway-action/versions.tf b/modules/terraform-ibm-transit-gateway-action/versions.tf index 8f4221b..3ec7f01 100644 --- a/modules/terraform-ibm-transit-gateway-action/versions.tf +++ b/modules/terraform-ibm-transit-gateway-action/versions.tf @@ -4,7 +4,7 @@ terraform { # Use "greater than or equal to" range in modules ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.52.0, < 2.0.0" + version = ">= 1.69.0, < 2.0.0" } } } diff --git a/outputs.tf b/outputs.tf index e42e208..5faa971 100644 --- a/outputs.tf +++ b/outputs.tf @@ -17,3 +17,8 @@ output "classic_conn_ids" { description = "List of classic connection IDs" value = { for k, v in ibm_tg_connection.classic_connections : v.network_id => v.connection_id } } + +output "filter_ids" { + description = "Prefix filter IDs" + value = ibm_tg_connection_prefix_filter.add_prefix_filter[*].filter_id +} diff --git a/tests/pr_test.go b/tests/pr_test.go index 47bf24f..a8cdfaa 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -81,6 +81,34 @@ func setupOptions2VpcsExample(t *testing.T, prefix string) *testhelper.TestOptio return options } +func setupOptions2VpcsPrefixFilterExample(t *testing.T, prefix string) *testhelper.TestOptions { + const PrefixExampleTerraformDir = "examples/add-prefix-filter" + + options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + Prefix: prefix, + ResourceGroup: resourceGroup, + CloudInfoService: sharedInfoSvc, // use pointer to shared info svc to keep track of region selections + DefaultRegion: "us-south", + TerraformDir: PrefixExampleTerraformDir, + IgnoreUpdates: testhelper.Exemptions{ // Ignore for consistency check + List: []string{ + // to skip update error due to updated in-place for ibm_tg_connection_prefix_filter, tracking provider issue https://github.com/IBM-Cloud/terraform-provider-ibm/issues/5885 + "module.tg_gateway_connection.ibm_tg_connection_prefix_filter.add_prefix_filter[0]", + "module.tg_gateway_connection.ibm_tg_connection_prefix_filter.add_prefix_filter[1]", + }, + }, + }) + + terraformVars := map[string]interface{}{ + "transit_gateway_name": fmt.Sprintf("%s-%s", options.Prefix, "tg"), + } + + maps.Copy(options.TerraformVars, terraformVars) + + return options +} + // func setupOptionsCrossaccountsExample(t *testing.T, prefix string) *testhelper.TestOptions { // const TwoVpcsExampleTerraformDir = "examples/crossaccounts" @@ -143,6 +171,16 @@ func TestRun2VpcsExample(t *testing.T) { assert.NotNil(t, output, "Expected some output") } +func TestRun2VpcsPrefixFilterExample(t *testing.T) { + t.Parallel() + + options := setupOptions2VpcsPrefixFilterExample(t, "prefix-tg") + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} + // The account that this test was using has been removed so disabling the test until we decide what account can be used // func TestRunCrossaccountsExample(t *testing.T) { diff --git a/variables.tf b/variables.tf index c2e4d94..08c4194 100644 --- a/variables.tf +++ b/variables.tf @@ -35,8 +35,15 @@ variable "resource_tags" { } variable "vpc_connections" { - type = list(string) - description = "The list of vpc instance resource_crn to add network connections for." + type = list(object({ + vpc_crn = string + default_prefix_filter = optional(string) + })) + description = "The list of VPC instance connections with their associated default prefix filter. Customise the default filter setting for each VPC connections to `permit` or `deny` specifiv IP ranges. `permit` makes it to accept all prefixes after processing all the entries in the prefix filters list. `deny` makes it to deny all prefixes after processing all the entries in the prefix filters list. By default it is set to `permit`. Refer to https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui for more details." + validation { + condition = alltrue([for default_filter in var.vpc_connections : default_filter.default_prefix_filter == "permit" || default_filter.default_prefix_filter == "deny" || default_filter.default_prefix_filter == null]) + error_message = "Valid values to set default prefix filter is `permit` or `deny`. By default it is set to `permit`" + } } variable "classic_connections_count" { @@ -49,3 +56,30 @@ variable "delete_timeout" { description = "Deleting timeout value of the ibm_tg_gateway" default = "45m" } + +variable "add_prefix_filters" { + description = "Map of VPC CRN to optionally add prefix filter to set an ordered list of filters that determine the routes that transit gateway should accept or deny. Connections are denied or permitted based on the order of the filters passed. See https://cloud.ibm.com/docs/transit-gateway?topic=transit-gateway-adding-prefix-filters&interface=ui" + type = list(object({ + action = string + prefix = string + le = optional(number) + ge = optional(number) + before = optional(string) + connection = string + })) + validation { + condition = alltrue([ + for filter in var.add_prefix_filters : + filter.le >= 0 && filter.le <= 32 && filter.ge >= 0 && filter.ge <= 32 + ]) + error_message = "Both 'le' and 'ge' must be between 0 and 32." + } + validation { + condition = alltrue([ + for filter in var.add_prefix_filters : + filter.action == "permit" || filter.action == "deny" + ]) + error_message = "Valid values for 'action' are 'permit' or 'deny'." + } + default = [] +} diff --git a/versions.tf b/versions.tf index 8f4221b..3ec7f01 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { # Use "greater than or equal to" range in modules ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.52.0, < 2.0.0" + version = ">= 1.69.0, < 2.0.0" } } }