diff --git a/.catalog-onboard-pipeline.yaml b/.catalog-onboard-pipeline.yaml new file mode 100644 index 00000000..66e3a232 --- /dev/null +++ b/.catalog-onboard-pipeline.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +offerings: + - name: deploy-arch-ibm-vpc + kind: solution + catalog_id: f64499c8-eb50-4985-bf91-29f9e605a433 + offering_id: 2af61763-f8ef-4527-a815-b92166f29bc8 + include_git_submodules: true + variations: + - name: fully-configurable + mark_ready: true + install_type: fullstack + scc: + instance_id: 1c7d5f78-9262-44c3-b779-b28fe4d88c37 + region: us-south + scope_resource_group_var_name: existing_resource_group_name diff --git a/.releaserc b/.releaserc index 708916f7..4160e575 100644 --- a/.releaserc +++ b/.releaserc @@ -10,6 +10,9 @@ }], ["@semantic-release/exec", { "successCmd": "echo \"SEMVER_VERSION=${nextRelease.version}\" >> $GITHUB_ENV" + }], + ["@semantic-release/exec",{ + "publishCmd": "./ci/trigger-catalog-onboarding-pipeline.sh --version=v${nextRelease.version}" }] ] } diff --git a/README.md b/README.md index 937363c5..73a2e063 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ To attach access management tags to resources in this module, you need the follo | [ibm_is_vpc_dns_resolution_binding.vpc_dns_resolution_binding_id](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_vpc_dns_resolution_binding) | resource | | [ibm_is_vpc_routing_table.route_table](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_vpc_routing_table) | resource | | [ibm_is_vpc_routing_table_route.routing_table_routes](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_vpc_routing_table_route) | resource | +| [ibm_is_vpn_gateway.vpn_gateway](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_vpn_gateway) | resource | | [ibm_resource_instance.dns_instance_hub](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource | | [time_sleep.wait_for_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [time_sleep.wait_for_vpc_creation_data](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | @@ -223,15 +224,16 @@ To attach access management tags to resources in this module, you need the follo | [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where the VPC to be created | `string` | n/a | yes | | [routes](#input\_routes) | OPTIONAL - Allows you to specify the next hop for packets based on their destination address |
list(
object({
name = string
route_direct_link_ingress = optional(bool)
route_transit_gateway_ingress = optional(bool)
route_vpc_zone_ingress = optional(bool)
routes = optional(
list(
object({
action = optional(string)
zone = number
destination = string
next_hop = string
})
))
})
)
| `[]` | no | | [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 | -| [security\_group\_rules](#input\_security\_group\_rules) | A list of security group rules to be added to the default vpc security group (default empty) |
list(
object({
name = string
direction = string
remote = string
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
| `[]` | no | +| [security\_group\_rules](#input\_security\_group\_rules) | A list of security group rules to be added to the default vpc security group (default empty) |
list(
object({
name = string
direction = string
remote = optional(string)
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
| `[]` | no | | [skip\_custom\_resolver\_hub\_creation](#input\_skip\_custom\_resolver\_hub\_creation) | Indicates whether to skip the configuration of a custom resolver in the hub VPC. Only relevant if enable\_hub is set to true. | `bool` | `false` | no | | [skip\_spoke\_auth\_policy](#input\_skip\_spoke\_auth\_policy) | Set to true to skip the creation of an authorization policy between the DNS resolution spoke and hub, only enable this if a policy already exists between these two VPCs. See https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-dns-sharing-s2s-auth&interface=ui for more details. | `bool` | `false` | no | -| [subnets](#input\_subnets) | List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addressess. Public gateways will be enabled only in zones where a gateway has been created |
object({
zone-1 = list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
}))
zone-2 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
})))
zone-3 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
})))
})
|
{
"zone-1": [
{
"acl_name": "vpc-acl",
"cidr": "10.10.10.0/24",
"name": "subnet-a",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-2": [
{
"acl_name": "vpc-acl",
"cidr": "10.20.10.0/24",
"name": "subnet-b",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-3": [
{
"acl_name": "vpc-acl",
"cidr": "10.30.10.0/24",
"name": "subnet-c",
"no_addr_prefix": false,
"public_gateway": false
}
]
}
| no | +| [subnets](#input\_subnets) | List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addressess. Public gateways will be enabled only in zones where a gateway has been created |
object({
zone-1 = list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
}))
zone-2 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
zone-3 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
})
|
{
"zone-1": [
{
"acl_name": "vpc-acl",
"cidr": "10.10.10.0/24",
"name": "subnet-a",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-2": [
{
"acl_name": "vpc-acl",
"cidr": "10.20.10.0/24",
"name": "subnet-b",
"no_addr_prefix": false,
"public_gateway": true
}
],
"zone-3": [
{
"acl_name": "vpc-acl",
"cidr": "10.30.10.0/24",
"name": "subnet-c",
"no_addr_prefix": false,
"public_gateway": false
}
]
}
| no | | [tags](#input\_tags) | List of Tags for the resource created | `list(string)` | `null` | no | | [update\_delegated\_resolver](#input\_update\_delegated\_resolver) | If set to true, and if the vpc is configured to be a spoke for DNS resolution (enable\_hub\_vpc\_crn or enable\_hub\_vpc\_id set), then the spoke VPC resolver will be updated to a delegated resolver. | `bool` | `false` | no | | [use\_existing\_dns\_instance](#input\_use\_existing\_dns\_instance) | Whether to use an existing dns instance. If true, existing\_dns\_instance\_id must be set. | `bool` | `false` | no | | [use\_public\_gateways](#input\_use\_public\_gateways) | Create a public gateway in any of the three zones with `true`. |
object({
zone-1 = optional(bool)
zone-2 = optional(bool)
zone-3 = optional(bool)
})
|
{
"zone-1": true,
"zone-2": false,
"zone-3": false
}
| no | | [vpc\_flow\_logs\_name](#input\_vpc\_flow\_logs\_name) | The name to give the provisioned VPC flow logs. If not set, the module generates a name based on the `prefix` and `name` variables. | `string` | `null` | no | +| [vpn\_gateways](#input\_vpn\_gateways) | List of VPN gateways to create. |
list(
object({
name = string
subnet_name = string # Do not include prefix, use same name as in `var.subnets`
mode = optional(string)
resource_group = optional(string)
access_tags = optional(list(string), [])
})
)
| `[]` | no | ### Outputs @@ -249,6 +251,7 @@ To attach access management tags to resources in this module, you need the follo | [dns\_zone\_state](#output\_dns\_zone\_state) | The state of the DNS zone. | | [network\_acls](#output\_network\_acls) | List of shortnames and IDs of network ACLs | | [public\_gateways](#output\_public\_gateways) | Map of public gateways by zone | +| [security\_group\_details](#output\_security\_group\_details) | Details of security group. | | [subnet\_detail\_list](#output\_subnet\_detail\_list) | A list of subnets containing names, CIDR blocks, and zones. | | [subnet\_detail\_map](#output\_subnet\_detail\_map) | A map of subnets containing IDs, CIDR blocks, and zones | | [subnet\_ids](#output\_subnet\_ids) | The IDs of the subnets | @@ -258,6 +261,8 @@ To attach access management tags to resources in this module, you need the follo | [vpc\_flow\_logs](#output\_vpc\_flow\_logs) | Details of VPC flow logs collector | | [vpc\_id](#output\_vpc\_id) | ID of VPC created | | [vpc\_name](#output\_vpc\_name) | Name of VPC created | +| [vpn\_gateways\_data](#output\_vpn\_gateways\_data) | Details of VPN gateways data. | +| [vpn\_gateways\_name](#output\_vpn\_gateways\_name) | List of names of VPN gateways. | ## Contributing diff --git a/ibm_catalog.json b/ibm_catalog.json new file mode 100644 index 00000000..2bde293a --- /dev/null +++ b/ibm_catalog.json @@ -0,0 +1,544 @@ +{ + "products": [ + { + "name": "deploy-arch-ibm-vpc", + "label": "[Add-ons Beta] Cloud automation for VPC", + "product_kind": "solution", + "tags": [ + "network", + "network_vpc", + "ibm_created", + "target_terraform", + "terraform", + "solution", + "ibm_beta" + ], + "keywords": [ + "vpc", + "terraform", + "IaC", + "infrastructure as code", + "solution" + ], + "short_description": "Automates VPC deployment on IBM Cloud, offering full configurability and flexibility for diverse workloads.", + "long_description": "The VPC deployable architecture deploys a Virtual Private Cloud (VPC) infrastructure without any compute resources, such as Virtual Server Instances (VSI) or Red Hat OpenShift clusters. This is an experimental tile and not suitable for production workloads. Stay here if you want to try an experimental version with the [Optional and swappable components](https://cloud.ibm.com/docs/secure-enterprise?topic=secure-enterprise-choose-plan-process#optional-swappable) capability.", + "offering_docs_url": "https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/README.md", + "offering_icon_url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/images/vpc_icon.svg", + "provider_name": "IBM", + "features": [ + { + "title": "VPC on IBM Cloud", + "description": "Creates and configures a VPC network on IBM Cloud." + }, + { + "title": "Subnets", + "description": "Creates and configures subnets for VPC." + }, + { + "title": "Network ACLs", + "description": "Creates and configures network ACLs." + }, + { + "title": "Public gateways", + "description": "Create and configure public gateways." + }, + { + "title": "VPN gateways", + "description": "Create and configure VPN gateways." + }, + { + "title": "VPE gateways", + "description": "Create and configure VPE gateways." + }, + { + "title": "Security groups", + "description": "Create and configure security group rules." + }, + { + "title": "VPC flow logs", + "description": "VPC flow logs can be enabled." + }, + { + "title": "Address Prefixes", + "description": "Creates and configures address prefixes." + }, + { + "title": "Routing Table and routes", + "description": "Creates and configures routing table and customized routes." + }, + { + "title": "Object Storage bucket for VPC flow logs", + "description": "Creates and configures an Object Storage bucket required for VPC flow logs." + }, + { + "title": "KMS encryption", + "description": "Supports creating a new key, or using an existing one to encrypt the COS flow log bucket." + } + ], + "flavors": [ + { + "label": "Fully configurable", + "name": "fully-configurable", + "install_type": "fullstack", + "working_directory": "solutions/fully-configurable", + "architecture": { + "descriptions": "This architecture supports provisioning and configuring fully configurable Virtual Private Cloud.", + "features": [ + { + "title": "Create VPC", + "description": "Yes" + }, + { + "title": "Use existing VPC instance", + "description": "No" + }, + { + "title": "New resource group creation", + "description": "No" + }, + { + "title": "Create public gateways", + "description": "Yes" + }, + { + "title": "Create subnets", + "description": "Yes" + }, + { + "title": "Create network ACLs", + "description": "Yes" + }, + { + "title": "Create VPN gateways", + "description": "Yes" + }, + { + "title": "Create VPE gateways", + "description": "Yes" + }, + { + "title": "Create security groups rules", + "description": "Yes" + }, + { + "title": "Configure VPC flow logs", + "description": "Yes" + }, + { + "title": "Create COS instance", + "description": "No" + }, + { + "title": "Enforced KMS encryption", + "description": "No" + }, + { + "title": "Use existing KMS key", + "description": "Yes" + }, + { + "title": "KMS key ring and key creation", + "description": "Yes" + }, + { + "title": "Create custom routes", + "description": "Yes" + } + ], + "diagrams": [ + { + "diagram": { + "caption": "Architecture for provisioning and configuring fully configurable Virtual Private Cloud..", + "url": "https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/reference-architecture/deployable-architecture-vpc.svg", + "type": "image/svg+xml" + }, + "description": "This architecture supports provisioning and configuring fully configurable Virtual Private Cloud." + } + ] + }, + "iam_permissions": [ + { + "role_crns": ["crn:v1:bluemix:public:iam::::role:Administrator"], + "service_name": "iam-identity" + }, + { + "role_crns": ["crn:v1:bluemix:public:iam::::role:Administrator"], + "service_name": "is.vpc" + }, + { + "service_name": "cloud-object-storage", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ] + }, + { + "service_name": "kms", + "role_crns": [ + "crn:v1:bluemix:public:iam::::serviceRole:Manager", + "crn:v1:bluemix:public:iam::::role:Editor" + ] + } + ], + "configuration": [ + { + "key": "ibmcloud_api_key" + }, + { + "key": "prefix", + "required": true, + "description": "The prefix to add to all resources that this solution creates. To not use any prefix value, you can enter the string `__NULL__`." + }, + { + "key": "region", + "required": true, + "custom_config": { + "config_constraints": { + "generationType": "2" + }, + "grouping": "deployment", + "original_grouping": "deployment", + "type": "vpc_region" + } + }, + { + "key": "existing_resource_group_name", + "required": true, + "custom_config": { + "type": "resource_group", + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "identifier": "rg_name" + } + } + }, + { + "key": "provider_visibility", + "options": [ + { + "displayname": "private", + "value": "private" + }, + { + "displayname": "public", + "value": "public" + }, + { + "displayname": "public-and-private", + "value": "public-and-private" + } + ] + }, + { + "key": "vpc_name", + "required": true + }, + { + "key": "subnets" + }, + { + "key": "network_acls" + }, + { + "key": "address_prefixes" + }, + { + "key": "routes" + }, + { + "key": "security_group_rules" + }, + { + "key": "clean_default_security_group_acl" + }, + { + "key": "vpn_gateways" + }, + { + "key": "vpe_gateway_cloud_services" + }, + { + "key": "vpe_gateway_cloud_service_by_crn" + }, + { + "key": "vpe_gateway_security_group_ids" + }, + { + "key": "vpe_gateway_service_endpoints", + "options": [ + { + "displayname": "Public", + "value": "public" + }, + { + "displayname": "Private", + "value": "private" + } + ] + }, + { + "key": "vpe_gateway_reserved_ips" + }, + { + "key": "default_network_acl_name" + }, + { + "key": "default_security_group_name" + }, + { + "key": "default_routing_table_name" + }, + { + "key": "resource_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "access_tags", + "custom_config": { + "grouping": "deployment", + "original_grouping": "deployment", + "config_constraints": { + "type": "string" + } + } + }, + { + "key": "enable_vpc_flow_logs" + }, + { + "key": "existing_cos_instance_crn" + }, + { + "key": "skip_vpc_cos_iam_auth_policy" + }, + { + "key": "flow_logs_cos_bucket_name" + }, + { + "key": "kms_encryption_enabled_bucket" + }, + { + "key": "existing_flow_logs_bucket_kms_key_crn" + }, + { + "key": "existing_kms_instance_crn" + }, + { + "key": "skip_cos_kms_iam_auth_policy" + }, + { + "key": "kms_endpoint_type", + "options": [ + { + "displayname": "private", + "value": "private" + }, + { + "displayname": "public", + "value": "public" + } + ] + }, + { + "key": "kms_key_ring_name" + }, + { + "key": "kms_key_name" + }, + { + "key": "ibmcloud_kms_api_key" + }, + { + "key": "management_endpoint_type_for_bucket", + "options": [ + { + "displayname": "Public", + "value": "public" + }, + { + "displayname": "Private", + "value": "private" + }, + { + "displayname": "Direct", + "value": "direct" + } + ] + }, + { + "key": "cos_bucket_class", + "options": [ + { + "displayname": "Standard", + "value": "standard" + }, + { + "displayname": "Vault", + "value": "vault" + }, + { + "displayname": "Cold", + "value": "cold" + }, + { + "displayname": "Smart", + "value": "smart" + }, + { + "displayname": "OneRate Active", + "value": "onerate_active" + } + ] + }, + { + "key": "add_bucket_name_suffix" + }, + { + "key": "flow_logs_cos_bucket_archive_days" + }, + { + "key": "flow_logs_cos_bucket_archive_type", + "options": [ + { + "displayname": "Glacier", + "value": "Glacier" + }, + { + "displayname": "Accelerated", + "value": "Accelerated" + } + ] + }, + { + "key": "flow_logs_cos_bucket_expire_days" + }, + { + "key": "flow_logs_cos_bucket_enable_object_versioning" + }, + { + "key": "flow_logs_cos_bucket_enable_retention" + }, + { + "key": "flow_logs_cos_bucket_default_retention_days" + }, + { + "key": "flow_logs_cos_bucket_maximum_retention_days" + }, + { + "key": "flow_logs_cos_bucket_minimum_retention_days" + }, + { + "key": "flow_logs_cos_bucket_enable_permanent_retention" + } + ], + "dependencies": [ + { + "name": "deploy-arch-ibm-account-infra-base", + "catalog_id": "7a4d68b4-cf8b-40cd-a3d1-f49aff526eb3", + "flavors": ["standard"], + "id": "63641cec-6093-4b4f-b7b0-98d2f4185cd6-global", + "ignore_auto_referencing": ["*"], + "input_mapping": [ + { + "dependency_output": "workload_resource_group_name", + "version_input": "existing_resource_group_name" + }, + { + "dependency_input": "prefix", + "version_input": "prefix", + "reference_version": true + } + ], + "optional": true, + "on_by_default": true, + "version": "^v1.18.0" + }, + { + "name": "testing-deploy-arch-ibm-kms", + "id": "85fdbd7a-8c77-4abd-b716-653a31f3aba9-global", + "version": "^v1.2.1", + "flavors": ["standard"], + "catalog_id": "7a4d68b4-cf8b-40cd-a3d1-f49aff526eb3", + "optional": true, + "on_by_default": true, + "ignore_auto_referencing": ["*"], + "input_mapping": [ + { + "dependency_output": "kms_instance_crn", + "version_input": "existing_kms_instance_crn" + }, + { + "dependency_input": "resource_group_name", + "version_input": "existing_resource_group_name", + "reference_version": true + }, + { + "dependency_input": "prefix", + "version_input": "prefix", + "reference_version": true + }, + { + "dependency_input": "region", + "version_input": "region", + "reference_version": true + }, + { + "dependency_input": "use_existing_resource_group", + "value": true, + "reference_version": true + }, + { + "version_input": "kms_encryption_enabled_bucket", + "value": true + } + ] + }, + { + "name": "deploy-arch-ibm-cos", + "id": "68921490-2778-4930-ac6d-bae7be6cd958-global", + "version": "^v8.20.1", + "flavors": ["instance"], + "catalog_id": "7a4d68b4-cf8b-40cd-a3d1-f49aff526eb3", + "optional": true, + "on_by_default": true, + "ignore_auto_referencing": ["*"], + "input_mapping": [ + { + "dependency_output": "cos_instance_id", + "version_input": "existing_cos_instance_crn" + }, + { + "dependency_input": "prefix", + "version_input": "prefix", + "reference_version": true + }, + { + "dependency_input": "resource_group_name", + "version_input": "existing_resource_group_name", + "reference_version": true + }, + { + "dependency_input": "use_existing_resource_group", + "value": true, + "reference_version": true + }, + { + "version_input": "enable_vpc_flow_logs", + "value": true + } + ] + } + ], + "dependency_version_2": true + } + ] + } + ] +} diff --git a/images/vpc_icon.svg b/images/vpc_icon.svg new file mode 100644 index 00000000..6f06ea97 --- /dev/null +++ b/images/vpc_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/main.tf b/main.tf index 6b7fab72..03d6b25b 100644 --- a/main.tf +++ b/main.tf @@ -69,7 +69,7 @@ resource "time_sleep" "wait_for_vpc_creation_data" { resource "ibm_is_vpc" "vpc" { count = var.create_vpc == true ? 1 : 0 - name = var.prefix != null ? "${var.prefix}-${var.name}-vpc" : var.name + name = var.prefix != null ? "${var.prefix}-${var.name}" : var.name resource_group = var.resource_group_id # address prefix is set to auto only if no address prefixes NOR any subnet is passed as input address_prefix_management = (length([for prefix in values(coalesce(var.address_prefixes, {})) : prefix if prefix != null]) != 0) || (length([for subnet in values(coalesce(var.subnets, {})) : subnet if subnet != null]) != 0) ? "manual" : null @@ -356,7 +356,7 @@ resource "ibm_is_flow_log" "flow_logs" { ############################################################################## # DNS ZONE -# ############################################################################## +############################################################################### resource "ibm_dns_zone" "dns_zone" { count = var.enable_hub && !var.skip_custom_resolver_hub_creation && alltrue([var.dns_zone_name != null, var.dns_zone_name != ""]) ? 1 : 0 @@ -409,3 +409,26 @@ locals { } ############################################################################## +# Create VPN Gateways +############################################################################## + +locals { + # Convert the vpn_gateway input from list to a map + vpn_gateway_map = { for gateway in var.vpn_gateways : gateway.name => gateway } +} + +resource "ibm_is_vpn_gateway" "vpn_gateway" { + for_each = local.vpn_gateway_map + name = var.prefix != null ? "${var.prefix}-${each.key}" : each.key + subnet = local.subnets["${local.vpc_name}-${each.value.subnet_name}"].id + mode = each.value.mode + resource_group = each.value.resource_group == null ? var.resource_group_id : each.value.resource_group + tags = var.tags + access_tags = each.value.access_tags + + timeouts { + delete = "1h" + } +} + +############################################################################## diff --git a/outputs.tf b/outputs.tf index a99031fa..e679654b 100644 --- a/outputs.tf +++ b/outputs.tf @@ -197,3 +197,32 @@ output "dns_record_ids" { description = "List of all the domain resource records." value = length(ibm_dns_resource_record.dns_record) > 0 ? local.record_ids : null } + +############################################################################## +# VPN Gateways +############################################################################## + +output "vpn_gateways_name" { + description = "List of names of VPN gateways." + value = [ + for gateway in ibm_is_vpn_gateway.vpn_gateway : + gateway.name + ] +} + +output "vpn_gateways_data" { + description = "Details of VPN gateways data." + value = [ + for gateway in ibm_is_vpn_gateway.vpn_gateway : + gateway + ] +} + +############################################################################## +# Security Group Details +############################################################################## + +output "security_group_details" { + description = "Details of security group." + value = ibm_is_security_group_rule.default_vpc_rule +} diff --git a/reference-architecture/deployable-architecture-vpc.svg b/reference-architecture/deployable-architecture-vpc.svg new file mode 100644 index 00000000..4de4ed1c --- /dev/null +++ b/reference-architecture/deployable-architecture-vpc.svg @@ -0,0 +1,4 @@ + + + +
ACL
locked
IBM Cloud
Region
Resource Group
Existing KMS
Key Ring
Root Key
Flow logs Bucket
Cloud Object Storage Instance
VPC
Subnet
Public Gateway (Optional)Virtual Private Endpoints(Optional)
Zone 2
VPN Gateway (Optional)
Subnet
Public Gateway (Optional)Virtual Private Endpoints(Optional)
Zone 1
VPN Gateway (Optional)
ACL
locked
Subnet
Public Gateway (Optional)Virtual Private Endpoints(Optional)
Zone 2
VPN Gateway (Optional)
\ No newline at end of file diff --git a/solutions/fully-configurable/DA-types.md b/solutions/fully-configurable/DA-types.md new file mode 100644 index 00000000..9d658fc1 --- /dev/null +++ b/solutions/fully-configurable/DA-types.md @@ -0,0 +1,315 @@ +# Configuring complex inputs for VPC + +Several input variables in the **Cloud automation of VPC** [deployable architecture](https://cloud.ibm.com/catalog#deployable_architecture) use complex object types. You can specify these inputs when you configure your deployable architecture. + +- [Subnets](#subnets) (`subnets`) +- [Network ACLs](#network-acls) (`network_acls`) +- [Security Group Rules](#security-group-rules)(`security_group_rules`) +- [Address Prefixes](#address-prefixes) (`address_prefixes`) +- [Routes](#routes) (`routes`) +- [VPN Gateways](#vpn-gateways) (`vpn_gateways`) +- [VPE Gateways Cloud Services](#cloud-services) (`vpe_gateway_cloud_services`) +- [VPE Gateways Cloud Service by CRN](#cloud-service-by-crn) (`vpe_gateway_cloud_service_by_crn`) +- [VPE Gateways Reserved IPs](#reserved-ips) (`vpe_gateway_reserved_ips`) + +## Subnets + +This variable configuration allows you to specify the subnets for the VPC. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total IPv4 addresses. Public gateways will be enabled only in zones where a gateway has been created. + +- Variable name: `subnets`. +- Type: A object containing three zones. Each zone is a list of object. +- Default value: Subnet for `zone-1`. + +### Options for subnets + +For each zone, you can define the follwoing: + + - `name` (required): The name of subnet + - `cidr` (required): The cidr to define for the subnet + - `public_gateway` (optional): (bool) Set to true if need to create public gateway for the zone + - `acl_name` (required): The name of ACL created + - `no_addr_prefix` (optional): (bool) Default is `false`, it does not add address prefix for subnet + - `subnet_tags` (optional): (list) To specify tags for subnet specifically + +### Example + +```hcl + { + zone-1 = [ + { + name = "subnet-a" + cidr = "10.10.10.0/24" + public_gateway = true + acl_name = "vpc-acl-a" + no_addr_prefix = false + subnet_tags = ["public"] + } + ] + zone-2 = [ + { + name = "subnet-b" + cidr = "10.10.20.0/24" + public_gateway = true + acl_name = "vpc-acl-b" + no_addr_prefix = false + } + ] + } +``` + +## Network ACLs + +This variable configuration allows you to specify the list of ACLs to create. Each ACL must have at least one rule defined. + +- Variable name: `network_acls`. +- Type: A list of object. + +### Options for Network ACLs + + - `name` (required): The name of network ACL. + - `add_ibm_cloud_internal_rules` (optional): (bool) Set to true to include pre-defined rules defined [here](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/network_acls.tf#L50). + - `add_vpc_connectivity_rules` (optional): (bool) Set to true to include pre-defined VPC connectivity rules defined [here](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/network_acls.tf#L102). + - `prepend_ibm_rules` (optional): (bool) Set to true to prepend pre-defined rules defined [here](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/network_acls.tf#L132). + - `rules` (required): (list of objects) + - `name`: Name of the rule. + - `action`: Allowed values are `allow` or `deny`. + - `direction`: Allowed values are `inbound` or `outbound`. + - `destination`: Destination address. + - `source`: Source address. + - `tcp` (optional): + - `port_min` + - `port_max` + - `source_port_min` + - `source_port_max` + - `udp` (optional): + - `port_min` + - `port_max` + - `source_port_min` + - `source_port_max` + - `icmp` (optional): + - `type` + - `code` + +### Example + +```hcl + [ + { + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [ + { + name = "allow-all-443-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 443 + port_max = 443 + source_port_min = 443 + source_port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + } + ] + } + ] +``` + +## Security Group Rules + +This variable configuration allows you to specify the list of security group rules to be added to the default VPC security group. You can create a different type of protocol rules." + +- Variable name: `security_group_rules`. +- Type: A list of object. +- Default value: An empty list (`[]`). + +### Options for Security Group Rules + +- `name` (required): The name of the security group rule. +- `direction` (required): The direction of the traffic. Allowed values are `inbound` or `outbound`. +- `remote` (optional): Security group ID or an IP address or a CIDR block. +- `tcp` (optional): + - `port_min` + - `port_max` +- `udp` (optional): + - `port_min` + - `port_max` +- `icmp` (optional): + - `type` + - `code` + + +### Example + +```hcl + [ + { + name = "security-group-rule-1" + direction = "inbound" + remote = "127.0.0.1" + tcp = { + port_min = 8080 + port_max = 8080 + } + } + ] +``` + +## Address Prefixes + +This variable allows you to specify the IP range for the VPC for a certain location. + +- Variable name: `address_prefixes`. +- Type: A object including three zones. Each zone can have a list of address prefixes. +- Default value: `null` for each zone. + +### Options for Address Prefixes + +- `zone-1` (optional): (list) Address prefixes for zone-1. +- `zone-2` (optional): (list) Address prefixes for zone-2. +- `zone-3` (optional): (list) Address prefixes for zone-3. + +### Example + +```hcl + { + zone-1 = ["10.10.10.0/18"] + zone-2 = null + zone-3 = null + } +``` + +## Routes + +This variable allows you to add the custom routing tables and then add routes. + +- Variable name: `routes`. +- Type: A list of object. +- Default value: An empty list `[]`. + +### Options for Routes + +- `name` (required): The name of the route. +- `route_direct_link_ingress` (optional): (bool) Required if the routing table will be used to route traffic that originates from Direct Link to the VPC. +- `route_transit_gateway_ingress` (optional): (bool) Required if the routing table will be used to route traffic that originates from the internet. +- `route_vpc_zone_ingress` (optional): (bool) Required if the routing table will be used to route traffic that originates from Transit Gateway to the VPC. +- `routes` (optional): (list) + - `action`: The action to perform with a packet. Allowed values are `delegate`, `delegate_vpc`, `deliver`, `drop`. + - `zone`: Number of the zone. + - `destination`: The destination of the route. + - `next_hop`: The next hop of the route. For action other than deliver, you must specify `0.0.0.0`. + +### Example + +```hcl + { + name = "route-1" + route_direct_link_ingress = false + route_transit_gateway_ingress = false + route_vpc_zone_ingress = true + routes = [ + { + zone = 1 + destination = "10.10.10.0/24" + next_hop = "10.10.0.4" + action = "deliver" + } + ] + } +``` + +## VPN Gateways + +This variable allows you to specify the list of VPN Gateways to create. + +- Variable name: `vpn_gateways`. +- Type: A list of object. +- Default value: An empty list `[]`. + +### Options for VPN Gateways + +- `name` (required): Name of the VPN gateway. +- `subnet_name` (required): Name of the subnet to attach a VPN gateway. +- `mode` (optional): Mode in VPN gateway. Allowed values are `route` and `policy`. +- `resource_group` (optional): The resource group where the VPN gateway to be created. +- `access_tags` (optional): (list) A list of tags to add to your VPN gateway. + +### Example + +```hcl + { + name = "vpn-gateway-1" + subnet_name = "subnet-a" + mode = "route" +} +``` + +## VPE Gateway Cloud Services + +This variable configuration allows you to specify the list of cloud services used to create endpoint gateways. + +- Variable name: `vpe_gateway_cloud_services`. +- Type: A list of object. +- Default value: An empty list `[]`. + +### Options for VPE Gateway Cloud Services + +- `service_name` (required): The name of the Cloud service. +- `vpe_name` (optional): The name of the VPE gateway. If it is not specified, VPE name will be automatically generated in the format `--`. +- `allow_dns_resolution_binding` (optional): (bool) Set to `true` to allow this endpoint gateway to participate in DNS resolution bindings with a VPC. + +### Example + +```hcl + { + service_name = "cloud-object-storage" + vpe_name = "vpe1" + } +``` + +## VPE Gateway Cloud Service by CRN + +This variable defines cloud service CRNs required to create endpoint gateways. This list is used to identify services that are not supported by service name in the `cloud_services` variable. For a list of supported services, see [VPE-enabled services](https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-supported-services). + +- Variable name: `vpe_gateway_cloud_service_by_crn`. +- Type: A list of object. +- Default value: An empty list `[]`. + +### Options for VPE Gateway Cloud Services by CRN + +- `crn` (required): The CRN of the Cloud service. +- `vpe_name` (optional): The name of the VPE gateway. If it is not specified, VPE name will be automatically generated in the format `--`. +- `service_name` (optional): The name of the service. Required to compute the name of VPE. If not specified, the service name will be obtained from the crn. +- `allow_dns_resolution_binding` (optional): (bool) Set to `true` to allow this endpoint gateway to participate in DNS resolution bindings with a VPC. + +### Example + +```hcl + { + crn = "crn:v1:bluemix:public:cloud-object-storage:global:::endpoint:s3.direct.mil01.cloud-object-storage.appdomain.cloud" + vpe_name = "vpe2" + } +``` + +## VPE Gateways Reserved IPs + +This variable defines a map of existing reserved IP names and values to attach with the endpoint gateways. This value is used when a user uses the existing reserved ips instead of creating new." + +- Variable name: `vpe_gateway_reserved_ips`. +- Type: A object. +- Default value: An empty object `{}`. + +### Options for VPE Gateway Cloud Services by CRN + +- `name` (optional): The name of the reserved IP with its value. + +### Example + +```hcl + { + name = "vpe-reserved-ip" + } +``` diff --git a/solutions/fully-configurable/README.md b/solutions/fully-configurable/README.md new file mode 100644 index 00000000..4b925bf1 --- /dev/null +++ b/solutions/fully-configurable/README.md @@ -0,0 +1,134 @@ +# Cloud automation for VPC (Fully configurable) + +### Prerequisites + +- An existing resource group. +- An existing COS istance if VPC flow logs is enabled. +- An existing KMS instance (or key) if encryption of the flow logs COS bucket is required. + +### Configuration + +This solution supports provisioning and configuring the following infrastructure: + +- A VPC +- A Cloud Object Storage bucket which is required to store flow logs +- KMS key-ring and key if existing key is not passed in +- Configures the following for the created VPC: + - subnets + - network ACLs + - security group rules + - address prefixes + - customized routing table and routes + - public gateway + - VPN gateway + - VPE gateway + - flow logs + + +![vpc-deployable-architecture](../../reference-architecture/deployable-architecture-vpc.svg) + +:exclamation: **Important:** This solution is not intended to be called by other modules because it contains a provider configuration and is not compatible with the `for_each`, `count`, and `depends_on` arguments. For more information, see [Providers Within Modules](https://developer.hashicorp.com/terraform/language/modules/develop/providers). + + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [ibm](#requirement\_ibm) | 1.76.1 | +| [time](#requirement\_time) | 0.13.0 | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [cos\_buckets](#module\_cos\_buckets) | terraform-ibm-modules/cos/ibm//modules/buckets | 8.19.2 | +| [existing\_cos\_crn\_parser](#module\_existing\_cos\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_instance\_crn\_parser](#module\_existing\_kms\_instance\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [existing\_kms\_key\_crn\_parser](#module\_existing\_kms\_key\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 | +| [kms](#module\_kms) | terraform-ibm-modules/kms-all-inclusive/ibm | 4.19.5 | +| [resource\_group](#module\_resource\_group) | terraform-ibm-modules/resource-group/ibm | 1.1.6 | +| [vpc](#module\_vpc) | ../../ | n/a | +| [vpe\_gateway](#module\_vpe\_gateway) | terraform-ibm-modules/vpe-gateway/ibm | 4.5.0 | + +### Resources + +| Name | Type | +|------|------| +| [ibm_iam_authorization_policy.cos_kms_policy](https://registry.terraform.io/providers/IBM-Cloud/ibm/1.76.1/docs/resources/iam_authorization_policy) | resource | +| [time_sleep.wait_for_cross_account_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/0.13.0/docs/resources/sleep) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [access\_tags](#input\_access\_tags) | The list of access tags to add to the VPC instance. | `list(string)` | `[]` | no | +| [add\_bucket\_name\_suffix](#input\_add\_bucket\_name\_suffix) | Add a randomly generated suffix that is 4 characters in length, to the name of the newly provisioned Cloud Object Storage bucket. Do not use this suffix if you are passing the existing Cloud Object Storage bucket. To manage the name of the Cloud Object Storage bucket manually, use the `flow_logs_cos_bucket_name` variables. | `bool` | `true` | no | +| [address\_prefixes](#input\_address\_prefixes) | The IP range that will be defined for the VPC for a certain location. Use only with manual address prefixes. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#address-prefixes-). |
object({
zone-1 = optional(list(string))
zone-2 = optional(list(string))
zone-3 = optional(list(string))
})
|
{
"zone-1": null,
"zone-2": null,
"zone-3": null
}
| no | +| [clean\_default\_security\_group\_acl](#input\_clean\_default\_security\_group\_acl) | Remove all rules from the default VPC security group and VPC ACL (less permissive) | `bool` | `true` | no | +| [cos\_bucket\_class](#input\_cos\_bucket\_class) | The storage class of the newly provisioned Cloud Object Storage bucket. Specify one of the following values for the storage class: `standard`, `vault`, `cold`, `smart` (default), or `onerate_active`. | `string` | `"standard"` | no | +| [default\_network\_acl\_name](#input\_default\_network\_acl\_name) | Name of the Default ACL. If null, a name will be automatically generated. | `string` | `null` | no | +| [default\_routing\_table\_name](#input\_default\_routing\_table\_name) | Name of the Default Routing Table. If null, a name will be automatically generated. | `string` | `null` | no | +| [default\_security\_group\_name](#input\_default\_security\_group\_name) | Name of the Default Security Group. If null, a name will be automatically generated. | `string` | `null` | no | +| [enable\_vpc\_flow\_logs](#input\_enable\_vpc\_flow\_logs) | To enable VPC Flow logs, set this to true. | `bool` | `false` | no | +| [existing\_cos\_instance\_crn](#input\_existing\_cos\_instance\_crn) | CRN of the existing COS instance. It is only required if `enable_vpc_flow_logs` is set to true and will be used to create the flow logs bucket. | `string` | `null` | no | +| [existing\_flow\_logs\_bucket\_kms\_key\_crn](#input\_existing\_flow\_logs\_bucket\_kms\_key\_crn) | The CRN of the existing root key of key management service (KMS) that is used to encrypt the flow logs Cloud Object Storage bucket. If no value is set for this variable, specify a value for the `existing_kms_instance_crn` variable to create a key ring and key. | `string` | `null` | no | +| [existing\_kms\_instance\_crn](#input\_existing\_kms\_instance\_crn) | The CRN of the existing key management service (KMS) that is used to create keys for encrypting the flow logs Cloud Object Storage bucket. Used to create a new KMS key unless an existing key is passed using the `existing_flow_logs_bucket_kms_key_crn` input. | `string` | `null` | no | +| [existing\_resource\_group\_name](#input\_existing\_resource\_group\_name) | The name of an existing resource group to provision the resources. | `string` | `"Default"` | no | +| [flow\_logs\_cos\_bucket\_archive\_days](#input\_flow\_logs\_cos\_bucket\_archive\_days) | The number of days before the `archive_type` rule action takes effect for the flow logs cloud object storage bucket. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_archive\_type](#input\_flow\_logs\_cos\_bucket\_archive\_type) | The storage class or archive type you want the object to transition to in the flow logs cloud object storage bucket. | `string` | `"Glacier"` | no | +| [flow\_logs\_cos\_bucket\_default\_retention\_days](#input\_flow\_logs\_cos\_bucket\_default\_retention\_days) | The number of days that an object can remain unmodified in the flow logs cloud object storage bucket. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_enable\_object\_versioning](#input\_flow\_logs\_cos\_bucket\_enable\_object\_versioning) | Set it to true if object versioning is enabled so that multiple versions of an object are retained in the flow logs cloud object storage bucket. Cannot be used if `flow_logs_cos_bucket_enable_retention` is true. | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_enable\_permanent\_retention](#input\_flow\_logs\_cos\_bucket\_enable\_permanent\_retention) | Whether permanent retention status is enabled for the flow logs cloud object storage bucket. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-immutable). | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_enable\_retention](#input\_flow\_logs\_cos\_bucket\_enable\_retention) | Set to true to enable retention for the flow logs cloud object storage bucket. | `bool` | `false` | no | +| [flow\_logs\_cos\_bucket\_expire\_days](#input\_flow\_logs\_cos\_bucket\_expire\_days) | The number of days before the expire rule action takes effect for the flow logs cloud object storage bucket. | `number` | `366` | no | +| [flow\_logs\_cos\_bucket\_maximum\_retention\_days](#input\_flow\_logs\_cos\_bucket\_maximum\_retention\_days) | The maximum number of days that an object can be kept unmodified in the flow logs cloud object storage. | `number` | `350` | no | +| [flow\_logs\_cos\_bucket\_minimum\_retention\_days](#input\_flow\_logs\_cos\_bucket\_minimum\_retention\_days) | The minimum number of days that an object must be kept unmodified in the flow logs cloud object storage. | `number` | `90` | no | +| [flow\_logs\_cos\_bucket\_name](#input\_flow\_logs\_cos\_bucket\_name) | Name of the Cloud Object Storage bucket to be created to collect VPC flow logs. | `string` | `"flow-logs-bucket"` | no | +| [ibmcloud\_api\_key](#input\_ibmcloud\_api\_key) | The IBM Cloud API key to deploy resources. | `string` | n/a | yes | +| [ibmcloud\_kms\_api\_key](#input\_ibmcloud\_kms\_api\_key) | The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud\_api\_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Cloud Object Storage instance. Leave this input empty if the same account owns both instances. | `string` | `null` | no | +| [kms\_encryption\_enabled\_bucket](#input\_kms\_encryption\_enabled\_bucket) | Set to true to encrypt the Cloud Object Storage Flow Logs bucket with a KMS key. If set to true, a value must be passed for existing\_flow\_logs\_bucket\_kms\_key\_crn (to use that key) or existing\_kms\_instance\_crn (to create a new key). Value cannot be set to true if enable\_vpc\_flow\_logs is set to false. | `bool` | `false` | no | +| [kms\_endpoint\_type](#input\_kms\_endpoint\_type) | The type of endpoint to use for communicating with the KMS. Possible values: `public`, `private`. Applies only if `existing_flow_logs_bucket_kms_key_crn` is not specified. | `string` | `"private"` | no | +| [kms\_key\_name](#input\_kms\_key\_name) | The name of the key to encrypt the flow logs Cloud Object Storage bucket. If an existing key is used, this variable is not required. If the prefix input variable is passed, the name of the key is prefixed to the value in the `-value` format. | `string` | `"flow-logs-cos-key"` | no | +| [kms\_key\_ring\_name](#input\_kms\_key\_ring\_name) | The name of the key ring to create for the Cloud Object Storage bucket key. If an existing key is used, this variable is not required. If the prefix input variable is passed, the name of the key ring is prefixed to the value in the `-value` format. | `string` | `"flow-logs-cos-key-ring"` | no | +| [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM Terraform provider to use to manage Cloud Object Storage buckets (`public`, `private`, or `direct`). If you are using a private endpoint, make sure that you enable virtual routing and forwarding (VRF) in your account, and that the Terraform runtime can access the IBM Cloud Private network. | `string` | `"direct"` | no | +| [network\_acls](#input\_network\_acls) | The list of ACLs to create. Provide at least one rule for each ACL. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#network-acls-). |
list(
object({
name = string
add_ibm_cloud_internal_rules = optional(bool)
add_vpc_connectivity_rules = optional(bool)
prepend_ibm_rules = optional(bool)
rules = list(
object({
name = string
action = string
destination = string
direction = string
source = string
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
source_port_max = optional(number)
source_port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
source_port_max = optional(number)
source_port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
})
)
|
[
{
"add_ibm_cloud_internal_rules": true,
"add_vpc_connectivity_rules": true,
"name": "vpc-acl",
"prepend_ibm_rules": true,
"rules": [
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-443-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"port_min": 443,
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-80-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 80,
"port_min": 80,
"source_port_max": 80,
"source_port_min": 80
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "inbound",
"name": "allow-all-22-inbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 22,
"port_min": 22,
"source_port_max": 22,
"source_port_min": 22
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-443-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 443,
"port_min": 443,
"source_port_max": 443,
"source_port_min": 443
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-80-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 80,
"port_min": 80,
"source_port_max": 80,
"source_port_min": 80
}
},
{
"action": "allow",
"destination": "0.0.0.0/0",
"direction": "outbound",
"name": "allow-all-22-outbound",
"source": "0.0.0.0/0",
"tcp": {
"port_max": 22,
"port_min": 22,
"source_port_max": 22,
"source_port_min": 22
}
}
]
}
]
| no | +| [prefix](#input\_prefix) | Prefix to add to all the resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string. | `string` | n/a | yes | +| [provider\_visibility](#input\_provider\_visibility) | Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints). | `string` | `"private"` | no | +| [region](#input\_region) | Region to deploy the VPC. | `string` | `"us-south"` | no | +| [resource\_tags](#input\_resource\_tags) | The list of tags to add to the VPC instance. | `list(string)` | `[]` | no | +| [routes](#input\_routes) | Allows you to specify the next hop for packets based on their destination address. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#routes-). |
list(
object({
name = string
route_direct_link_ingress = optional(bool)
route_transit_gateway_ingress = optional(bool)
route_vpc_zone_ingress = optional(bool)
routes = optional(
list(
object({
action = optional(string)
zone = number
destination = string
next_hop = string
})
))
})
)
| `[]` | no | +| [security\_group\_rules](#input\_security\_group\_rules) | A list of security group rules to be added to the default vpc security group (default empty). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#security-group-rules-). |
list(
object({
name = string
direction = string
remote = optional(string)
tcp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
udp = optional(
object({
port_max = optional(number)
port_min = optional(number)
})
)
icmp = optional(
object({
type = optional(number)
code = optional(number)
})
)
})
)
| `[]` | no | +| [skip\_cos\_kms\_iam\_auth\_policy](#input\_skip\_cos\_kms\_iam\_auth\_policy) | To skip creating an IAM authorization policy that allows Cloud Object Storage(COS) to access KMS key. | `bool` | `false` | no | +| [skip\_vpc\_cos\_iam\_auth\_policy](#input\_skip\_vpc\_cos\_iam\_auth\_policy) | To skip creating an IAM authorization policy that allows the VPC to access the Cloud Object Storage, set this variable to `true`. Required only if `enable_vpc_flow_logs` is set to true. | `bool` | `false` | no | +| [subnets](#input\_subnets) | List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addressess. Public gateways will be enabled only in zones where a gateway has been created. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#subnets-). |
object({
zone-1 = list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
}))
zone-2 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
zone-3 = optional(list(object({
name = string
cidr = string
public_gateway = optional(bool)
acl_name = string
no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true
subnet_tags = optional(list(string), [])
})))
})
|
{
"zone-1": [
{
"acl_name": "vpc-acl",
"cidr": "10.10.10.0/24",
"name": "subnet-a",
"no_addr_prefix": false,
"public_gateway": true
}
]
}
| no | +| [vpc\_name](#input\_vpc\_name) | Name of the VPC. If a prefix input variable is specified, the prefix is added to the name in the `-` format. | `string` | `"vpc"` | no | +| [vpe\_gateway\_cloud\_service\_by\_crn](#input\_vpe\_gateway\_cloud\_service\_by\_crn) | The list of cloud service CRNs used to create endpoint gateways. Use this list to identify services that are not supported by service name in the `cloud_services` variable. For a list of supported services, see [VPE-enabled services](https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-supported-services). If `service_name` is not specified, the CRN is used to find the name. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpe-gateway-cloud-service-by-crn-). |
set(
object({
crn = string
vpe_name = optional(string) # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name.
service_name = optional(string) # Name of the service used to compute the name of the VPE. If not specified, the service name will be obtained from the crn.
allow_dns_resolution_binding = optional(bool, true)
})
)
| `[]` | no | +| [vpe\_gateway\_cloud\_services](#input\_vpe\_gateway\_cloud\_services) | The list of cloud services used to create endpoint gateways. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpe-gateway-cloud-services-). |
set(object({
service_name = string
vpe_name = optional(string), # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name.
allow_dns_resolution_binding = optional(bool, false)
}))
| `[]` | no | +| [vpe\_gateway\_reserved\_ips](#input\_vpe\_gateway\_reserved\_ips) | Map of existing reserved IP names and values. Leave this value as default if you want to create new reserved ips, this value is used when a user passes their existing reserved ips created here and not attempt to recreate those. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#reserved-ips-). |
object({
name = optional(string) # reserved ip name
})
| `{}` | no | +| [vpe\_gateway\_security\_group\_ids](#input\_vpe\_gateway\_security\_group\_ids) | List of security group ids to attach to each endpoint gateway. | `list(string)` | `null` | no | +| [vpe\_gateway\_service\_endpoints](#input\_vpe\_gateway\_service\_endpoints) | Service endpoints to use to create endpoint gateways. Can be `public`, or `private`. | `string` | `"private"` | no | +| [vpn\_gateways](#input\_vpn\_gateways) | List of VPN Gateways to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpn-gateways-). |
list(
object({
name = string
subnet_name = string # Do not include prefix, use same name as in `var.subnets`
mode = optional(string)
resource_group = optional(string)
access_tags = optional(list(string), [])
})
)
| `[]` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [network\_acls](#output\_network\_acls) | List of shortnames and IDs of network ACLs | +| [private\_path\_subnet\_id](#output\_private\_path\_subnet\_id) | The IDs of the subnets | +| [public\_gateways](#output\_public\_gateways) | Map of public gateways by zone | +| [security\_group\_details](#output\_security\_group\_details) | Details of security group. | +| [subnet\_detail\_list](#output\_subnet\_detail\_list) | A list of subnets containing names, CIDR blocks, and zones. | +| [subnet\_detail\_map](#output\_subnet\_detail\_map) | A map of subnets containing IDs, CIDR blocks, and zones | +| [subnet\_ids](#output\_subnet\_ids) | The IDs of the subnets | +| [subnet\_zone\_list](#output\_subnet\_zone\_list) | A list containing subnet IDs and subnet zones | +| [vpc\_crn](#output\_vpc\_crn) | CRN of VPC created | +| [vpc\_flow\_logs](#output\_vpc\_flow\_logs) | Details of VPC flow logs collector | +| [vpc\_id](#output\_vpc\_id) | ID of VPC created | +| [vpc\_name](#output\_vpc\_name) | Name of VPC created | +| [vpe\_crn](#output\_vpe\_crn) | The CRN of the endpoint gateway | +| [vpe\_ips](#output\_vpe\_ips) | The reserved IPs for endpoint gateways. | +| [vpn\_gateways\_data](#output\_vpn\_gateways\_data) | Details of VPN gateways data | +| [vpn\_gateways\_name](#output\_vpn\_gateways\_name) | List of names of VPN gateways. | + diff --git a/solutions/fully-configurable/catalogValidationValues.json.template b/solutions/fully-configurable/catalogValidationValues.json.template new file mode 100644 index 00000000..92c260d6 --- /dev/null +++ b/solutions/fully-configurable/catalogValidationValues.json.template @@ -0,0 +1,11 @@ +{ + "ibmcloud_api_key": $VALIDATION_APIKEY, + "region": "us-south", + "resource_tags": $TAGS, + "existing_resource_group_name": "geretain-test-resources", + "prefix": $PREFIX, + "enable_vpc_flow_logs": true, + "kms_encryption_enabled_bucket": true, + "existing_kms_instance_crn": $HPCS_US_SOUTH_CRN, + "existing_cos_instance_crn": $COS_INSTANCE_CRN +} diff --git a/solutions/fully-configurable/main.tf b/solutions/fully-configurable/main.tf new file mode 100644 index 00000000..1bd22a76 --- /dev/null +++ b/solutions/fully-configurable/main.tf @@ -0,0 +1,245 @@ +locals { + prefix = var.prefix != null ? (trimspace(var.prefix) != "" ? "${var.prefix}-" : "") : "" +} + +############################################################################## +# Resource Group +############################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + existing_resource_group_name = var.existing_resource_group_name +} + +############################################################################# +# COS Bucket for VPC flow logs +############################################################################# + +# parse COS details from the existing COS instance CRN +module "existing_cos_crn_parser" { + count = var.existing_cos_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_cos_instance_crn +} + +locals { + cos_instance_guid = var.existing_cos_instance_crn != null ? module.existing_cos_crn_parser[0].service_instance : null + cos_account_id = var.existing_cos_instance_crn != null ? module.existing_cos_crn_parser[0].account_id : null + bucket_name = "${local.prefix}${var.flow_logs_cos_bucket_name}" + kms_guid = var.kms_encryption_enabled_bucket ? (length(module.existing_kms_key_crn_parser) > 0 ? module.existing_kms_key_crn_parser[0].service_instance : module.existing_kms_instance_crn_parser[0].service_instance) : null + kms_account_id = var.kms_encryption_enabled_bucket ? (length(module.existing_kms_key_crn_parser) > 0 ? module.existing_kms_key_crn_parser[0].account_id : module.existing_kms_instance_crn_parser[0].account_id) : null + kms_service_name = var.kms_encryption_enabled_bucket ? (length(module.existing_kms_key_crn_parser) > 0 ? module.existing_kms_key_crn_parser[0].service_name : module.existing_kms_instance_crn_parser[0].service_name) : null + cos_kms_key_crn = var.kms_encryption_enabled_bucket ? (length(module.existing_kms_key_crn_parser) > 0 ? var.existing_flow_logs_bucket_kms_key_crn : module.kms[0].keys[format("%s.%s", local.kms_key_ring_name, local.kms_key_name)].crn) : null + create_cos_kms_iam_auth_policy = var.enable_vpc_flow_logs && var.kms_encryption_enabled_bucket && !var.skip_cos_kms_iam_auth_policy + create_cross_account_cos_kms_auth_policy = (local.create_cos_kms_iam_auth_policy && var.ibmcloud_kms_api_key == null) ? false : (local.cos_account_id != local.kms_account_id) + + # configuration for the flow logs bucket + bucket_config = [{ + access_tags = var.access_tags + bucket_name = local.bucket_name + add_bucket_name_suffix = var.add_bucket_name_suffix + kms_encryption_enabled = var.kms_encryption_enabled_bucket + kms_guid = local.kms_guid + kms_key_crn = local.cos_kms_key_crn + skip_iam_authorization_policy = local.create_cross_account_cos_kms_auth_policy || var.skip_cos_kms_iam_auth_policy + management_endpoint_type = var.management_endpoint_type_for_bucket + storage_class = var.cos_bucket_class + resource_instance_id = var.existing_cos_instance_crn + region_location = var.region + force_delete = true + archive_rule = var.flow_logs_cos_bucket_archive_days != null ? { + enable = true + days = var.flow_logs_cos_bucket_archive_days + type = var.flow_logs_cos_bucket_archive_type + } : null + expire_rule = var.flow_logs_cos_bucket_expire_days != null ? { + enable = true + days = var.flow_logs_cos_bucket_expire_days + } : null + retention_rule = var.flow_logs_cos_bucket_enable_retention ? { + default = var.flow_logs_cos_bucket_default_retention_days + maximum = var.flow_logs_cos_bucket_maximum_retention_days + minimum = var.flow_logs_cos_bucket_minimum_retention_days + permanent = var.flow_logs_cos_bucket_enable_permanent_retention + } : null + object_versioning_enabled = var.flow_logs_cos_bucket_enable_object_versioning + }] +} + +# Create COS bucket using the defined bucket configuration +module "cos_buckets" { + count = var.enable_vpc_flow_logs ? 1 : 0 + depends_on = [time_sleep.wait_for_cross_account_authorization_policy[0]] + source = "terraform-ibm-modules/cos/ibm//modules/buckets" + version = "8.19.2" + bucket_configs = local.bucket_config +} + +# Create IAM Authorization Policy to allow COS to access KMS for the encryption key, if cross account KMS is passed in +resource "ibm_iam_authorization_policy" "cos_kms_policy" { + count = local.create_cross_account_cos_kms_auth_policy ? 1 : 0 + provider = ibm.kms + source_service_account = local.cos_account_id + source_service_name = "cloud-object-storage" + source_resource_instance_id = local.cos_instance_guid + roles = ["Reader"] + description = "Allow the COS instance ${local.cos_instance_guid} to read the ${local.kms_service_name} key ${local.cos_kms_key_crn} from the instance ${local.kms_guid}" + resource_attributes { + name = "serviceName" + operator = "stringEquals" + value = local.kms_service_name + } + resource_attributes { + name = "accountId" + operator = "stringEquals" + value = local.kms_account_id + } + resource_attributes { + name = "serviceInstance" + operator = "stringEquals" + value = local.kms_guid + } + resource_attributes { + name = "resourceType" + operator = "stringEquals" + value = "key" + } + resource_attributes { + name = "resource" + operator = "stringEquals" + value = local.cos_kms_key_crn + } + # Scope of policy now includes the key, so ensure to create new policy before + # destroying old one to prevent any disruption to every day services. + lifecycle { + create_before_destroy = true + } +} + +# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478 +resource "time_sleep" "wait_for_cross_account_authorization_policy" { + depends_on = [ibm_iam_authorization_policy.cos_kms_policy] + count = local.create_cross_account_cos_kms_auth_policy ? 1 : 0 + + create_duration = "30s" +} + +####################################################################################################################### +# KMS Key +####################################################################################################################### + +# parse KMS details from the existing KMS instance CRN +module "existing_kms_instance_crn_parser" { + count = var.kms_encryption_enabled_bucket && var.existing_kms_instance_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_kms_instance_crn +} + +# parse KMS details from the existing KMS instance CRN +module "existing_kms_key_crn_parser" { + count = var.kms_encryption_enabled_bucket && var.existing_flow_logs_bucket_kms_key_crn != null ? 1 : 0 + source = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser" + version = "1.1.0" + crn = var.existing_flow_logs_bucket_kms_key_crn +} + +locals { + # fetch KMS region from existing_kms_instance_crn if KMS resources are required + kms_region = var.kms_encryption_enabled_bucket && var.existing_kms_instance_crn != null ? module.existing_kms_instance_crn_parser[0].region : null + + kms_key_ring_name = "${local.prefix}${var.kms_key_ring_name}" + kms_key_name = "${local.prefix}${var.kms_key_name}" + + create_kms_key = (var.enable_vpc_flow_logs && var.kms_encryption_enabled_bucket) ? (var.existing_flow_logs_bucket_kms_key_crn == null ? (var.existing_kms_instance_crn != null ? true : false) : false) : false +} + +# KMS root key for flow logs COS bucket +module "kms" { + providers = { + ibm = ibm.kms + } + count = local.create_kms_key ? 1 : 0 # no need to create any KMS resources if not passing an existing KMS CRN or existing KMS key CRN is provided + source = "terraform-ibm-modules/kms-all-inclusive/ibm" + version = "4.19.5" + create_key_protect_instance = false + region = local.kms_region + existing_kms_instance_crn = var.existing_kms_instance_crn + key_ring_endpoint_type = var.kms_endpoint_type + key_endpoint_type = var.kms_endpoint_type + keys = [ + { + key_ring_name = local.kms_key_ring_name + existing_key_ring = false + keys = [ + { + key_name = local.kms_key_name + standard_key = false + rotation_interval_month = 3 + dual_auth_delete_enabled = false + force_delete = true + } + ] + } + ] +} + +############################################################################# +# VPC +############################################################################# + +locals { + # create 'use_public_gateways' object + public_gateway_object = { + for key, value in var.subnets : key => value != null ? length([for sub in value : sub.public_gateway if sub.public_gateway]) > 0 ? [for sub in value : sub.public_gateway if sub.public_gateway][0] : false : false + } +} + +# Create VPC +module "vpc" { + source = "../../" + resource_group_id = module.resource_group.resource_group_id + region = var.region + create_vpc = true + name = var.vpc_name + prefix = local.prefix != "" ? trimspace(var.prefix) : null + tags = var.resource_tags + access_tags = var.access_tags + subnets = var.subnets + default_network_acl_name = var.default_network_acl_name + default_security_group_name = var.default_security_group_name + default_routing_table_name = var.default_routing_table_name + network_acls = var.network_acls + security_group_rules = var.security_group_rules + clean_default_sg_acl = var.clean_default_security_group_acl + use_public_gateways = local.public_gateway_object + address_prefixes = var.address_prefixes + routes = var.routes + enable_vpc_flow_logs = var.enable_vpc_flow_logs + create_authorization_policy_vpc_to_cos = !var.skip_vpc_cos_iam_auth_policy + existing_cos_instance_guid = var.enable_vpc_flow_logs ? local.cos_instance_guid : null + existing_storage_bucket_name = var.enable_vpc_flow_logs ? module.cos_buckets[0].buckets[local.bucket_name].bucket_name : null + vpn_gateways = var.vpn_gateways +} + +############################################################################# +# VPE Gateway +############################################################################# + +module "vpe_gateway" { + source = "terraform-ibm-modules/vpe-gateway/ibm" + version = "4.5.0" + resource_group_id = module.resource_group.resource_group_id + region = var.region + prefix = local.prefix + security_group_ids = var.vpe_gateway_security_group_ids + vpc_name = module.vpc.vpc_name + vpc_id = module.vpc.vpc_id + subnet_zone_list = module.vpc.subnet_zone_list + cloud_services = var.vpe_gateway_cloud_services + cloud_service_by_crn = var.vpe_gateway_cloud_service_by_crn + service_endpoints = var.vpe_gateway_service_endpoints + reserved_ips = var.vpe_gateway_reserved_ips +} diff --git a/solutions/fully-configurable/outputs.tf b/solutions/fully-configurable/outputs.tf new file mode 100644 index 00000000..0a8cfef0 --- /dev/null +++ b/solutions/fully-configurable/outputs.tf @@ -0,0 +1,111 @@ +############################################################################## +# VPC +############################################################################## + +output "vpc_name" { + description = "Name of VPC created" + value = module.vpc.vpc_name +} + +output "vpc_id" { + description = "ID of VPC created" + value = module.vpc.vpc_id +} + +output "vpc_crn" { + description = "CRN of VPC created" + value = module.vpc.vpc_crn +} + +############################################################################## +# Public Gateways +############################################################################## + +output "public_gateways" { + description = "Map of public gateways by zone" + value = module.vpc.public_gateways +} + +############################################################################## +# VPC flow logs +############################################################################## + +output "vpc_flow_logs" { + description = "Details of VPC flow logs collector" + value = module.vpc.vpc_flow_logs +} + +############################################################################## +# Network ACLs +############################################################################## + +output "network_acls" { + description = "List of shortnames and IDs of network ACLs" + value = module.vpc.network_acls +} + +############################################################################## +# Subnet Outputs +############################################################################## + +output "subnet_ids" { + description = "The IDs of the subnets" + value = module.vpc.subnet_ids +} + +output "private_path_subnet_id" { + description = "The IDs of the subnets" + value = length(module.vpc.subnet_ids) > 0 ? module.vpc.subnet_ids[0] : null +} + +output "subnet_detail_list" { + description = "A list of subnets containing names, CIDR blocks, and zones." + value = module.vpc.subnet_detail_list +} + +output "subnet_zone_list" { + description = "A list containing subnet IDs and subnet zones" + value = module.vpc.subnet_zone_list +} + +output "subnet_detail_map" { + description = "A map of subnets containing IDs, CIDR blocks, and zones" + value = module.vpc.subnet_detail_map +} + +############################################################################## +# VPN Gateways Outputs +############################################################################## + +output "vpn_gateways_name" { + description = "List of names of VPN gateways." + value = module.vpc.vpn_gateways_name +} + +output "vpn_gateways_data" { + description = "Details of VPN gateways data" + value = module.vpc.vpn_gateways_data +} + +############################################################################## +# VPE Outputs +############################################################################## + +output "vpe_ips" { + description = "The reserved IPs for endpoint gateways." + value = module.vpe_gateway.vpe_ips +} + +output "vpe_crn" { + description = "The CRN of the endpoint gateway" + value = module.vpe_gateway.crn +} + +############################################################################## +# Security Group Details +############################################################################## + +output "security_group_details" { + description = "Details of security group." + value = module.vpc.security_group_details +} diff --git a/solutions/fully-configurable/provider.tf b/solutions/fully-configurable/provider.tf new file mode 100644 index 00000000..b97eb3ca --- /dev/null +++ b/solutions/fully-configurable/provider.tf @@ -0,0 +1,16 @@ +######################################################################################################################## +# Provider config +######################################################################################################################## + +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region + visibility = var.provider_visibility +} + +provider "ibm" { + alias = "kms" + ibmcloud_api_key = var.ibmcloud_kms_api_key != null ? var.ibmcloud_kms_api_key : var.ibmcloud_api_key + region = local.kms_region + visibility = var.provider_visibility +} diff --git a/solutions/fully-configurable/variables.tf b/solutions/fully-configurable/variables.tf new file mode 100644 index 00000000..bef9415d --- /dev/null +++ b/solutions/fully-configurable/variables.tf @@ -0,0 +1,698 @@ +############################################################################## +# Input Variables +############################################################################## + +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API key to deploy resources." + sensitive = true +} + +variable "provider_visibility" { + description = "Set the visibility value for the IBM terraform provider. Supported values are `public`, `private`, `public-and-private`. [Learn more](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/guides/custom-service-endpoints)." + type = string + default = "private" + + validation { + condition = contains(["public", "private", "public-and-private"], var.provider_visibility) + error_message = "Invalid visibility option. Allowed values are 'public', 'private', or 'public-and-private'." + } +} + +variable "existing_resource_group_name" { + type = string + description = "The name of an existing resource group to provision the resources." + default = "Default" +} + +variable "prefix" { + type = string + nullable = true + description = "Prefix to add to all the resources created by this solution. To not use any prefix value, you can set this value to `null` or an empty string." + + validation { + condition = (var.prefix == null ? true : + alltrue([ + can(regex("^[a-z]{0,1}[-a-z0-9]{0,14}[a-z0-9]{0,1}$", var.prefix)), + length(regexall("^.*--.*", var.prefix)) == 0 + ]) + ) + error_message = "Prefix must begin with a lowercase letter, contain only lowercase letters, numbers, and - characters. Prefixes must end with a lowercase letter or number and be 16 or fewer characters." + } +} + +variable "vpc_name" { + default = "vpc" + description = "Name of the VPC. If a prefix input variable is specified, the prefix is added to the name in the `-` format." + type = string +} + +variable "region" { + default = "us-south" + description = "Region to deploy the VPC." + type = string +} + +variable "resource_tags" { + type = list(string) + description = "The list of tags to add to the VPC instance." + default = [] +} + +variable "access_tags" { + type = list(string) + description = "The list of access tags to add to the VPC instance." + default = [] +} + +############################################################################## +# Subnets +############################################################################## + +variable "subnets" { + description = "List of subnets for the vpc. For each item in each array, a subnet will be created. Items can be either CIDR blocks or total ipv4 addressess. Public gateways will be enabled only in zones where a gateway has been created. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#subnets-)." + type = object({ + zone-1 = list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + })) + zone-2 = optional(list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + }))) + zone-3 = optional(list(object({ + name = string + cidr = string + public_gateway = optional(bool) + acl_name = string + no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) + }))) + }) + + default = { + zone-1 = [ + { + name = "subnet-a" + cidr = "10.10.10.0/24" + public_gateway = true + acl_name = "vpc-acl" + no_addr_prefix = false + } + ] + } + + validation { + condition = alltrue([for key, value in var.subnets : value != null ? length([for subnet in value : subnet.public_gateway if subnet.public_gateway]) > 1 ? false : true : true]) + error_message = "var.subnets has more than one public gateway in a zone. Only one public gateway can be attached to a zone for the virtual private cloud." + } +} + +############################################################################## +# Network ACLs +############################################################################## + +variable "network_acls" { + description = "The list of ACLs to create. Provide at least one rule for each ACL. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#network-acls-)." + type = list( + object({ + name = string + add_ibm_cloud_internal_rules = optional(bool) + add_vpc_connectivity_rules = optional(bool) + prepend_ibm_rules = optional(bool) + rules = list( + object({ + name = string + action = string + destination = string + direction = string + source = string + tcp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + udp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + icmp = optional( + object({ + type = optional(number) + code = optional(number) + }) + ) + }) + ) + }) + ) + + default = [ + { + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [ + { + name = "allow-all-443-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 443 + port_max = 443 + source_port_min = 443 + source_port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 80 + port_max = 80 + source_port_min = 80 + source_port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-22-inbound" + action = "allow" + direction = "inbound" + tcp = { + port_min = 22 + port_max = 22 + source_port_min = 22 + source_port_max = 22 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-443-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 443 + source_port_max = 443 + port_min = 443 + port_max = 443 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-80-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 80 + source_port_max = 80 + port_min = 80 + port_max = 80 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + }, + { + name = "allow-all-22-outbound" + action = "allow" + direction = "outbound" + tcp = { + source_port_min = 22 + source_port_max = 22 + port_min = 22 + port_max = 22 + } + destination = "0.0.0.0/0" + source = "0.0.0.0/0" + } + ] + } + ] + + validation { + error_message = "ACL rule actions can only be `allow` or `deny`." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false action is not valid + false if !contains(["allow", "deny"], rule.action) + ]) + )) == 0 + } + + validation { + error_message = "ACL rule direction can only be `inbound` or `outbound`." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false if direction is not valid + false if !contains(["inbound", "outbound"], rule.direction) + ]) + )) == 0 + } + + validation { + error_message = "ACL rule names must match the regex pattern ^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$." + condition = length(distinct( + flatten([ + # Check through rules + for rule in flatten([var.network_acls[*].rules]) : + # Return false if direction is not valid + false if !can(regex("^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", rule.name)) + ]) + )) == 0 + } + +} + +############################################################################## +# Default Security Group Rules +############################################################################## + +variable "security_group_rules" { + description = "A list of security group rules to be added to the default vpc security group (default empty). [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#security-group-rules-)." + default = [] + type = list( + object({ + name = string + direction = string + remote = optional(string) + tcp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + }) + ) + udp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + }) + ) + icmp = optional( + object({ + type = optional(number) + code = optional(number) + }) + ) + }) + ) + + validation { + error_message = "Security group rule direction can only be `inbound` or `outbound`." + condition = (var.security_group_rules == null || length(var.security_group_rules) == 0) ? true : length(distinct( + flatten([ + # Check through rules + for rule in var.security_group_rules : + # Return false if direction is not valid + false if !contains(["inbound", "outbound"], rule.direction) + ]) + )) == 0 + } + + validation { + error_message = "Security group rule names must match the regex pattern ^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$." + condition = (var.security_group_rules == null || length(var.security_group_rules) == 0) ? true : length(distinct( + flatten([ + # Check through rules + for rule in var.security_group_rules : + # Return false if direction is not valid + false if !can(regex("^([a-z]|[a-z][-a-z0-9]*[a-z0-9])$", rule.name)) + ]) + )) == 0 + } +} + +variable "clean_default_security_group_acl" { + description = "Remove all rules from the default VPC security group and VPC ACL (less permissive)" + type = bool + nullable = false + default = true +} + +############################################################################## +# Address Prefixes +############################################################################## + +variable "address_prefixes" { + description = "The IP range that will be defined for the VPC for a certain location. Use only with manual address prefixes. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#address-prefixes-)." + type = object({ + zone-1 = optional(list(string)) + zone-2 = optional(list(string)) + zone-3 = optional(list(string)) + }) + default = { + zone-1 = null + zone-2 = null + zone-3 = null + } + validation { + error_message = "Keys for `use_public_gateways` must be in the order `zone-1`, `zone-2`, `zone-3`." + condition = var.address_prefixes == null ? true : ( + (length(var.address_prefixes) == 1 && keys(var.address_prefixes)[0] == "zone-1") || + (length(var.address_prefixes) == 2 && keys(var.address_prefixes)[0] == "zone-1" && keys(var.address_prefixes)[1] == "zone-2") || + (length(var.address_prefixes) == 3 && keys(var.address_prefixes)[0] == "zone-1" && keys(var.address_prefixes)[1] == "zone-2") && keys(var.address_prefixes)[2] == "zone-3" + ) + } +} + +############################################################################## +# Add routes to VPC +############################################################################## + +variable "routes" { + description = "Allows you to specify the next hop for packets based on their destination address. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#routes-)." + type = list( + object({ + name = string + route_direct_link_ingress = optional(bool) + route_transit_gateway_ingress = optional(bool) + route_vpc_zone_ingress = optional(bool) + routes = optional( + list( + object({ + action = optional(string) + zone = number + destination = string + next_hop = string + }) + )) + }) + ) + default = [] +} + +############################################################################## +# VPC Flow Logs +############################################################################## + +variable "enable_vpc_flow_logs" { + description = "To enable VPC Flow logs, set this to true." + type = bool + nullable = false + default = false +} + +variable "skip_vpc_cos_iam_auth_policy" { + description = "To skip creating an IAM authorization policy that allows the VPC to access the Cloud Object Storage, set this variable to `true`. Required only if `enable_vpc_flow_logs` is set to true." + type = bool + nullable = false + default = false +} + +variable "existing_cos_instance_crn" { + description = "CRN of the existing COS instance. It is only required if `enable_vpc_flow_logs` is set to true and will be used to create the flow logs bucket." + type = string + default = null + + validation { + condition = var.enable_vpc_flow_logs ? (var.existing_cos_instance_crn != null ? true : false) : true + error_message = "'existing_cos_instance_crn' is required if 'enable_vpc_flow_logs' is set to true." + } +} + +variable "flow_logs_cos_bucket_name" { + description = "Name of the Cloud Object Storage bucket to be created to collect VPC flow logs." + type = string + default = "flow-logs-bucket" +} + +variable "kms_encryption_enabled_bucket" { + description = "Set to true to encrypt the Cloud Object Storage Flow Logs bucket with a KMS key. If set to true, a value must be passed for existing_flow_logs_bucket_kms_key_crn (to use that key) or existing_kms_instance_crn (to create a new key). Value cannot be set to true if enable_vpc_flow_logs is set to false." + type = bool + nullable = false + default = false + + validation { + condition = !var.enable_vpc_flow_logs ? (var.kms_encryption_enabled_bucket ? false : true) : true + error_message = "'kms_encryption_enabled_bucket' can not be true if 'enable_vpc_flow_logs' is set to false." + } + + validation { + condition = var.enable_vpc_flow_logs && var.kms_encryption_enabled_bucket ? ((var.existing_flow_logs_bucket_kms_key_crn != null || var.existing_kms_instance_crn != null) ? true : false) : true + error_message = "Either 'existing_flow_logs_bucket_kms_key_crn' or 'existing_kms_instance_crn' is required if 'enable_vpc_flow_logs' and 'kms_encryption_enabled_bucket' are set to true." + } +} + +variable "skip_cos_kms_iam_auth_policy" { + type = bool + nullable = false + description = "To skip creating an IAM authorization policy that allows Cloud Object Storage(COS) to access KMS key." + default = false +} + +variable "management_endpoint_type_for_bucket" { + description = "The type of endpoint for the IBM Terraform provider to use to manage Cloud Object Storage buckets (`public`, `private`, or `direct`). If you are using a private endpoint, make sure that you enable virtual routing and forwarding (VRF) in your account, and that the Terraform runtime can access the IBM Cloud Private network." + type = string + default = "direct" + validation { + condition = contains(["public", "private", "direct"], var.management_endpoint_type_for_bucket) + error_message = "The specified `management_endpoint_type_for_bucket` is not valid. Specify a valid type of endpoint for the IBM Terraform provider to use to manage Cloud Object Storage buckets." + } +} + +variable "cos_bucket_class" { + type = string + default = "standard" + description = "The storage class of the newly provisioned Cloud Object Storage bucket. Specify one of the following values for the storage class: `standard`, `vault`, `cold`, `smart` (default), or `onerate_active`." + validation { + condition = contains(["standard", "vault", "cold", "smart", "onerate_active"], var.cos_bucket_class) + error_message = "Specify one of the following values for the `cos_bucket_class`: `standard`, `vault`, `cold`, `smart`, or `onerate_active`." + } +} + +variable "add_bucket_name_suffix" { + type = bool + nullable = false + description = "Add a randomly generated suffix that is 4 characters in length, to the name of the newly provisioned Cloud Object Storage bucket. Do not use this suffix if you are passing the existing Cloud Object Storage bucket. To manage the name of the Cloud Object Storage bucket manually, use the `flow_logs_cos_bucket_name` variables." + default = true +} + +variable "flow_logs_cos_bucket_archive_days" { + description = "The number of days before the `archive_type` rule action takes effect for the flow logs cloud object storage bucket." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_archive_type" { + description = "The storage class or archive type you want the object to transition to in the flow logs cloud object storage bucket." + type = string + default = "Glacier" + validation { + condition = contains(["Glacier", "Accelerated"], var.flow_logs_cos_bucket_archive_type) + error_message = "The specified flow_logs_cos_bucket_archive_type is not a valid selection!" + } +} + +variable "flow_logs_cos_bucket_expire_days" { + description = "The number of days before the expire rule action takes effect for the flow logs cloud object storage bucket." + type = number + default = 366 +} + +variable "flow_logs_cos_bucket_enable_object_versioning" { + description = "Set it to true if object versioning is enabled so that multiple versions of an object are retained in the flow logs cloud object storage bucket. Cannot be used if `flow_logs_cos_bucket_enable_retention` is true." + type = bool + nullable = false + default = false + + validation { + condition = var.flow_logs_cos_bucket_enable_object_versioning ? (var.flow_logs_cos_bucket_enable_retention ? false : true) : true + error_message = "`flow_logs_cos_bucket_enable_object_versioning` cannot set true if `flow_logs_cos_bucket_enable_retention` is true." + } +} + +variable "flow_logs_cos_bucket_enable_retention" { + description = "Set to true to enable retention for the flow logs cloud object storage bucket." + type = bool + nullable = false + default = false +} + +variable "flow_logs_cos_bucket_default_retention_days" { + description = "The number of days that an object can remain unmodified in the flow logs cloud object storage bucket." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_maximum_retention_days" { + description = "The maximum number of days that an object can be kept unmodified in the flow logs cloud object storage." + type = number + default = 350 +} + +variable "flow_logs_cos_bucket_minimum_retention_days" { + description = "The minimum number of days that an object must be kept unmodified in the flow logs cloud object storage." + type = number + default = 90 +} + +variable "flow_logs_cos_bucket_enable_permanent_retention" { + description = "Whether permanent retention status is enabled for the flow logs cloud object storage bucket. [Learn more](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-immutable)." + type = bool + nullable = false + default = false +} + +############################################################################################################### +# KMS +############################################################################################################### + +variable "existing_flow_logs_bucket_kms_key_crn" { + type = string + default = null + description = "The CRN of the existing root key of key management service (KMS) that is used to encrypt the flow logs Cloud Object Storage bucket. If no value is set for this variable, specify a value for the `existing_kms_instance_crn` variable to create a key ring and key." +} + +variable "existing_kms_instance_crn" { + type = string + default = null + description = "The CRN of the existing key management service (KMS) that is used to create keys for encrypting the flow logs Cloud Object Storage bucket. Used to create a new KMS key unless an existing key is passed using the `existing_flow_logs_bucket_kms_key_crn` input." +} + +variable "kms_endpoint_type" { + type = string + description = "The type of endpoint to use for communicating with the KMS. Possible values: `public`, `private`. Applies only if `existing_flow_logs_bucket_kms_key_crn` is not specified." + default = "private" + validation { + condition = can(regex("public|private", var.kms_endpoint_type)) + error_message = "Valid values for the `kms_endpoint_type_value` are `public` or `private`." + } +} + +variable "kms_key_ring_name" { + type = string + default = "flow-logs-cos-key-ring" + description = "The name of the key ring to create for the Cloud Object Storage bucket key. If an existing key is used, this variable is not required. If the prefix input variable is passed, the name of the key ring is prefixed to the value in the `-value` format." +} + +variable "kms_key_name" { + type = string + default = "flow-logs-cos-key" + description = "The name of the key to encrypt the flow logs Cloud Object Storage bucket. If an existing key is used, this variable is not required. If the prefix input variable is passed, the name of the key is prefixed to the value in the `-value` format." +} + +variable "ibmcloud_kms_api_key" { + type = string + description = "The IBM Cloud API key that can create a root key and key ring in the key management service (KMS) instance. If not specified, the 'ibmcloud_api_key' variable is used. Specify this key if the instance in `existing_kms_instance_crn` is in an account that's different from the Cloud Object Storage instance. Leave this input empty if the same account owns both instances." + sensitive = true + default = null +} + +############################################################################## +# Optional VPC Variables +############################################################################## + +variable "default_network_acl_name" { + description = "Name of the Default ACL. If null, a name will be automatically generated." + type = string + default = null +} + +variable "default_security_group_name" { + description = "Name of the Default Security Group. If null, a name will be automatically generated." + type = string + default = null +} + +variable "default_routing_table_name" { + description = "Name of the Default Routing Table. If null, a name will be automatically generated." + type = string + default = null +} + +############################################################################## +# VPN Gateways +############################################################################## + +variable "vpn_gateways" { + description = "List of VPN Gateways to create. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpn-gateways-)." + nullable = false + type = list( + object({ + name = string + subnet_name = string # Do not include prefix, use same name as in `var.subnets` + mode = optional(string) + resource_group = optional(string) + access_tags = optional(list(string), []) + }) + ) + + default = [] +} + +############################################################################## +# VPE Gateways +############################################################################## + +variable "vpe_gateway_cloud_services" { + description = "The list of cloud services used to create endpoint gateways. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpe-gateway-cloud-services-)." + type = set(object({ + service_name = string + vpe_name = optional(string), # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name. + allow_dns_resolution_binding = optional(bool, false) + })) + default = [] +} + +variable "vpe_gateway_cloud_service_by_crn" { + description = "The list of cloud service CRNs used to create endpoint gateways. Use this list to identify services that are not supported by service name in the `cloud_services` variable. For a list of supported services, see [VPE-enabled services](https://cloud.ibm.com/docs/vpc?topic=vpc-vpe-supported-services). If `service_name` is not specified, the CRN is used to find the name. If `vpe_name` is not specified in the list, VPE names are created in the format `--`. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#vpe-gateway-cloud-service-by-crn-)." + type = set( + object({ + crn = string + vpe_name = optional(string) # Full control on the VPE name. If not specified, the VPE name will be computed based on prefix, vpc name and service name. + service_name = optional(string) # Name of the service used to compute the name of the VPE. If not specified, the service name will be obtained from the crn. + allow_dns_resolution_binding = optional(bool, true) + }) + ) + default = [] +} + +variable "vpe_gateway_service_endpoints" { + description = "Service endpoints to use to create endpoint gateways. Can be `public`, or `private`." + type = string + default = "private" + + validation { + error_message = "Service endpoints can only be `public` or `private`." + condition = contains(["public", "private"], var.vpe_gateway_service_endpoints) + } +} + +variable "vpe_gateway_security_group_ids" { + description = "List of security group ids to attach to each endpoint gateway." + type = list(string) + default = null # Let this default value be null instead of []. Provider issue - https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4546 +} + +variable "vpe_gateway_reserved_ips" { + description = "Map of existing reserved IP names and values. Leave this value as default if you want to create new reserved ips, this value is used when a user passes their existing reserved ips created here and not attempt to recreate those. [Learn more](https://github.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/blob/main/solutions/fully-configurable/DA-types.md#reserved-ips-)." + type = object({ + name = optional(string) # reserved ip name + }) + default = {} +} diff --git a/solutions/fully-configurable/version.tf b/solutions/fully-configurable/version.tf new file mode 100644 index 00000000..6015f671 --- /dev/null +++ b/solutions/fully-configurable/version.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.9.0" + required_providers { + # Lock DA into an exact provider version - renovate automation will keep it updated + ibm = { + source = "IBM-Cloud/ibm" + version = "1.76.1" + } + time = { + source = "hashicorp/time" + version = "0.13.0" + } + } +} diff --git a/tests/pr_test.go b/tests/pr_test.go index 1fed344e..b935b54e 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/common" "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" + "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testschematic" ) const basicExampleTerraformDir = "examples/basic" @@ -26,6 +27,7 @@ const existingVPCExampleTerraformDir = "examples/existing_vpc" const specificZoneExampleTerraformDir = "examples/specific-zone-only" const noprefixExampleTerraformDir = "examples/no-prefix" const vpcWithDnsExampleTerraformDir = "examples/vpc-with-dns" +const fullyConfigFlavorDir = "solutions/fully-configurable" const resourceGroup = "geretain-test-resources" // Define a struct with fields that match the structure of the YAML data @@ -201,3 +203,93 @@ func TestRunVpcWithDnsExample(t *testing.T) { assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } + +// Test the fully-configurable DA with defaults (no flow logs) +func TestFullyConfigurable(t *testing.T) { + t.Parallel() + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + // Programmatically determine region to use based on availability + region, _ := testhelper.GetBestVpcRegion(val, "../common-dev-assets/common-go-assets/cloudinfo-region-vpc-gen2-prefs.yaml", "eu-de") + + prefix := "vpc-da" + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + "dynamic_values/*.tf", + "dynamic_values/config_modules/*/*.tf", + fullyConfigFlavorDir + "/*.tf", + }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"vpc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 120, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "region", Value: options.Region, DataType: "string"}, + {Name: "resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + } + + err := options.RunSchematicTest() + assert.Nil(t, err, "This should not have errored") +} + +// Test the upgrade of fully-configurable DA with defaults +func TestRunUpgradeFullyConfigurable(t *testing.T) { + t.Parallel() + + // Verify ibmcloud_api_key variable is set + checkVariable := "TF_VAR_ibmcloud_api_key" + val, present := os.LookupEnv(checkVariable) + require.True(t, present, checkVariable+" environment variable not set") + require.NotEqual(t, "", val, checkVariable+" environment variable is empty") + + // Programmatically determine region to use based on availability + region, _ := testhelper.GetBestVpcRegion(val, "../common-dev-assets/common-go-assets/cloudinfo-region-vpc-gen2-prefs.yaml", "eu-de") + + prefix := "vpc-upg" + + options := testschematic.TestSchematicOptionsDefault(&testschematic.TestSchematicOptions{ + Testing: t, + Region: region, + Prefix: prefix, + TarIncludePatterns: []string{ + "*.tf", + "dynamic_values/*.tf", + "dynamic_values/config_modules/*/*.tf", + fullyConfigFlavorDir + "/*.tf", + }, + TemplateFolder: fullyConfigFlavorDir, + Tags: []string{"vpc-da-test"}, + DeleteWorkspaceOnFail: false, + WaitJobCompleteMinutes: 120, + }) + + options.TerraformVars = []testschematic.TestSchematicTerraformVar{ + {Name: "ibmcloud_api_key", Value: options.RequiredEnvironmentVars["TF_VAR_ibmcloud_api_key"], DataType: "string", Secure: true}, + {Name: "existing_resource_group_name", Value: resourceGroup, DataType: "string"}, + {Name: "region", Value: options.Region, DataType: "string"}, + {Name: "resource_tags", Value: options.Tags, DataType: "list(string)"}, + {Name: "access_tags", Value: permanentResources["accessTags"], DataType: "list(string)"}, + {Name: "prefix", Value: options.Prefix, DataType: "string"}, + } + + err := options.RunSchematicUpgradeTest() + if !options.UpgradeTestSkipped { + assert.Nil(t, err, "This should not have errored") + } +} diff --git a/variables.tf b/variables.tf index 6428db7f..f0508036 100644 --- a/variables.tf +++ b/variables.tf @@ -319,6 +319,7 @@ variable "subnets" { public_gateway = optional(bool) acl_name = string no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) })) zone-2 = optional(list(object({ name = string @@ -326,6 +327,7 @@ variable "subnets" { public_gateway = optional(bool) acl_name = string no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) }))) zone-3 = optional(list(object({ name = string @@ -333,6 +335,7 @@ variable "subnets" { public_gateway = optional(bool) acl_name = string no_addr_prefix = optional(bool, false) # do not automatically add address prefix for subnet, overrides other conditions if set to true + subnet_tags = optional(list(string), []) }))) }) @@ -406,7 +409,7 @@ variable "security_group_rules" { object({ name = string direction = string - remote = string + remote = optional(string) tcp = optional( object({ port_max = optional(number) @@ -718,3 +721,22 @@ variable "dns_records" { error_message = "Invalid MX record configuration. For 'MX' records, value for 'preference' must be provided." } } + +############################################################################## +# VPN Gateways +############################################################################## + +variable "vpn_gateways" { + description = "List of VPN gateways to create." + nullable = false + type = list( + object({ + name = string + subnet_name = string # Do not include prefix, use same name as in `var.subnets` + mode = optional(string) + resource_group = optional(string) + access_tags = optional(list(string), []) + }) + ) + default = [] +}