Merge pull request #14 from terraform-google-modules/averbuks-net-hub-and-spoke
Initial Hub and Spoke (VPNs) example (does not include tests, diagram and readme atm).
This commit is contained in:
81
infrastructure/hub-and-spoke-vpns/README.md
Normal file
81
infrastructure/hub-and-spoke-vpns/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Hub and Spoke VPNs
|
||||
|
||||
This sample creates a simple **Hub and Spoke VPNs** architecture, where network connects every location (VPC Network) through a single intermediary location called a hub via IPsec VPNs.
|
||||
|
||||
> **NOTE**: This example is not desined to provide HA, please refer to the [documentation](https://cloud.google.com/vpn/docs/concepts/advanced#ha-options) for information on Cloud VPNs and HA.
|
||||
|
||||
|
||||
The benefits of this topology include:
|
||||
|
||||
- Network/Security Admin manages Central Services Project (Hub).
|
||||
- Central services and tools deployed in Central Services Project (Hub) for use by all Service Projects (Spokes).
|
||||
- Network/Security Admin hands over spoke Projects to respective team who then have full autonomy.
|
||||
- Network/Security Admin monitors spoke projects for organization security posture compliance using tools like [Forseti](https://forsetisecurity.org/), [CSCC](https://cloud.google.com/security-command-center/) etc deployed in Central Services Project (Hub).
|
||||
- Spokes communicate with on-prem via VPN to transit hub and then over Interconnect or VPN to on-premises.
|
||||
- (Optional) Spokes communicate in a full-mesh to each other via VPN transit routing in Central Services Project (Hub).
|
||||
- This is a decentralized architecture where each spoke project has autonomy to manage all their GCP compute and network resources.
|
||||
|
||||
The purpose of this sample is showing how to wire different [Cloud Foundation Fabric](https://github.com/search?q=topic%3Acft-fabric+org%3Aterraform-google-modules&type=Repositories) modules to create **Hub and Spoke VPNs** network architectures, and as such it is meant to be used for prototyping, or to experiment with networking configurations. Additional best practices and security considerations need to be taken into account for real world usage (eg removal of default service accounts, disabling of external IPs, firewall design, etc).
|
||||
|
||||
|
||||

|
||||
|
||||
## Managed resources and services
|
||||
|
||||
This sample creates several distinct groups of resources:
|
||||
|
||||
- three VPC Networks (hub network and two ppoke networks)
|
||||
- VPC-level resources (VPC, subnets, firewall rules, etc.)
|
||||
- one Cloud DNS Private zone in the hub project
|
||||
- one Cloud DNS Forwarding zone in the hub project
|
||||
- four Cloud DNS Peering zones (two per each spoke project)
|
||||
- one Cloud DNS Policy for inbound forwarding
|
||||
- four Cloud Routers (two in hub project and one per each spoke project)
|
||||
- four Cloud VPNs (two in hub project and one per each spoke project)
|
||||
|
||||
## Test resources
|
||||
|
||||
A set of test resources are included for convenience, as they facilitate experimenting with different networking configurations (firewall rules, external connectivity via VPN, etc.). They are encapsulated in the `test-resources.tf` file, and can be safely removed as a single unit.
|
||||
|
||||
- two virtual machine instances in hub project (one per each region)
|
||||
- two virtual machine instances in spoke1 project (one per each region)
|
||||
- two virtual machine instances in spoke2 project (one per each region)
|
||||
|
||||
SSH access to instances is configured via [OS Login](https://cloud.google.com/compute/docs/oslogin/). External access is allowed via the default SSH rule created by the firewall module, and corresponding `ssh` tags on the instances.
|
||||
|
||||
## Known issues
|
||||
- It is not possible to get inbound DNS forwarding IPs in the terraform output.
|
||||
- Please refer to the [bug](https://github.com/terraform-providers/terraform-provider-google/issues/3753) for more details.
|
||||
- Please refer to the [documentation](https://cloud.google.com/dns/zones/#creating_a_dns_policy_that_enables_inbound_dns_forwarding) on how to get the IPs with `gcloud`.
|
||||
|
||||
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|:----:|:-----:|:-----:|
|
||||
| forwarding\_dns\_zone\_domain | Forwarding DNS Zone Domain. | string | `"on-prem.local."` | no |
|
||||
| forwarding\_dns\_zone\_name | Forwarding DNS Zone Name. | string | `"on-prem-local"` | no |
|
||||
| forwarding\_zone\_server\_addresses | Forwarding DNS Zone Server Addresses | list | `<list>` | no |
|
||||
| hub\_bgp\_asn | Hub BGP ASN. | string | `"64515"` | no |
|
||||
| hub\_project\_id | Hub Project id. | string | n/a | yes |
|
||||
| hub\_subnets | Hub VPC subnets configuration. | list | `<list>` | no |
|
||||
| private\_dns\_zone\_domain | Private DNS Zone Domain. | string | `"gcp.local."` | no |
|
||||
| private\_dns\_zone\_name | Private DNS Zone Name. | string | `"gcp-local"` | no |
|
||||
| spoke\_1\_bgp\_asn | Spoke 1 BGP ASN. | string | `"64516"` | no |
|
||||
| spoke\_1\_project\_id | Spoke 1 Project id. | string | n/a | yes |
|
||||
| spoke\_1\_subnets | Spoke 1 VPC subnets configuration. | list | `<list>` | no |
|
||||
| spoke\_2\_bgp\_asn | Spoke 2 BGP ASN. | string | `"64517"` | no |
|
||||
| spoke\_2\_project\_id | Spoke 2 Project id. | string | n/a | yes |
|
||||
| spoke\_2\_subnets | Spoke 2 VPC subnets configuration. | list | `<list>` | no |
|
||||
| spoke\_to\_spoke\_route\_advertisement | Use custom route advertisement in hub routers to advertise all spoke subnets. | string | `"true"` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| hub | Hub network resources. |
|
||||
| spoke-1 | Spoke1 network resources. |
|
||||
| spoke-2 | Spoke2 network resources. |
|
||||
| test-instances | Test instance attributes. |
|
||||
|
||||
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
|
||||
20
infrastructure/hub-and-spoke-vpns/backend.tf.sample
Normal file
20
infrastructure/hub-and-spoke-vpns/backend.tf.sample
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2019 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 {
|
||||
backend "gcs" {
|
||||
bucket = ""
|
||||
}
|
||||
}
|
||||
BIN
infrastructure/hub-and-spoke-vpns/diagram.png
Normal file
BIN
infrastructure/hub-and-spoke-vpns/diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
344
infrastructure/hub-and-spoke-vpns/main.tf
Normal file
344
infrastructure/hub-and-spoke-vpns/main.tf
Normal file
@@ -0,0 +1,344 @@
|
||||
# Copyright 2019 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.
|
||||
|
||||
locals {
|
||||
hub_subnet_regions = [for subnet in var.hub_subnets : subnet["subnet_region"]]
|
||||
spoke_1_subnet_regions = [for subnet in var.spoke_1_subnets : subnet["subnet_region"]]
|
||||
spoke_2_subnet_regions = [for subnet in var.spoke_2_subnets : subnet["subnet_region"]]
|
||||
hub_subnet_cidr_ranges = [for subnet in var.hub_subnets : subnet["subnet_ip"]]
|
||||
spoke_1_subnet_cidr_ranges = [for subnet in var.spoke_1_subnets : subnet["subnet_ip"]]
|
||||
spoke_2_subnet_cidr_ranges = [for subnet in var.spoke_2_subnets : subnet["subnet_ip"]]
|
||||
all_subnet_cidrs = concat(local.hub_subnet_cidr_ranges, local.spoke_1_subnet_cidr_ranges, local.spoke_2_subnet_cidr_ranges)
|
||||
hub_to_spoke_1_router = var.spoke_to_spoke_route_advertisement ? element(concat(google_compute_router.hub-to-spoke-1-custom.*.name, list("")), 0) : element(concat(google_compute_router.hub-to-spoke-1-default.*.name, list("")), 0)
|
||||
hub_to_spoke_2_router = var.spoke_to_spoke_route_advertisement ? element(concat(google_compute_router.hub-to-spoke-2-custom.*.name, list("")), 0) : element(concat(google_compute_router.hub-to-spoke-2-default.*.name, list("")), 0)
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# VPCs #
|
||||
##############################################################
|
||||
|
||||
module "vpc-hub" {
|
||||
source = "terraform-google-modules/network/google"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
network_name = "hub-network"
|
||||
subnets = var.hub_subnets
|
||||
routing_mode = "GLOBAL"
|
||||
}
|
||||
|
||||
module "vpc-spoke-1" {
|
||||
source = "terraform-google-modules/network/google"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.spoke_1_project_id
|
||||
network_name = "spoke-1-network"
|
||||
subnets = var.spoke_1_subnets
|
||||
routing_mode = "GLOBAL"
|
||||
}
|
||||
|
||||
module "vpc-spoke-2" {
|
||||
source = "terraform-google-modules/network/google"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.spoke_2_project_id
|
||||
network_name = "spoke-2-network"
|
||||
subnets = var.spoke_2_subnets
|
||||
routing_mode = "GLOBAL"
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# Firewalls #
|
||||
##############################################################
|
||||
|
||||
module "firewall-hub" {
|
||||
source = "terraform-google-modules/network/google//modules/fabric-net-firewall"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
network = module.vpc-hub.network_name
|
||||
admin_ranges_enabled = true
|
||||
admin_ranges = local.all_subnet_cidrs
|
||||
}
|
||||
|
||||
module "firewall-spoke-1" {
|
||||
source = "terraform-google-modules/network/google//modules/fabric-net-firewall"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.spoke_1_project_id
|
||||
network = module.vpc-spoke-1.network_name
|
||||
admin_ranges_enabled = true
|
||||
admin_ranges = local.all_subnet_cidrs
|
||||
}
|
||||
|
||||
module "firewall-spoke-2" {
|
||||
source = "terraform-google-modules/network/google//modules/fabric-net-firewall"
|
||||
version = "~> 1.2"
|
||||
|
||||
project_id = var.spoke_2_project_id
|
||||
network = module.vpc-spoke-2.network_name
|
||||
admin_ranges_enabled = true
|
||||
admin_ranges = local.all_subnet_cidrs
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# Cloud Routers #
|
||||
##############################################################
|
||||
|
||||
resource "google_compute_router" "hub-to-spoke-1-custom" {
|
||||
count = var.spoke_to_spoke_route_advertisement ? 1 : 0
|
||||
name = "hub-to-spoke-1-custom"
|
||||
region = element(local.hub_subnet_regions, 0)
|
||||
network = module.vpc-hub.network_name
|
||||
project = var.hub_project_id
|
||||
bgp {
|
||||
asn = var.hub_bgp_asn
|
||||
advertise_mode = "CUSTOM"
|
||||
advertised_groups = ["ALL_SUBNETS"]
|
||||
|
||||
dynamic "advertised_ip_ranges" {
|
||||
for_each = toset(local.spoke_2_subnet_cidr_ranges)
|
||||
content {
|
||||
range = advertised_ip_ranges.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_router" "hub-to-spoke-2-custom" {
|
||||
count = var.spoke_to_spoke_route_advertisement ? 1 : 0
|
||||
name = "hub-to-spoke-2-custom"
|
||||
region = element(local.hub_subnet_regions, 1)
|
||||
network = module.vpc-hub.network_name
|
||||
project = var.hub_project_id
|
||||
bgp {
|
||||
asn = var.hub_bgp_asn
|
||||
advertise_mode = "CUSTOM"
|
||||
advertised_groups = ["ALL_SUBNETS"]
|
||||
dynamic "advertised_ip_ranges" {
|
||||
for_each = toset(local.spoke_1_subnet_cidr_ranges)
|
||||
content {
|
||||
range = advertised_ip_ranges.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_router" "hub-to-spoke-1-default" {
|
||||
count = var.spoke_to_spoke_route_advertisement ? 0 : 1
|
||||
name = "hub-to-spoke-1-default"
|
||||
region = element(local.hub_subnet_regions, 0)
|
||||
network = module.vpc-hub.network_name
|
||||
project = var.hub_project_id
|
||||
bgp {
|
||||
asn = var.hub_bgp_asn
|
||||
}
|
||||
}
|
||||
resource "google_compute_router" "hub-to-spoke-2-default" {
|
||||
count = var.spoke_to_spoke_route_advertisement ? 0 : 1
|
||||
name = "hub-to-spoke-2-default"
|
||||
region = element(local.hub_subnet_regions, 1)
|
||||
network = module.vpc-hub.network_name
|
||||
project = var.hub_project_id
|
||||
bgp {
|
||||
asn = var.hub_bgp_asn
|
||||
}
|
||||
}
|
||||
resource "google_compute_router" "spoke-1" {
|
||||
name = "spoke-1"
|
||||
region = element(local.spoke_1_subnet_regions, 0)
|
||||
network = module.vpc-spoke-1.network_name
|
||||
project = var.spoke_1_project_id
|
||||
bgp {
|
||||
asn = var.spoke_1_bgp_asn
|
||||
}
|
||||
}
|
||||
resource "google_compute_router" "spoke-2" {
|
||||
name = "spoke-2"
|
||||
region = element(local.spoke_2_subnet_regions, 1)
|
||||
network = module.vpc-spoke-2.network_name
|
||||
project = var.spoke_2_project_id
|
||||
bgp {
|
||||
asn = var.spoke_2_bgp_asn
|
||||
}
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# VPNs #
|
||||
##############################################################
|
||||
|
||||
module "vpn-hub-to-spoke-1" {
|
||||
source = "terraform-google-modules/vpn/google"
|
||||
version = "~> 1.1"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
network = module.vpc-hub.network_name
|
||||
region = element(local.hub_subnet_regions, 0)
|
||||
gateway_name = "hub-to-spoke-1-gtw"
|
||||
tunnel_name_prefix = "hub-to-spoke-1"
|
||||
peer_ips = [module.vpn-spoke-1-to-hub.gateway_ip]
|
||||
bgp_cr_session_range = ["169.254.0.1/30"]
|
||||
bgp_remote_session_range = ["169.254.0.2"]
|
||||
peer_asn = [var.spoke_1_bgp_asn]
|
||||
cr_name = local.hub_to_spoke_1_router
|
||||
}
|
||||
|
||||
module "vpn-hub-to-spoke-2" {
|
||||
source = "terraform-google-modules/vpn/google"
|
||||
version = "~> 1.1"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
network = module.vpc-hub.network_name
|
||||
region = element(local.hub_subnet_regions, 1)
|
||||
gateway_name = "hub-to-spoke-2-gtw"
|
||||
tunnel_name_prefix = "hub-to-spoke-2"
|
||||
peer_ips = [module.vpn-spoke-2-to-hub.gateway_ip]
|
||||
bgp_cr_session_range = ["169.254.1.1/30"]
|
||||
bgp_remote_session_range = ["169.254.1.2"]
|
||||
peer_asn = [var.spoke_2_bgp_asn]
|
||||
cr_name = local.hub_to_spoke_2_router
|
||||
}
|
||||
|
||||
module "vpn-spoke-1-to-hub" {
|
||||
source = "terraform-google-modules/vpn/google"
|
||||
version = "~> 1.1"
|
||||
|
||||
project_id = var.spoke_1_project_id
|
||||
network = module.vpc-spoke-1.network_name
|
||||
region = element(local.spoke_1_subnet_regions, 0)
|
||||
gateway_name = "spoke-1-to-hub-gtw"
|
||||
tunnel_name_prefix = "spoke-1-to-hub"
|
||||
shared_secret = module.vpn-hub-to-spoke-1.ipsec_secret-dynamic[0]
|
||||
peer_ips = [module.vpn-hub-to-spoke-1.gateway_ip]
|
||||
bgp_cr_session_range = ["169.254.0.2/30"]
|
||||
bgp_remote_session_range = ["169.254.0.1"]
|
||||
peer_asn = [var.hub_bgp_asn]
|
||||
cr_name = google_compute_router.spoke-1.name
|
||||
}
|
||||
|
||||
module "vpn-spoke-2-to-hub" {
|
||||
source = "terraform-google-modules/vpn/google"
|
||||
version = "~> 1.1"
|
||||
|
||||
project_id = var.spoke_2_project_id
|
||||
network = module.vpc-spoke-2.network_name
|
||||
region = element(local.spoke_2_subnet_regions, 1)
|
||||
gateway_name = "spoke-2-to-hub-gtw"
|
||||
tunnel_name_prefix = "spoke-2-to-hub"
|
||||
shared_secret = module.vpn-hub-to-spoke-2.ipsec_secret-dynamic[0]
|
||||
peer_ips = [module.vpn-hub-to-spoke-2.gateway_ip]
|
||||
bgp_cr_session_range = ["169.254.1.2/30"]
|
||||
bgp_remote_session_range = ["169.254.1.1"]
|
||||
peer_asn = [var.hub_bgp_asn]
|
||||
cr_name = google_compute_router.spoke-2.name
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# DNS Zones #
|
||||
##############################################################
|
||||
|
||||
module "hub-private-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
type = "private"
|
||||
name = "${var.private_dns_zone_name}-hub-private"
|
||||
domain = var.private_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-hub.network_self_link]
|
||||
}
|
||||
|
||||
module "hub-forwarding-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.hub_project_id
|
||||
type = "forwarding"
|
||||
name = "${var.forwarding_dns_zone_name}-hub-forwarding"
|
||||
domain = var.forwarding_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-hub.network_self_link]
|
||||
target_name_server_addresses = var.forwarding_zone_server_addresses
|
||||
}
|
||||
|
||||
module "spoke-1-peering-zone-to-hub-private-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.spoke_1_project_id
|
||||
type = "peering"
|
||||
name = "${var.private_dns_zone_name}-spoke-1-peering-to-hub-private"
|
||||
domain = var.private_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-spoke-1.network_self_link]
|
||||
target_network = module.vpc-hub.network_self_link
|
||||
}
|
||||
|
||||
module "spoke-2-peering-zone-to-hub-private-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.spoke_2_project_id
|
||||
type = "peering"
|
||||
name = "${var.private_dns_zone_name}-spoke-2-peering-to-hub-private"
|
||||
domain = var.private_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-spoke-2.network_self_link]
|
||||
target_network = module.vpc-hub.network_self_link
|
||||
}
|
||||
|
||||
module "spoke-1-peering-zone-to-hub-forwarding-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.spoke_1_project_id
|
||||
type = "peering"
|
||||
name = "${var.private_dns_zone_name}-spoke-1-peering-to-hub-forwarding"
|
||||
domain = var.forwarding_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-spoke-1.network_self_link]
|
||||
target_network = module.vpc-hub.network_self_link
|
||||
}
|
||||
|
||||
module "spoke-2-peering-zone-to-hub-forwarding-zone" {
|
||||
source = "terraform-google-modules/cloud-dns/google"
|
||||
version = "~> 2.0"
|
||||
|
||||
project_id = var.spoke_2_project_id
|
||||
type = "peering"
|
||||
name = "${var.private_dns_zone_name}-spoke-2-peering-to-hub-forwarding"
|
||||
domain = var.forwarding_dns_zone_domain
|
||||
|
||||
private_visibility_config_networks = [module.vpc-spoke-2.network_self_link]
|
||||
target_network = module.vpc-hub.network_self_link
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# Inbount DNS Forwarding #
|
||||
##############################################################
|
||||
|
||||
# TODO Provide resolver addresses in the output once https://github.com/terraform-providers/terraform-provider-google/issues/3753 resolved.
|
||||
# For now please refer to the documentation on how to get the compute addresses for the DNS Resolver https://cloud.google.com/dns/zones/#creating_a_dns_policy_that_enables_inbound_dns_forwarding
|
||||
resource "google_dns_policy" "google_dns_policy" {
|
||||
provider = "google-beta"
|
||||
|
||||
project = var.hub_project_id
|
||||
name = "inbound-dns-forwarding-policy"
|
||||
enable_inbound_forwarding = true
|
||||
|
||||
networks {
|
||||
network_url = module.vpc-hub.network_self_link
|
||||
}
|
||||
}
|
||||
82
infrastructure/hub-and-spoke-vpns/outputs.tf
Normal file
82
infrastructure/hub-and-spoke-vpns/outputs.tf
Normal file
@@ -0,0 +1,82 @@
|
||||
# Copyright 2019 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.
|
||||
|
||||
output "hub" {
|
||||
description = "Hub network resources."
|
||||
value = {
|
||||
network_name = module.vpc-hub.network_name
|
||||
subnets_ips = zipmap(
|
||||
module.vpc-hub.subnets_names,
|
||||
module.vpc-hub.subnets_ips
|
||||
)
|
||||
subnets_regions = zipmap(
|
||||
module.vpc-hub.subnets_names,
|
||||
module.vpc-hub.subnets_regions
|
||||
)
|
||||
privte_dns_zone = {
|
||||
name = module.hub-private-zone.name
|
||||
domain = module.hub-private-zone.domain
|
||||
}
|
||||
forwarding_dns_zone = {
|
||||
name = module.hub-forwarding-zone.name
|
||||
domain = module.hub-forwarding-zone.domain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "spoke-1" {
|
||||
description = "Spoke1 network resources."
|
||||
value = {
|
||||
network_name = module.vpc-spoke-1.network_name
|
||||
subnets_ips = zipmap(
|
||||
module.vpc-spoke-1.subnets_names,
|
||||
module.vpc-spoke-1.subnets_ips
|
||||
)
|
||||
subnets_regions = zipmap(
|
||||
module.vpc-spoke-1.subnets_names,
|
||||
module.vpc-spoke-1.subnets_regions
|
||||
)
|
||||
peering_to_hub_private_dns_zone = {
|
||||
name = module.spoke-1-peering-zone-to-hub-private-zone.name
|
||||
domain = module.spoke-1-peering-zone-to-hub-private-zone.domain
|
||||
}
|
||||
peering_to_hub_forwarding_dns_zone = {
|
||||
name = module.spoke-1-peering-zone-to-hub-forwarding-zone.name
|
||||
domain = module.spoke-1-peering-zone-to-hub-forwarding-zone.domain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "spoke-2" {
|
||||
description = "Spoke2 network resources."
|
||||
value = {
|
||||
network_name = module.vpc-spoke-2.network_name
|
||||
subnets_ips = zipmap(
|
||||
module.vpc-spoke-2.subnets_names,
|
||||
module.vpc-spoke-2.subnets_ips
|
||||
)
|
||||
subnets_regions = zipmap(
|
||||
module.vpc-spoke-2.subnets_names,
|
||||
module.vpc-spoke-2.subnets_regions
|
||||
)
|
||||
peering_to_hub_private_dns_zone = {
|
||||
name = module.spoke-2-peering-zone-to-hub-private-zone.name
|
||||
domain = module.spoke-2-peering-zone-to-hub-private-zone.domain
|
||||
}
|
||||
peering_to_hub_forwarding_dns_zone = {
|
||||
name = module.spoke-2-peering-zone-to-hub-forwarding-zone.name
|
||||
domain = module.spoke-2-peering-zone-to-hub-forwarding-zone.domain
|
||||
}
|
||||
}
|
||||
}
|
||||
4
infrastructure/hub-and-spoke-vpns/provider.tf
Normal file
4
infrastructure/hub-and-spoke-vpns/provider.tf
Normal file
@@ -0,0 +1,4 @@
|
||||
provider "google" {
|
||||
}
|
||||
provider "google-beta" {
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
hub_project_id = "automation-examples"
|
||||
spoke_1_project_id = "automation-examples"
|
||||
spoke_2_project_id = "automation-examples"
|
||||
158
infrastructure/hub-and-spoke-vpns/test-resources.tf
Normal file
158
infrastructure/hub-and-spoke-vpns/test-resources.tf
Normal file
@@ -0,0 +1,158 @@
|
||||
# Copyright 2019 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.
|
||||
|
||||
###############################################################################
|
||||
# Hub test VMs and DNS records #
|
||||
###############################################################################
|
||||
|
||||
resource "google_compute_instance" "hub" {
|
||||
count = length(var.hub_subnets)
|
||||
project = var.hub_project_id
|
||||
name = "hub-${element(var.hub_subnets, count.index)["subnet_name"]}"
|
||||
machine_type = "f1-micro"
|
||||
zone = "${element(local.hub_subnet_regions, count.index)}-b"
|
||||
tags = ["ssh"]
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-9"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork = element(module.vpc-hub.subnets_self_links, count.index)
|
||||
access_config {}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_dns_record_set" "hub" {
|
||||
count = length(var.hub_subnets)
|
||||
|
||||
project = var.hub_project_id
|
||||
name = "hub-${count.index}.${module.hub-private-zone.domain}"
|
||||
type = "A"
|
||||
ttl = 300
|
||||
|
||||
managed_zone = module.hub-private-zone.name
|
||||
|
||||
rrdatas = [google_compute_instance.hub[count.index].network_interface.0.network_ip]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Spoke 1 test VMs and DNS records #
|
||||
###############################################################################
|
||||
|
||||
resource "google_compute_instance" "spoke-1" {
|
||||
count = length(var.spoke_1_subnets)
|
||||
project = var.spoke_1_project_id
|
||||
name = "spoke-1-${element(var.spoke_1_subnets, count.index)["subnet_name"]}"
|
||||
machine_type = "f1-micro"
|
||||
zone = "${element(local.spoke_1_subnet_regions, count.index)}-b"
|
||||
tags = ["ssh"]
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-9"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork = element(module.vpc-spoke-1.subnets_self_links, count.index)
|
||||
access_config {}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_dns_record_set" "spoke-1" {
|
||||
count = length(var.spoke_1_subnets)
|
||||
|
||||
project = var.hub_project_id
|
||||
name = "spoke-1-${count.index}.${module.hub-private-zone.domain}"
|
||||
type = "A"
|
||||
ttl = 300
|
||||
|
||||
managed_zone = module.hub-private-zone.name
|
||||
|
||||
rrdatas = [google_compute_instance.spoke-1[count.index].network_interface.0.network_ip]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Spoke 2 test VMs and DNS records #
|
||||
###############################################################################
|
||||
|
||||
resource "google_compute_instance" "spoke-2" {
|
||||
count = length(var.spoke_2_subnets)
|
||||
project = var.spoke_2_project_id
|
||||
name = "spoke-2-${element(var.spoke_2_subnets, count.index)["subnet_name"]}"
|
||||
machine_type = "f1-micro"
|
||||
zone = "${element(local.spoke_2_subnet_regions, count.index)}-b"
|
||||
tags = ["ssh"]
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-9"
|
||||
}
|
||||
}
|
||||
network_interface {
|
||||
subnetwork = element(module.vpc-spoke-2.subnets_self_links, count.index)
|
||||
access_config {}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_dns_record_set" "spoke-2" {
|
||||
count = length(var.spoke_2_subnets)
|
||||
|
||||
project = var.hub_project_id
|
||||
name = "spoke-2-${count.index}.${module.hub-private-zone.domain}"
|
||||
type = "A"
|
||||
ttl = 300
|
||||
|
||||
managed_zone = module.hub-private-zone.name
|
||||
|
||||
rrdatas = [google_compute_instance.spoke-2[count.index].network_interface.0.network_ip]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# test outputs #
|
||||
###############################################################################
|
||||
|
||||
output "test-instances" {
|
||||
description = "Test instance attributes."
|
||||
value = {
|
||||
hub = {
|
||||
instance_zones = zipmap(
|
||||
google_compute_instance.hub.*.name,
|
||||
google_compute_instance.hub.*.zone
|
||||
)
|
||||
instances_dns_names = zipmap(
|
||||
google_compute_instance.hub.*.name,
|
||||
google_dns_record_set.hub.*.name
|
||||
)
|
||||
}
|
||||
spoke-1 = {
|
||||
instances_zones = zipmap(
|
||||
google_compute_instance.spoke-1.*.name,
|
||||
google_compute_instance.spoke-1.*.zone
|
||||
)
|
||||
instances_dns_names = zipmap(
|
||||
google_compute_instance.spoke-1.*.name,
|
||||
google_dns_record_set.spoke-1.*.name
|
||||
)
|
||||
}
|
||||
spoke-2 = {
|
||||
instances_zones = zipmap(
|
||||
google_compute_instance.spoke-2.*.name,
|
||||
google_compute_instance.spoke-2.*.zone
|
||||
)
|
||||
instances_dns_names = zipmap(
|
||||
google_compute_instance.spoke-2.*.name,
|
||||
google_dns_record_set.spoke-2.*.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
115
infrastructure/hub-and-spoke-vpns/variables.tf
Normal file
115
infrastructure/hub-and-spoke-vpns/variables.tf
Normal file
@@ -0,0 +1,115 @@
|
||||
# Copyright 2019 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.
|
||||
|
||||
variable "hub_project_id" {
|
||||
description = "Hub Project id."
|
||||
}
|
||||
|
||||
variable "spoke_1_project_id" {
|
||||
description = "Spoke 1 Project id."
|
||||
}
|
||||
|
||||
variable "spoke_2_project_id" {
|
||||
description = "Spoke 2 Project id."
|
||||
}
|
||||
|
||||
variable "spoke_to_spoke_route_advertisement" {
|
||||
description = "Use custom route advertisement in hub routers to advertise all spoke subnets."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "hub_bgp_asn" {
|
||||
description = "Hub BGP ASN."
|
||||
default = 64515
|
||||
}
|
||||
|
||||
variable "spoke_1_bgp_asn" {
|
||||
description = "Spoke 1 BGP ASN."
|
||||
default = 64516
|
||||
}
|
||||
|
||||
variable "spoke_2_bgp_asn" {
|
||||
description = "Spoke 2 BGP ASN."
|
||||
default = 64517
|
||||
}
|
||||
|
||||
variable "hub_subnets" {
|
||||
description = "Hub VPC subnets configuration."
|
||||
default = [{
|
||||
subnet_name = "subnet-a"
|
||||
subnet_ip = "10.10.10.0/24"
|
||||
subnet_region = "europe-west1"
|
||||
},
|
||||
{
|
||||
subnet_name = "subnet-b"
|
||||
subnet_ip = "10.10.20.0/24"
|
||||
subnet_region = "europe-west2"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
variable "spoke_1_subnets" {
|
||||
description = "Spoke 1 VPC subnets configuration."
|
||||
default = [{
|
||||
subnet_name = "spoke-1-subnet-a"
|
||||
subnet_ip = "10.20.10.0/24"
|
||||
subnet_region = "europe-west1"
|
||||
},
|
||||
{
|
||||
subnet_name = "spoke-1-subnet-b"
|
||||
subnet_ip = "10.20.20.0/24"
|
||||
subnet_region = "europe-west2"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
variable "spoke_2_subnets" {
|
||||
description = "Spoke 2 VPC subnets configuration."
|
||||
default = [{
|
||||
subnet_name = "spoke-2-subnet-a"
|
||||
subnet_ip = "10.30.10.0/24"
|
||||
subnet_region = "europe-west1"
|
||||
},
|
||||
{
|
||||
subnet_name = "spoke-2-subnet-b"
|
||||
subnet_ip = "10.30.20.0/24"
|
||||
subnet_region = "europe-west2"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
variable "private_dns_zone_name" {
|
||||
description = "Private DNS Zone Name."
|
||||
default = "gcp-local"
|
||||
}
|
||||
|
||||
variable "private_dns_zone_domain" {
|
||||
description = "Private DNS Zone Domain."
|
||||
default = "gcp.local."
|
||||
}
|
||||
|
||||
variable "forwarding_dns_zone_name" {
|
||||
description = "Forwarding DNS Zone Name."
|
||||
default = "on-prem-local"
|
||||
}
|
||||
|
||||
variable "forwarding_dns_zone_domain" {
|
||||
description = "Forwarding DNS Zone Domain."
|
||||
default = "on-prem.local."
|
||||
}
|
||||
|
||||
variable "forwarding_zone_server_addresses" {
|
||||
description = "Forwarding DNS Zone Server Addresses"
|
||||
default = ["8.8.8.8", "8.8.4.4"]
|
||||
}
|
||||
Reference in New Issue
Block a user