Skip to content

Commit

Permalink
feat: allow use of existing reserved ip for endpoints (#415) <br> - P…
Browse files Browse the repository at this point in the history
…rovides a way to create a reserved ip independently from the VPE creation. <br> - New optional input variable `reserved_ips` can be used to supply existing IPs <br> - New submodule `modules/reserved-ips` which can be used to manage reserved IPs separate from VPE module

* feat: add reserved ip submodule

* fix: disable dns-svc for time being

---------

Co-authored-by: Jordan-Williams2 <[email protected]>
  • Loading branch information
jor2 and Jordan-Williams2 authored Nov 21, 2024
1 parent c528b11 commit a32c967
Show file tree
Hide file tree
Showing 17 changed files with 581 additions and 15 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This module creates and configures virtual private endpoint gateways (https://cl
The module supports the following actions:
- Create virtual private endpoint gateways
- Create reserved IP addresses
- Attach endpoint gateways to reserved IP addresses
- Attach endpoint gateways to reserved IP addresses.

### Known provider issues

Expand All @@ -21,9 +21,12 @@ An IBM Provider [issue](https://github.com/IBM-Cloud/terraform-provider-ibm/issu
<!-- BEGIN OVERVIEW HOOK -->
## Overview
* [terraform-ibm-vpe-gateway](#terraform-ibm-vpe-gateway)
* [Submodules](./modules)
* [reserved-ips](./modules/reserved-ips)
* [Examples](./examples)
* [Advanced dedicated service VPE gateway](./examples/advanced)
* [Basic multi-tenant VPE gateway](./examples/basic)
* [Existing Reserved IPs example](./examples/reserved-ips)
* [Contributing](#contributing)
<!-- END OVERVIEW HOOK -->

Expand Down Expand Up @@ -103,13 +106,14 @@ You need the following permissions to run this module.

### Modules

No modules.
| Name | Source | Version |
|------|--------|---------|
| <a name="module_ip"></a> [ip](#module\_ip) | ./modules/reserved-ips | n/a |

### Resources

| Name | Type |
|------|------|
| [ibm_is_subnet_reserved_ip.ip](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_subnet_reserved_ip) | resource |
| [ibm_is_virtual_endpoint_gateway.vpe](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_virtual_endpoint_gateway) | resource |
| [ibm_is_virtual_endpoint_gateway_ip.endpoint_gateway_ip](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/is_virtual_endpoint_gateway_ip) | resource |
| [ibm_is_virtual_endpoint_gateway.vpe](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/data-sources/is_virtual_endpoint_gateway) | data source |
Expand All @@ -120,8 +124,9 @@ No modules.
|------|-------------|------|---------|:--------:|
| <a name="input_cloud_service_by_crn"></a> [cloud\_service\_by\_crn](#input\_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 `<prefix>-<vpc_name>-<service_name>`. The value that you specify for `vpc_name` must be known at Terraform plan time. | <pre>set(<br/> object({<br/> crn = string<br/> 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.<br/> 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.<br/> allow_dns_resolution_binding = optional(bool, true)<br/> })<br/> )</pre> | `[]` | no |
| <a name="input_cloud_services"></a> [cloud\_services](#input\_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 `<prefix>-<vpc_name>-<service_name>`. The value that you specify for `vpc_name` must be known at Terraform plan time. | <pre>set(object({<br/> service_name = string<br/> 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.<br/> allow_dns_resolution_binding = optional(bool, false)<br/> }))</pre> | `[]` | no |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The prefix that you would like to append to your resources | `string` | `"vpe"` | no |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | The prefix that you would like to append to your resources. Value is only used if no value is passed for the `vpe_name` option in the `cloud_services` input variable. | `string` | `"vpe"` | no |
| <a name="input_region"></a> [region](#input\_region) | The region where VPC and services are deployed | `string` | `"us-south"` | no |
| <a name="input_reserved_ips"></a> [reserved\_ips](#input\_reserved\_ips) | Map of existing reserved IP names and values. If you wish to create your reserved ips independently and not create new ones you can first run the `reserved-ips` submodule and then copy the output `reserved_ip_map` here. | <pre>object({<br/> name = optional(string) # reserved ip name<br/> })</pre> | `{}` | no |
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | ID of the resource group where endpoint gateways will be provisioned | `string` | `null` | no |
| <a name="input_security_group_ids"></a> [security\_group\_ids](#input\_security\_group\_ids) | List of security group ids to attach to each endpoint gateway. | `list(string)` | `null` | no |
| <a name="input_service_endpoints"></a> [service\_endpoints](#input\_service\_endpoints) | Service endpoints to use to create endpoint gateways. Can be `public`, or `private`. | `string` | `"private"` | no |
Expand Down
1 change: 0 additions & 1 deletion examples/advanced/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ module "vpes" {
{
service_name = "cloud-object-storage"
}

]
cloud_service_by_crn = [
{
Expand Down
15 changes: 15 additions & 0 deletions examples/reserved-ips/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Existing Reserved IPs example

This example creates reserved ips in the example and passes those values to the main modules `reserved_ips` variable which will use those existing reserved ips instead of creating new values.

This example creates the following infrastructure:
- A resource group, if one is not passed in.
- A VPC, if one is not passed in.
- The VPC is created with three subnets across the three availability zones of the region that is passed as input.
- A security group in the VPC.
- The security group is created with a single inbound rule that allows traffic from resources that are attached to the default VPC security group. This rule is added as an example.
- The reserved IPs are created. These are later passed to the gateway as an example of how the reserved IPs module could be used.
- Two virtual private endpoint (VPE) gateways. By default, one VPE to COS and another VPE to Key Protect are created. You can change the defaults by using the `service_endpoints` input.
- Each of the two virtual private endpoint gateways are attached to the three VPC subnets.
- The new security group is attached to the two VPE gateways.
- Passes existing reserved ip values to be used instead of creating new ones.
96 changes: 96 additions & 0 deletions examples/reserved-ips/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
##############################################################################
# Resource Group
##############################################################################
module "resource_group" {
source = "terraform-ibm-modules/resource-group/ibm"
version = "1.0.6"
# if an existing resource group is not set (null) create a new one using prefix
resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null
existing_resource_group_name = var.resource_group
}

##############################################################################
# Create a VPC for this example using defaults from terraform-ibm-landing-zone-vpc
# ( 3 subnets across the 3 AZs in the region )
##############################################################################

module "vpc" {
count = var.vpc_id != null ? 0 : 1
source = "terraform-ibm-modules/landing-zone-vpc/ibm"
version = "7.5.0"
resource_group_id = module.resource_group.resource_group_id
region = var.region
prefix = var.prefix
name = var.vpc_name
tags = var.resource_tags
}

##############################################################################
# Demonstrate how to create a custom security group that is applied to the VPEs
# This examples allow all workload associated with the default VPC security group
# to interact with the VPEs
##############################################################################

data "ibm_is_vpc" "vpc" {
# Explicit depends as the vpc_name is known prior to VPC creation
depends_on = [
module.vpc
]
name = var.vpc_id != null ? var.vpc_id : module.vpc[0].vpc_name
}

data "ibm_is_security_group" "default_sg" {
name = data.ibm_is_vpc.vpc.default_security_group_name
}

module "vpe_security_group" {
source = "terraform-ibm-modules/security-group/ibm"
version = "2.0.0"
security_group_name = "${var.prefix}-vpe-sg"
add_ibm_cloud_internal_rules = false # No need for the internal ibm cloud rules for SG associated with VPEs

security_group_rules = [{
name = "allow-all-default-sg-inbound"
direction = "inbound"
remote = data.ibm_is_security_group.default_sg.id
}]

resource_group = module.resource_group.resource_group_id
vpc_id = var.vpc_id != null ? var.vpc_id : module.vpc[0].vpc_id
}

##############################################################################
# Create Reserved IPs in the VPC
##############################################################################
module "ips" {
source = "../../modules/reserved-ips"
region = var.region
subnet_zone_list = var.vpc_id != null ? var.subnet_zone_list : module.vpc[0].subnet_zone_list
reserved_ips = {}
reserved_ip_cloud_services = [
{
service_name = "kms"
},
{
service_name = "cloud-object-storage"
}
]
}

##############################################################################
# Create VPEs in the VPC
##############################################################################
module "vpes" {
source = "../../"
region = var.region
prefix = var.prefix
vpc_name = var.vpc_name
vpc_id = var.vpc_id != null ? var.vpc_id : module.vpc[0].vpc_id
subnet_zone_list = var.vpc_id != null ? var.subnet_zone_list : module.vpc[0].subnet_zone_list
resource_group_id = module.resource_group.resource_group_id
security_group_ids = var.security_group_ids != null ? var.security_group_ids : [module.vpe_security_group.security_group_id]
service_endpoints = var.service_endpoints
reserved_ips = module.ips.reserved_ip_map
}

##############################################################################
25 changes: 25 additions & 0 deletions examples/reserved-ips/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
output "vpe_ips" {
description = "The endpoint gateway reserved ips"
value = module.vpes.vpe_ips
}

output "crn" {
description = "The CRN of the endpoint gateway"
value = module.vpes.crn
}


output "reserved_ips" {
description = "The map of reserved ips created in the example"
value = module.ips.reserved_ip_map
}

output "endpoint_ip_list" {
description = "The endpoint ip list created in the example"
value = module.ips.endpoint_ip_list
}

output "subnet_zone_list" {
description = "The subnet zone list created in the example"
value = var.vpc_id != null ? var.subnet_zone_list : module.vpc[0].subnet_zone_list
}
4 changes: 4 additions & 0 deletions examples/reserved-ips/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
provider "ibm" {
ibmcloud_api_key = var.ibmcloud_api_key
region = var.region
}
83 changes: 83 additions & 0 deletions examples/reserved-ips/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
variable "ibmcloud_api_key" {
type = string
description = "The IBM Cloud API Key"
sensitive = true
}

variable "region" {
description = "The region where VPC and services are deployed"
type = string
default = "us-south"
}

variable "prefix" {
description = "The prefix that you would like to append to your resources"
type = string
default = "vpe"
}

variable "resource_group" {
type = string
description = "An existing resource group name to use for this example, if unset a new resource group will be created"
default = null
}

##############################################################################
# VPC Variables
##############################################################################

variable "vpc_name" {
description = "Name of the VPC where the Endpoint Gateways will be created. This value is used to dynamically generate VPE names. It is also used to create a VPC when the vpc_id input is set to null."
type = string
default = "vpc-instance"
}

variable "vpc_id" {
description = "ID of the VPC where the Endpoint Gateways will be created. Creates a VPC if set to null."
type = string
default = null
}

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

##############################################################################
# VPE Variables
##############################################################################

variable "subnet_zone_list" {
description = "List of subnets in the VPC where gateways and reserved IPs will be provisioned. This value is intended to use the `subnet_zone_list` output from the ICSE VPC Subnet Module (https://github.com/Cloud-Schematics/vpc-subnet-module) or from templates using that module for subnet creation."
type = list(
object({
name = string
id = string
zone = optional(string)
cidr = optional(string)
})
)
default = []
}

variable "security_group_ids" {
description = "List of security group ids to attach to each endpoint gateway."
type = list(string)
default = null
}

variable "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.service_endpoints)
}
}

variable "resource_tags" {
type = list(string)
description = "Optional list of tags to be added to created resources"
default = []
}

##############################################################################
15 changes: 15 additions & 0 deletions examples/reserved-ips/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
##############################################################################
# Terraform Providers
##############################################################################

terraform {
required_version = ">= 1.3.0"
required_providers {
ibm = {
source = "IBM-Cloud/ibm"
version = ">= 1.58.0"
}
}
}

##############################################################################
16 changes: 7 additions & 9 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,12 @@ locals {
# Create Reserved IPs
##############################################################################

resource "ibm_is_subnet_reserved_ip" "ip" {
for_each = {
# Create a map based on endpoint IP name
for gateway_ip in local.endpoint_ip_list :
(gateway_ip.ip_name) => gateway_ip
}
name = each.value.name
subnet = each.value.subnet_id
module "ip" {
source = "./modules/reserved-ips"
endpoint_ip_list = local.endpoint_ip_list
reserved_ips = var.reserved_ips
prefix = var.prefix
vpc_name = var.vpc_name
}

##############################################################################
Expand Down Expand Up @@ -113,7 +111,7 @@ resource "ibm_is_virtual_endpoint_gateway_ip" "endpoint_gateway_ip" {
(gateway_ip.ip_name) => gateway_ip
}
gateway = local.vpe_map[each.value.gateway_name].id
reserved_ip = ibm_is_subnet_reserved_ip.ip[each.key].reserved_ip
reserved_ip = lookup(var.reserved_ips, each.value.name, module.ip.reserved_ip_map[each.value.name])
}

##############################################################################
Expand Down
Loading

0 comments on commit a32c967

Please sign in to comment.