Update hub and spoke peering to optionally create project (#195)

* optionally create project, add vm in hub, export routes to gke peering

* fix typo in unrelated module

* update README

* update README

* update unrelated README for lint

* fix test
This commit is contained in:
Ludovico Magnocavallo 2021-02-04 12:12:56 +01:00 committed by GitHub
parent a551fb1224
commit 2ab64446a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 43 deletions

View File

@ -62,7 +62,7 @@ Run the `subscription_pull` command until it returns nothing, then run the follo
| project_id | Project id that references existing project. | <code title="">string</code> | ✓ | |
| *bundle_path* | Path used to write the intermediate Cloud Function code bundle. | <code title="">string</code> | | <code title="">./bundle.zip</code> |
| *name* | Arbitrary string used to name created resources. | <code title="">string</code> | | <code title="">asset-feed</code> |
| *project_create* | Create project instead ofusing an existing one. | <code title="">bool</code> | | <code title="">false</code> |
| *project_create* | Create project instead of using an existing one. | <code title="">bool</code> | | <code title="">false</code> |
| *region* | Compute region used in the example. | <code title="">string</code> | | <code title="">europe-west1</code> |
## Outputs

View File

@ -27,7 +27,7 @@ variable "name" {
}
variable "project_create" {
description = "Create project instead ofusing an existing one."
description = "Create project instead of using an existing one."
type = bool
default = false
}

View File

@ -41,7 +41,7 @@ gcloud container clusters get-credentials cluster-1 --zone europe-west1-b
kubectl get all
```
The next step is to edit the peering towards the GKE master tenant VPC, and enable export routes. You can do it directly in Terraform with the GKE module `peering_config' variable, via gcloud, or on the cloud ccnsole. We're leaving it as an option, since one of the goals of this example is to allow testing both working and non-working configurations.
The example configures the peering with the GKE master VPC to export routes for you, so that VPN routes are passed through the peering. You can diable by hand in the console or by editing the `peering_config' variable in the cluster module, to test non-working configurations or switch to using the [GKE proxy](https://cloud.google.com/solutions/creating-kubernetes-engine-private-clusters-with-net-proxies).
### Export routes via Terraform
@ -82,15 +82,18 @@ The VPN used to connect the GKE masters VPC does not account for HA, upgrading t
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| project_id | Project id for all resources. | <code title="">string</code> | ✓ | |
| project_id | Project id used for all resources. | <code title="">string</code> | ✓ | |
| *ip_ranges* | IP CIDR ranges. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;hub &#61; &#34;10.0.0.0&#47;24&#34;&#10;spoke-1 &#61; &#34;10.0.16.0&#47;24&#34;&#10;spoke-2 &#61; &#34;10.0.32.0&#47;24&#34;&#10;&#125;">...</code> |
| *ip_secondary_ranges* | Secondary IP CIDR ranges. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;spoke-2-pods &#61; &#34;10.128.0.0&#47;18&#34;&#10;spoke-2-services &#61; &#34;172.16.0.0&#47;24&#34;&#10;&#125;">...</code> |
| *prefix* | Arbitrary string used to prefix resource names. | <code title="">string</code> | | <code title="">null</code> |
| *private_service_ranges* | Private service IP CIDR ranges. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#10;spoke-2-cluster-1 &#61; &#34;192.168.0.0&#47;28&#34;&#10;&#125;">...</code> |
| *project_create* | Set to non null if project needs to be created. | <code title="object&#40;&#123;&#10;billing_account &#61; string&#10;oslogin &#61; bool&#10;parent &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="null&#10;validation &#123;&#10;condition &#61; &#40;&#10;var.project_create &#61;&#61; null&#10;&#63; true&#10;: can&#40;regex&#40;&#34;&#40;organizations&#124;folders&#41;&#47;&#91;0-9&#93;&#43;&#34;, var.project_create.parent&#41;&#41;&#10;&#41;&#10;error_message &#61; &#34;Project parent must be of the form folders&#47;folder_id or organizations&#47;organization_id.&#34;&#10;&#125;">...</code> |
| *region* | VPC region. | <code title="">string</code> | | <code title="">europe-west1</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| project | Project id. | |
| vms | GCE VMs. | |
<!-- END TFDOC -->

View File

@ -13,7 +13,9 @@
# limitations under the License.
locals {
prefix = var.prefix != null && var.prefix != "" ? "${var.prefix}-" : ""
vm-instances = concat(
module.vm-hub.instances,
module.vm-spoke-1.instances,
module.vm-spoke-2.instances
)
@ -23,24 +25,54 @@ locals {
])
}
###############################################################################
# project #
###############################################################################
module "project" {
source = "../../modules/project"
project_create = var.project_create != null
billing_account = try(var.project_create.billing_account, null)
oslogin = try(var.project_create.oslogin, null)
parent = try(var.project_create.parent, null)
name = var.project_id
services = [
"compute.googleapis.com",
"container.googleapis.com"
]
service_config = {
disable_on_destroy = false,
disable_dependent_services = false
}
}
################################################################################
# Hub networking #
################################################################################
module "vpc-hub" {
source = "../../modules/net-vpc"
project_id = var.project_id
name = "hub"
project_id = module.project.project_id
name = "${local.prefix}hub"
subnets = [
{
ip_cidr_range = var.ip_ranges.hub
name = "hub-default"
name = "${local.prefix}hub-1"
region = var.region
secondary_ip_range = {}
}
]
}
module "nat-hub" {
source = "../../modules/net-cloudnat"
project_id = module.project.project_id
region = var.region
name = "${local.prefix}hub"
router_name = "${local.prefix}hub"
router_network = module.vpc-hub.self_link
}
module "vpc-hub-firewall" {
source = "../../modules/net-vpc-firewall"
project_id = var.project_id
@ -55,12 +87,12 @@ module "vpc-hub-firewall" {
module "vpc-spoke-1" {
source = "../../modules/net-vpc"
project_id = var.project_id
name = "spoke-1"
project_id = module.project.project_id
name = "${local.prefix}spoke-1"
subnets = [
{
ip_cidr_range = var.ip_ranges.spoke-1
name = "spoke-1-default"
name = "${local.prefix}spoke-1-1"
region = var.region
secondary_ip_range = {}
}
@ -69,7 +101,7 @@ module "vpc-spoke-1" {
module "vpc-spoke-1-firewall" {
source = "../../modules/net-vpc-firewall"
project_id = var.project_id
project_id = module.project.project_id
network = module.vpc-spoke-1.name
admin_ranges_enabled = true
admin_ranges = values(var.ip_ranges)
@ -77,10 +109,10 @@ module "vpc-spoke-1-firewall" {
module "nat-spoke-1" {
source = "../../modules/net-cloudnat"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
name = "spoke-1"
router_name = "spoke-1"
name = "${local.prefix}spoke-1"
router_name = "${local.prefix}spoke-1"
router_network = module.vpc-spoke-1.self_link
}
@ -98,12 +130,12 @@ module "hub-to-spoke-1-peering" {
module "vpc-spoke-2" {
source = "../../modules/net-vpc"
project_id = var.project_id
name = "spoke-2"
project_id = module.project.project_id
name = "${local.prefix}spoke-2"
subnets = [
{
ip_cidr_range = var.ip_ranges.spoke-2
name = "spoke-2-default"
name = "${local.prefix}spoke-2-1"
region = var.region
secondary_ip_range = {
pods = var.ip_secondary_ranges.spoke-2-pods
@ -115,7 +147,7 @@ module "vpc-spoke-2" {
module "vpc-spoke-2-firewall" {
source = "../../modules/net-vpc-firewall"
project_id = var.project_id
project_id = module.project.project_id
network = module.vpc-spoke-2.name
admin_ranges_enabled = true
admin_ranges = values(var.ip_ranges)
@ -123,10 +155,10 @@ module "vpc-spoke-2-firewall" {
module "nat-spoke-2" {
source = "../../modules/net-cloudnat"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
name = "spoke-2"
router_name = "spoke-2"
name = "${local.prefix}spoke-2"
router_name = "${local.prefix}spoke-2"
router_network = module.vpc-spoke-2.self_link
}
@ -143,14 +175,32 @@ module "hub-to-spoke-2-peering" {
# Test VMs #
################################################################################
module "vm-hub" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
name = "${local.prefix}hub"
network_interfaces = [{
network = module.vpc-hub.self_link
subnetwork = module.vpc-hub.subnet_self_links["${var.region}/${local.prefix}hub-1"]
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.vm-startup-script }
service_account = module.service-account-gce.email
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
tags = ["ssh"]
}
module "vm-spoke-1" {
source = "../../modules/compute-vm"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
name = "spoke-1-test"
name = "${local.prefix}spoke-1"
network_interfaces = [{
network = module.vpc-spoke-1.self_link
subnetwork = module.vpc-spoke-1.subnet_self_links["${var.region}/spoke-1-default"]
subnetwork = module.vpc-spoke-1.subnet_self_links["${var.region}/${local.prefix}spoke-1-1"]
nat = false
addresses = null
alias_ips = null
@ -163,12 +213,12 @@ module "vm-spoke-1" {
module "vm-spoke-2" {
source = "../../modules/compute-vm"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
name = "spoke-2-test"
name = "${local.prefix}spoke-2"
network_interfaces = [{
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/spoke-2-default"]
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/${local.prefix}spoke-2-1"]
nat = false
addresses = null
alias_ips = null
@ -181,8 +231,8 @@ module "vm-spoke-2" {
module "service-account-gce" {
source = "../../modules/iam-service-account"
project_id = var.project_id
name = "gce-test"
project_id = module.project.project_id
name = "${local.prefix}gce-test"
iam_project_roles = {
(var.project_id) = [
"roles/container.developer",
@ -198,11 +248,11 @@ module "service-account-gce" {
module "cluster-1" {
source = "../../modules/gke-cluster"
name = "cluster-1"
project_id = var.project_id
name = "${local.prefix}cluster-1"
project_id = module.project.project_id
location = "${var.region}-b"
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/spoke-2-default"]
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/${local.prefix}spoke-2-1"]
secondary_range_pods = "pods"
secondary_range_services = "services"
default_max_pods_per_node = 32
@ -217,12 +267,17 @@ module "cluster-1" {
enable_private_endpoint = true
master_ipv4_cidr_block = var.private_service_ranges.spoke-2-cluster-1
}
peering_config = {
export_routes = true
import_routes = false
project_id = null
}
}
module "cluster-1-nodepool-1" {
source = "../../modules/gke-nodepool"
name = "nodepool-1"
project_id = var.project_id
name = "${local.prefix}nodepool-1"
project_id = module.project.project_id
location = module.cluster-1.location
cluster_name = module.cluster-1.name
node_service_account = module.service-account-gke-node.email
@ -233,8 +288,8 @@ module "cluster-1-nodepool-1" {
module "service-account-gke-node" {
source = "../../modules/iam-service-account"
project_id = var.project_id
name = "gke-node"
project_id = module.project.project_id
name = "${local.prefix}gke-node"
iam_project_roles = {
(var.project_id) = [
"roles/logging.logWriter", "roles/monitoring.metricWriter",
@ -248,10 +303,10 @@ module "service-account-gke-node" {
module "vpn-hub" {
source = "../../modules/net-vpn-static"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
network = module.vpc-hub.name
name = "hub"
name = "${local.prefix}hub"
remote_ranges = values(var.private_service_ranges)
tunnels = {
spoke-2 = {
@ -265,10 +320,10 @@ module "vpn-hub" {
module "vpn-spoke-2" {
source = "../../modules/net-vpn-static"
project_id = var.project_id
project_id = module.project.project_id
region = var.region
network = module.vpc-spoke-2.name
name = "spoke-2"
name = "${local.prefix}spoke-2"
# use an aggregate of the remote ranges, so as to be less specific than the
# routes exchanged via peering
remote_ranges = ["10.0.0.0/8"]

View File

@ -12,6 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
output "project" {
description = "Project id."
value = module.project.project_id
}
output "vms" {
description = "GCE VMs."
value = {

View File

@ -31,6 +31,12 @@ variable "ip_secondary_ranges" {
}
}
variable "prefix" {
description = "Arbitrary string used to prefix resource names."
type = string
default = null
}
variable "private_service_ranges" {
description = "Private service IP CIDR ranges."
type = map(string)
@ -39,8 +45,26 @@ variable "private_service_ranges" {
}
}
variable "project_create" {
description = "Set to non null if project needs to be created."
type = object({
billing_account = string
oslogin = bool
parent = string
})
default = null
validation {
condition = (
var.project_create == null
? true
: can(regex("(organizations|folders)/[0-9]+", var.project_create.parent))
)
error_message = "Project parent must be of the form folders/folder_id or organizations/organization_id."
}
}
variable "project_id" {
description = "Project id for all resources."
description = "Project id used for all resources."
type = string
}

View File

@ -16,5 +16,10 @@
module "test" {
source = "../../../../networking/hub-and-spoke-peering"
project_create = {
billing_account = "123456-123456-123456"
oslogin = true
parent = "folders/123456789"
}
project_id = var.project_id
}

View File

@ -23,5 +23,5 @@ FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 18
assert len(resources) == 53
assert len(modules) == 21
assert len(resources) == 61