diff --git a/modules/cloud-config-container/simple-nva/README.md b/modules/cloud-config-container/simple-nva/README.md new file mode 100644 index 00000000..7fbb109d --- /dev/null +++ b/modules/cloud-config-container/simple-nva/README.md @@ -0,0 +1,79 @@ +# Google Cloud DNS Module + +This module allows for the creation of a NVA (Network Virtual Appliance) to be used for experiments and as a stub for future appliances deployment. + +This NVA can be used to interconnect up to 8 VPCs. + +## Examples + +### Simple example + +```hcl +# Interfaces configuration +locals { + network_interfaces = [ + { + addresses = null + name = "dev" + nat = false + network = "dev_vpc_self_link" + routes = ["10.128.0.0/9"] + subnetwork = "dev_vpc_nva_subnet_self_link" + }, + { + addresses = null + name = "prod" + nat = false + network = "prod_vpc_self_link" + routes = ["10.0.0.0/9"] + subnetwork = "prod_vpc_nva_subnet_self_link" + } +} + +# NVA config +module "nva-cloud-config" { + source = "../../../cloud-foundation-fabric/modules/cloud-config-container/simple-nva" + enable_health_checks = true + network_interfaces = local.network_interfaces +} + +# COS VM +module "nva" { + source = "../../modules/compute-vm" + project_id = "myproject" + instance_type = "e2-standard-2" + name = "nva" + can_ip_forward = true + zone = "europe-west8-a" + tags = ["nva"] + network_interfaces = local.network_interfaces + boot_disk = { + image = "projects/cos-cloud/global/images/family/cos-stable" + size = 10 + type = "pd-balanced" + } + metadata = { + user-data = module.nva-cloud-config.cloud_config + } +} +``` + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [network_interfaces](variables.tf#L29) | Network interfaces configuration. | list(object({…})) | ✓ | | +| [cloud_config](variables.tf#L17) | Cloud config template path. If null default will be used. | string | | null | +| [enable_health_checks](variables.tf#L23) | Configures routing to enable responses to health check probes. | bool | | false | +| [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | object({…}) | | null | +| [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | object({…}) | | {…} | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [cloud_config](outputs.tf#L17) | Rendered cloud-config file to be passed as user-data instance metadata. | | +| [test_instance](outputs-instance.tf#L17) | Optional test instance name and address. | | + + diff --git a/modules/cloud-config-container/simple-nva/cloud-config.yaml b/modules/cloud-config-container/simple-nva/cloud-config.yaml new file mode 100644 index 00000000..f7dc2607 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/cloud-config.yaml @@ -0,0 +1,38 @@ +#cloud-config + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +write_files: +%{ for path, data in files } + - path: ${path} + owner: ${lookup(data, "owner", "root")} + permissions: ${lookup(data, "permissions", "0644")} + content: | + ${indent(6, data.content)} +%{ endfor } + +bootcmd: + - systemctl start node-problem-detector + +runcmd: + - iptables --policy FORWARD ACCEPT +%{if enable_health_checks ~} +%{ for interface in network_interfaces ~} + - /var/run/nva/policy_based_routing.sh ${interface.name} +%{ for route in interface.routes ~} + - ip route add ${route} via `curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/${interface.number}/gateway -H "Metadata-Flavor:Google"` dev ${interface.name} +%{ endfor ~} +%{ endfor ~} +%{ endif ~} diff --git a/modules/cloud-config-container/simple-nva/files/ipprefix_by_netmask.sh b/modules/cloud-config-container/simple-nva/files/ipprefix_by_netmask.sh new file mode 100644 index 00000000..405c1649 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/files/ipprefix_by_netmask.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# https://stackoverflow.com/questions/50413579/bash-convert-netmask-in-cidr-notation +c=0 x=0$(printf '%o' $${1//./ }) +while [ $x -gt 0 ]; do + let c+=$((x % 2)) 'x>>=1' +done +echo $c diff --git a/modules/cloud-config-container/simple-nva/files/policy_based_routing.sh b/modules/cloud-config-container/simple-nva/files/policy_based_routing.sh new file mode 100644 index 00000000..42ed0dcb --- /dev/null +++ b/modules/cloud-config-container/simple-nva/files/policy_based_routing.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +IF_NAME=$1 +IF_NUMBER=$(echo $1 | sed -e s/eth//) +IF_GW=$(curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$IF_NUMBER/gateway -H "Metadata-Flavor: Google") +IF_IP=$(curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$IF_NUMBER/ip -H "Metadata-Flavor: Google") +IF_NETMASK=$(curl http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/$IF_NUMBER/subnetmask -H "Metadata-Flavor: Google") +IF_IP_PREFIX=$(/var/run/nva/ipprefix_by_netmask.sh $IF_NETMASK) +IP_LB=$(ip r show table local | grep "$IF_NAME proto 66" | cut -f 2 -d " ") +grep -qxF "$((200 + $IF_NUMBER)) hc-$IF_NAME" /etc/iproute2/rt_tables || echo "$((200 + $IF_NUMBER)) hc-$IF_NAME" >>/etc/iproute2/rt_tables +ip route add $IF_GW src $IF_IP dev $IF_NAME table hc-$IF_NAME +ip route add default via $IF_GW dev $IF_NAME table hc-$IF_NAME +ip rule add from $IP_LB/32 table hc-$IF_NAME diff --git a/modules/cloud-config-container/simple-nva/instance.tf b/modules/cloud-config-container/simple-nva/instance.tf new file mode 120000 index 00000000..bdef596b --- /dev/null +++ b/modules/cloud-config-container/simple-nva/instance.tf @@ -0,0 +1 @@ +../instance.tf \ No newline at end of file diff --git a/modules/cloud-config-container/simple-nva/main.tf b/modules/cloud-config-container/simple-nva/main.tf new file mode 100644 index 00000000..5b9663bd --- /dev/null +++ b/modules/cloud-config-container/simple-nva/main.tf @@ -0,0 +1,50 @@ +/** + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + cloud_config = templatefile(local.template, merge({ + files = local.files + enable_health_checks = var.enable_health_checks + network_interfaces = local.network_interfaces + })) + + files = { + "/var/run/nva/ipprefix_by_netmask.sh" = { + content = file("${path.module}/files/ipprefix_by_netmask.sh") + owner = "root" + permissions = "0744" + } + "/var/run/nva/policy_based_routing.sh" = { + content = file("${path.module}/files/policy_based_routing.sh") + owner = "root" + permissions = "0744" + } + } + + network_interfaces = [ + for index, interface in var.network_interfaces : { + name = "eth${index}" + number = index + routes = interface.routes + } + ] + + template = ( + var.cloud_config == null + ? "${path.module}/cloud-config.yaml" + : var.cloud_config + ) +} diff --git a/modules/cloud-config-container/simple-nva/outputs-instance.tf b/modules/cloud-config-container/simple-nva/outputs-instance.tf new file mode 120000 index 00000000..ea9e2404 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/outputs-instance.tf @@ -0,0 +1 @@ +../outputs-instance.tf \ No newline at end of file diff --git a/modules/cloud-config-container/simple-nva/outputs.tf b/modules/cloud-config-container/simple-nva/outputs.tf new file mode 100644 index 00000000..7d8d4165 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "cloud_config" { + description = "Rendered cloud-config file to be passed as user-data instance metadata." + value = local.cloud_config +} diff --git a/modules/cloud-config-container/simple-nva/variables-instance.tf b/modules/cloud-config-container/simple-nva/variables-instance.tf new file mode 120000 index 00000000..94af61e4 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/variables-instance.tf @@ -0,0 +1 @@ +../variables-instance.tf \ No newline at end of file diff --git a/modules/cloud-config-container/simple-nva/variables.tf b/modules/cloud-config-container/simple-nva/variables.tf new file mode 100644 index 00000000..9307ddac --- /dev/null +++ b/modules/cloud-config-container/simple-nva/variables.tf @@ -0,0 +1,34 @@ +/** + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "cloud_config" { + description = "Cloud config template path. If null default will be used." + type = string + default = null +} + +variable "enable_health_checks" { + description = "Configures routing to enable responses to health check probes." + type = bool + default = false +} + +variable "network_interfaces" { + description = "Network interfaces configuration." + type = list(object({ + routes = optional(list(string)) + })) +} diff --git a/modules/cloud-config-container/simple-nva/versions.tf b/modules/cloud-config-container/simple-nva/versions.tf new file mode 100644 index 00000000..8abac788 --- /dev/null +++ b/modules/cloud-config-container/simple-nva/versions.tf @@ -0,0 +1,29 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +terraform { + required_version = ">= 1.3.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.32.0" # tftest + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 4.32.0" # tftest + } + } +} + +