From 569bd9c8243815f5a36983579d69bf7309d76bd9 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Mon, 30 Sep 2019 17:56:10 -0700 Subject: [PATCH 1/9] Add a parameter 'registry_project_id' The PR allows configuring the project holding the GCR registry when used in connection with 'create_service_account'=true and grant_registry_access=true. Holding the GCR is a project with other resources increases the risk of exposing sensitive data to the service account running the nodes, as the required permissions of role roles/storage.objectViewer provide access to all storage objects in the project. --- .kitchen.yml | 7 ++ README.md | 6 +- autogen/README.md | 3 + autogen/sa.tf | 2 +- autogen/variables.tf | 8 +- examples/create_service_account/README.md | 45 +++++++ examples/create_service_account/main.tf | 63 ++++++++++ examples/create_service_account/outputs.tf | 35 ++++++ .../create_service_account/test_outputs.tf | 1 + examples/create_service_account/variables.tf | 54 ++++++++ modules/beta-private-cluster/README.md | 6 +- modules/beta-private-cluster/sa.tf | 2 +- modules/beta-private-cluster/variables.tf | 8 +- modules/beta-public-cluster/README.md | 6 +- modules/beta-public-cluster/sa.tf | 2 +- modules/beta-public-cluster/variables.tf | 8 +- modules/private-cluster/README.md | 6 +- modules/private-cluster/sa.tf | 2 +- modules/private-cluster/variables.tf | 8 +- sa.tf | 2 +- test/ci/create-service-account.yml | 18 +++ .../create_service_account/example.tf | 30 +++++ .../create_service_account/network.tf | 47 +++++++ .../create_service_account/outputs.tf | 1 + .../create_service_account/terraform.tfvars | 1 + .../create_service_account/variables.tf | 1 + test/fixtures/shared/outputs.tf | 3 + test/fixtures/shared/terraform.tfvars | 6 + test/fixtures/shared/terraform.tfvars.sample | 2 + test/fixtures/shared/variables.tf | 4 + .../create_service_account/controls/gcloud.rb | 116 ++++++++++++++++++ .../create_service_account/inspec.yml | 23 ++++ variables.tf | 8 +- 33 files changed, 520 insertions(+), 14 deletions(-) create mode 100644 examples/create_service_account/README.md create mode 100644 examples/create_service_account/main.tf create mode 100644 examples/create_service_account/outputs.tf create mode 120000 examples/create_service_account/test_outputs.tf create mode 100644 examples/create_service_account/variables.tf create mode 100644 test/ci/create-service-account.yml create mode 100644 test/fixtures/create_service_account/example.tf create mode 100644 test/fixtures/create_service_account/network.tf create mode 120000 test/fixtures/create_service_account/outputs.tf create mode 120000 test/fixtures/create_service_account/terraform.tfvars create mode 120000 test/fixtures/create_service_account/variables.tf create mode 100644 test/integration/create_service_account/controls/gcloud.rb create mode 100644 test/integration/create_service_account/inspec.yml diff --git a/.kitchen.yml b/.kitchen.yml index 6bf414c21f..6a7fbf997b 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -29,6 +29,13 @@ platforms: - name: local suites: + - name: "create_service_account" + driver: + root_module_directory: test/fixtures/create_service_account + verifier: + systems: + - name: create_service_account + backend: local - name: "deploy_service" driver: root_module_directory: test/fixtures/deploy_service diff --git a/README.md b/README.md index 923d3f7a09..34d280b41b 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | @@ -167,6 +167,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | service\_account | The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created. | string | `""` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | map(list(string)) | `` | no | @@ -228,6 +229,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/autogen/README.md b/autogen/README.md index 73a6314289..607adf8a1b 100644 --- a/autogen/README.md +++ b/autogen/README.md @@ -173,6 +173,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/autogen/sa.tf b/autogen/sa.tf index 62b31f457a..eaebeb2a22 100644 --- a/autogen/sa.tf +++ b/autogen/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/autogen/variables.tf b/autogen/variables.tf index 0fedacb2af..b9a29a1613 100644 --- a/autogen/variables.tf +++ b/autogen/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({cidr_blocks = list(object({cidr_block = string, display_name = string}))})) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -269,6 +269,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/examples/create_service_account/README.md b/examples/create_service_account/README.md new file mode 100644 index 0000000000..ee2f605d18 --- /dev/null +++ b/examples/create_service_account/README.md @@ -0,0 +1,45 @@ +# Simple Regional Cluster + +This example illustrates how to create a simple private cluster. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| cluster\_name\_suffix | A suffix to append to the default cluster name | string | `""` | no | +| ip\_range\_pods | The secondary ip range to use for pods | string | n/a | yes | +| ip\_range\_services | The secondary ip range to use for pods | string | n/a | yes | +| network | The VPC network to host the cluster in | string | n/a | yes | +| project\_id | The project ID to host the cluster in | string | n/a | yes | +| region | The region to host the cluster in | string | n/a | yes | +| registry\_project\_id | Project name for the GCR registry | string | n/a | yes | +| subnetwork | The subnetwork to host the cluster in | string | n/a | yes | +| zones | The zone to host the cluster in (required if is a zonal cluster) | list(string) | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| ca\_certificate | | +| client\_token | | +| cluster\_name | Cluster name | +| ip\_range\_pods | The secondary IP range used for pods | +| ip\_range\_services | The secondary IP range used for services | +| kubernetes\_endpoint | | +| location | | +| master\_kubernetes\_version | The master Kubernetes version | +| network | | +| project\_id | | +| region | | +| service\_account | The service account to default running nodes as if not overridden in `node_pools`. | +| subnetwork | | +| zones | List of zones in which the cluster resides | + + + +To provision this example, run the following from within this directory: +- `terraform init` to get the plugins +- `terraform plan` to see the infrastructure plan +- `terraform apply` to apply the infrastructure build +- `terraform destroy` to destroy the built infrastructure diff --git a/examples/create_service_account/main.tf b/examples/create_service_account/main.tf new file mode 100644 index 0000000000..f278bb79d6 --- /dev/null +++ b/examples/create_service_account/main.tf @@ -0,0 +1,63 @@ +/** + * Copyright 2018 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 { + cluster_type = "create-service-account" +} + +provider "google" { + version = "~> 2.12.0" + region = var.region +} + +data "google_compute_subnetwork" "subnetwork" { + name = var.subnetwork + project = var.project_id + region = var.region +} + +module "gke" { + source = "../../modules/private-cluster/" + project_id = var.project_id + name = "${local.cluster_type}-cluster${var.cluster_name_suffix}" + regional = false + region = var.region + zones = var.zones + network = var.network + subnetwork = var.subnetwork + ip_range_pods = var.ip_range_pods + ip_range_services = var.ip_range_services + create_service_account = true + grant_registry_access = true + registry_project_id = var.registry_project_id + enable_private_endpoint = true + enable_private_nodes = true + master_ipv4_cidr_block = "172.16.0.0/28" + + master_authorized_networks_config = [ + { + cidr_blocks = [ + { + cidr_block = data.google_compute_subnetwork.subnetwork.ip_cidr_range + display_name = "VPC" + }, + ] + }, + ] +} + +data "google_client_config" "default" { +} diff --git a/examples/create_service_account/outputs.tf b/examples/create_service_account/outputs.tf new file mode 100644 index 0000000000..0d972dcd88 --- /dev/null +++ b/examples/create_service_account/outputs.tf @@ -0,0 +1,35 @@ +/** + * Copyright 2018 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 "kubernetes_endpoint" { + sensitive = true + value = module.gke.endpoint +} + +output "client_token" { + sensitive = true + value = base64encode(data.google_client_config.default.access_token) +} + +output "ca_certificate" { + value = module.gke.ca_certificate +} + +output "service_account" { + description = "The service account to default running nodes as if not overridden in `node_pools`." + value = module.gke.service_account +} + diff --git a/examples/create_service_account/test_outputs.tf b/examples/create_service_account/test_outputs.tf new file mode 120000 index 0000000000..17b34213ba --- /dev/null +++ b/examples/create_service_account/test_outputs.tf @@ -0,0 +1 @@ +../../test/fixtures/all_examples/test_outputs.tf \ No newline at end of file diff --git a/examples/create_service_account/variables.tf b/examples/create_service_account/variables.tf new file mode 100644 index 0000000000..dfdea6bedd --- /dev/null +++ b/examples/create_service_account/variables.tf @@ -0,0 +1,54 @@ +/** + * Copyright 2018 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 "project_id" { + description = "The project ID to host the cluster in" +} + +variable "cluster_name_suffix" { + description = "A suffix to append to the default cluster name" + default = "" +} + +variable "region" { + description = "The region to host the cluster in" +} + +variable "zones" { + type = list(string) + description = "The zone to host the cluster in (required if is a zonal cluster)" +} + +variable "network" { + description = "The VPC network to host the cluster in" +} + +variable "subnetwork" { + description = "The subnetwork to host the cluster in" +} + +variable "ip_range_pods" { + description = "The secondary ip range to use for pods" +} + +variable "ip_range_services" { + description = "The secondary ip range to use for pods" +} + +variable "registry_project_id" { + description = "Project name for the GCR registry" +} + diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md index 1175553890..f97bace58c 100644 --- a/modules/beta-private-cluster/README.md +++ b/modules/beta-private-cluster/README.md @@ -169,7 +169,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | @@ -190,6 +190,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | resource\_usage\_export\_dataset\_id | The dataset id for which network egress metering for this cluster will be enabled. If enabled, a daemonset will be created in the cluster to meter network egress traffic. | string | `""` | no | | sandbox\_enabled | (Beta) Enable GKE Sandbox (Do not forget to set `image_type` = `COS_CONTAINERD` and `node_version` = `1.12.7-gke.17` or later to use it). | bool | `"false"` | no | @@ -258,6 +259,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/beta-private-cluster/sa.tf b/modules/beta-private-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/beta-private-cluster/sa.tf +++ b/modules/beta-private-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf index 9a869a830f..586e7020c2 100644 --- a/modules/beta-private-cluster/variables.tf +++ b/modules/beta-private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -267,6 +267,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md index 1f78c95082..8d61b3b8ff 100644 --- a/modules/beta-public-cluster/README.md +++ b/modules/beta-public-cluster/README.md @@ -161,7 +161,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | @@ -181,6 +181,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | resource\_usage\_export\_dataset\_id | The dataset id for which network egress metering for this cluster will be enabled. If enabled, a daemonset will be created in the cluster to meter network egress traffic. | string | `""` | no | | sandbox\_enabled | (Beta) Enable GKE Sandbox (Do not forget to set `image_type` = `COS_CONTAINERD` and `node_version` = `1.12.7-gke.17` or later to use it). | bool | `"false"` | no | @@ -249,6 +250,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/beta-public-cluster/sa.tf b/modules/beta-public-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/beta-public-cluster/sa.tf +++ b/modules/beta-public-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf index 0ae2b75661..f1d0f26239 100644 --- a/modules/beta-public-cluster/variables.tf +++ b/modules/beta-public-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -267,6 +267,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md index c29d58ee93..8f0b5ae585 100644 --- a/modules/private-cluster/README.md +++ b/modules/private-cluster/README.md @@ -158,7 +158,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | @@ -176,6 +176,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | service\_account | The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created. | string | `""` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | map(list(string)) | `` | no | @@ -237,6 +238,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/private-cluster/sa.tf b/modules/private-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/private-cluster/sa.tf +++ b/modules/private-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf index 8008e08975..871b785816 100644 --- a/modules/private-cluster/variables.tf +++ b/modules/private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -257,6 +257,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/sa.tf b/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/sa.tf +++ b/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/test/ci/create-service-account.yml b/test/ci/create-service-account.yml new file mode 100644 index 0000000000..6bfa98bd77 --- /dev/null +++ b/test/ci/create-service-account.yml @@ -0,0 +1,18 @@ +--- + +platform: linux + +inputs: +- name: pull-request + path: terraform-google-kubernetes-engine + +run: + path: make + args: ['test_integration'] + dir: terraform-google-kubernetes-engine + +params: + SUITE: "create-service-account-local" + COMPUTE_ENGINE_SERVICE_ACCOUNT: "" + REGION: "us-east4" + ZONES: '["us-east4-a", "us-east4-b", "us-east4-c"]' diff --git a/test/fixtures/create_service_account/example.tf b/test/fixtures/create_service_account/example.tf new file mode 100644 index 0000000000..9dbaa83e93 --- /dev/null +++ b/test/fixtures/create_service_account/example.tf @@ -0,0 +1,30 @@ +/** + * Copyright 2018 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. + */ + +module "example" { + source = "../../../examples/create_service_account" + + project_id = var.project_id + cluster_name_suffix = "-${random_string.suffix.result}" + region = var.region + zones = slice(var.zones, 0, 1) + network = google_compute_network.main.name + subnetwork = google_compute_subnetwork.main.name + ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name + ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name + registry_project_id = var.registry_project_id +} + diff --git a/test/fixtures/create_service_account/network.tf b/test/fixtures/create_service_account/network.tf new file mode 100644 index 0000000000..76d33f6bfc --- /dev/null +++ b/test/fixtures/create_service_account/network.tf @@ -0,0 +1,47 @@ +/** + * Copyright 2018 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. + */ + +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + + +resource "google_compute_network" "main" { + project = var.project_id + name = "cft-gke-test-${random_string.suffix.result}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "main" { + project = var.project_id + name = "cft-gke-test-${random_string.suffix.result}" + ip_cidr_range = "10.0.0.0/17" + region = var.region + network = google_compute_network.main.self_link + + secondary_ip_range { + range_name = "cft-gke-test-pods-${random_string.suffix.result}" + ip_cidr_range = "192.168.0.0/18" + } + + secondary_ip_range { + range_name = "cft-gke-test-services-${random_string.suffix.result}" + ip_cidr_range = "192.168.64.0/18" + } +} + diff --git a/test/fixtures/create_service_account/outputs.tf b/test/fixtures/create_service_account/outputs.tf new file mode 120000 index 0000000000..726bdc722f --- /dev/null +++ b/test/fixtures/create_service_account/outputs.tf @@ -0,0 +1 @@ +../shared/outputs.tf \ No newline at end of file diff --git a/test/fixtures/create_service_account/terraform.tfvars b/test/fixtures/create_service_account/terraform.tfvars new file mode 120000 index 0000000000..08ac6f4724 --- /dev/null +++ b/test/fixtures/create_service_account/terraform.tfvars @@ -0,0 +1 @@ +../shared/terraform.tfvars \ No newline at end of file diff --git a/test/fixtures/create_service_account/variables.tf b/test/fixtures/create_service_account/variables.tf new file mode 120000 index 0000000000..c113c00a3d --- /dev/null +++ b/test/fixtures/create_service_account/variables.tf @@ -0,0 +1 @@ +../shared/variables.tf \ No newline at end of file diff --git a/test/fixtures/shared/outputs.tf b/test/fixtures/shared/outputs.tf index 1c2eb5e9ba..71b4b250de 100644 --- a/test/fixtures/shared/outputs.tf +++ b/test/fixtures/shared/outputs.tf @@ -79,3 +79,6 @@ output "service_account" { value = module.example.service_account } +output "registry_project_id" { + value = var.registry_project_id +} diff --git a/test/fixtures/shared/terraform.tfvars b/test/fixtures/shared/terraform.tfvars index e69de29bb2..8595587132 100644 --- a/test/fixtures/shared/terraform.tfvars +++ b/test/fixtures/shared/terraform.tfvars @@ -0,0 +1,6 @@ +project_id = "mm-kitchen-test-1" +registry_project_id = "mm-kitchen-test-2" +region = "us-east4" +zones = ["us-east4-a", "us-east4-b", "us-east4-c"] +compute_engine_service_account = "1039498062444-compute@developer.gserviceaccount.com" + diff --git a/test/fixtures/shared/terraform.tfvars.sample b/test/fixtures/shared/terraform.tfvars.sample index 3110e9b3d5..d83b4ca3d5 100644 --- a/test/fixtures/shared/terraform.tfvars.sample +++ b/test/fixtures/shared/terraform.tfvars.sample @@ -1,4 +1,6 @@ project_id="" +registry_project_id="" region="us-east4" zones=["us-east4-a","us-east4-b","us-east4-c"] compute_engine_service_account="" + diff --git a/test/fixtures/shared/variables.tf b/test/fixtures/shared/variables.tf index f8e3d6dfa4..f5e59bd0cc 100644 --- a/test/fixtures/shared/variables.tf +++ b/test/fixtures/shared/variables.tf @@ -32,3 +32,7 @@ variable "compute_engine_service_account" { description = "The email address of the service account to associate with the GKE cluster" } +variable "registry_project_id" { + description = "Project to use for granting access to the GCR registry, if requested" +} + diff --git a/test/integration/create_service_account/controls/gcloud.rb b/test/integration/create_service_account/controls/gcloud.rb new file mode 100644 index 0000000000..830e85667a --- /dev/null +++ b/test/integration/create_service_account/controls/gcloud.rb @@ -0,0 +1,116 @@ +# Copyright 2018 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. + +project_id = attribute('project_id') +registry_project_id = attribute('registry_project_id') +location = attribute('location') +cluster_name = attribute('cluster_name') +service_account = attribute('service_account') + +control "gcloud" do + title "Google Compute Engine GKE configuration" + + describe command("gcloud --project=#{project_id} container clusters --zone=#{location} describe #{cluster_name} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:data) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + + describe "cluster" do + it "is running" do + expect(data['status']).to eq 'RUNNING' + end + + + it "node config has service account" do + expect(data['nodeConfig']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ + end + + end + + describe "default node pool" do + it "exists" do + expect(data['nodePools']).to include( + including( + "name" => "default-pool", + ) + ) + end + end + + describe "node pool" do + let(:node_pools) { data['nodePools'].reject { |p| p['name'] == "default-pool" } } + + it "has the expected minimum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "minNodeCount" => 1, + ), + ) + ) + end + + it "has the expected maximum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "maxNodeCount" => 100, + ), + ) + ) + end + + it "has the expected labels" do + expect(node_pools).to include( + including( + "config" => including( + "labels" => including( + "cluster_name" => cluster_name, + "node_pool" => "default-node-pool", + ), + ), + ) + ) + end + + it "has service account" do + expect(node_pools[0]['config']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ + end + end + end + + describe command("gcloud projects get-iam-policy #{registry_project_id} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:iam) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + it "has expected registry roles" do + expect(iam['bindings']).to include("members" => ["serviceAccount:#{service_account}"], "role" => "roles/storage.objectViewer") + end + end + +end \ No newline at end of file diff --git a/test/integration/create_service_account/inspec.yml b/test/integration/create_service_account/inspec.yml new file mode 100644 index 0000000000..c9e8ee336e --- /dev/null +++ b/test/integration/create_service_account/inspec.yml @@ -0,0 +1,23 @@ +name: create_service_account +attributes: + - name: project_id + required: true + type: string + - name: registry_project_id + required: false + type: string + - name: location + required: true + type: string + - name: cluster_name + required: true + type: string + - name: kubernetes_endpoint + required: true + type: string + - name: client_token + required: true + type: string + - name: service_account + required: true + type: string diff --git a/variables.tf b/variables.tf index 460bdeaeff..bf20907042 100644 --- a/variables.tf +++ b/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -257,6 +257,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." From 3c4e8a166cf6c29526fd687a100b8b01f2b8fa15 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Tue, 1 Oct 2019 16:05:01 -0700 Subject: [PATCH 2/9] Fix an accidentally removed part of a comment. --- README.md | 2 +- autogen/variables.tf | 2 +- modules/beta-private-cluster/README.md | 2 +- modules/beta-private-cluster/variables.tf | 2 +- modules/beta-public-cluster/README.md | 2 +- modules/beta-public-cluster/variables.tf | 2 +- modules/private-cluster/README.md | 2 +- modules/private-cluster/variables.tf | 2 +- variables.tf | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 34d280b41b..2d273f1d71 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | diff --git a/autogen/variables.tf b/autogen/variables.tf index b9a29a1613..17566d238f 100644 --- a/autogen/variables.tf +++ b/autogen/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({cidr_blocks = list(object({cidr_block = string, display_name = string}))})) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md index f97bace58c..a9f1d18073 100644 --- a/modules/beta-private-cluster/README.md +++ b/modules/beta-private-cluster/README.md @@ -169,7 +169,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf index 586e7020c2..2c53d06b90 100644 --- a/modules/beta-private-cluster/variables.tf +++ b/modules/beta-private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md index 8d61b3b8ff..c8efe6f826 100644 --- a/modules/beta-public-cluster/README.md +++ b/modules/beta-public-cluster/README.md @@ -161,7 +161,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf index f1d0f26239..07771a27a9 100644 --- a/modules/beta-public-cluster/variables.tf +++ b/modules/beta-public-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md index 8f0b5ae585..82255a4712 100644 --- a/modules/private-cluster/README.md +++ b/modules/private-cluster/README.md @@ -158,7 +158,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf index 871b785816..00d7779e83 100644 --- a/modules/private-cluster/variables.tf +++ b/modules/private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/variables.tf b/variables.tf index bf20907042..da9c744646 100644 --- a/variables.tf +++ b/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } From d791335c52f46b6ac53b648f8c85a28b753d417e Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Fri, 4 Oct 2019 12:32:51 -0700 Subject: [PATCH 3/9] Removed the custom test for create_service_account I will integrate the test with the workload identity test. --- .kitchen.yml | 7 -- examples/create_service_account/README.md | 45 ------- examples/create_service_account/main.tf | 63 ---------- examples/create_service_account/outputs.tf | 35 ------ .../create_service_account/test_outputs.tf | 1 - examples/create_service_account/variables.tf | 54 -------- examples/workload_metadata_config/main.tf | 5 +- .../workload_metadata_config/variables.tf | 5 +- test/ci/create-service-account.yml | 18 --- .../create_service_account/example.tf | 30 ----- .../create_service_account/network.tf | 47 ------- .../create_service_account/outputs.tf | 1 - .../create_service_account/terraform.tfvars | 1 - .../create_service_account/variables.tf | 1 - .../workload_metadata_config/example.tf | 2 +- .../create_service_account/controls/gcloud.rb | 116 ------------------ .../create_service_account/inspec.yml | 23 ---- .../controls/gcloud.rb | 18 +++ .../workload_metadata_config/inspec.yml | 6 + 19 files changed, 30 insertions(+), 448 deletions(-) delete mode 100644 examples/create_service_account/README.md delete mode 100644 examples/create_service_account/main.tf delete mode 100644 examples/create_service_account/outputs.tf delete mode 120000 examples/create_service_account/test_outputs.tf delete mode 100644 examples/create_service_account/variables.tf delete mode 100644 test/ci/create-service-account.yml delete mode 100644 test/fixtures/create_service_account/example.tf delete mode 100644 test/fixtures/create_service_account/network.tf delete mode 120000 test/fixtures/create_service_account/outputs.tf delete mode 120000 test/fixtures/create_service_account/terraform.tfvars delete mode 120000 test/fixtures/create_service_account/variables.tf delete mode 100644 test/integration/create_service_account/controls/gcloud.rb delete mode 100644 test/integration/create_service_account/inspec.yml diff --git a/.kitchen.yml b/.kitchen.yml index 6a7fbf997b..6bf414c21f 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -29,13 +29,6 @@ platforms: - name: local suites: - - name: "create_service_account" - driver: - root_module_directory: test/fixtures/create_service_account - verifier: - systems: - - name: create_service_account - backend: local - name: "deploy_service" driver: root_module_directory: test/fixtures/deploy_service diff --git a/examples/create_service_account/README.md b/examples/create_service_account/README.md deleted file mode 100644 index ee2f605d18..0000000000 --- a/examples/create_service_account/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Simple Regional Cluster - -This example illustrates how to create a simple private cluster. - - -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|:----:|:-----:|:-----:| -| cluster\_name\_suffix | A suffix to append to the default cluster name | string | `""` | no | -| ip\_range\_pods | The secondary ip range to use for pods | string | n/a | yes | -| ip\_range\_services | The secondary ip range to use for pods | string | n/a | yes | -| network | The VPC network to host the cluster in | string | n/a | yes | -| project\_id | The project ID to host the cluster in | string | n/a | yes | -| region | The region to host the cluster in | string | n/a | yes | -| registry\_project\_id | Project name for the GCR registry | string | n/a | yes | -| subnetwork | The subnetwork to host the cluster in | string | n/a | yes | -| zones | The zone to host the cluster in (required if is a zonal cluster) | list(string) | n/a | yes | - -## Outputs - -| Name | Description | -|------|-------------| -| ca\_certificate | | -| client\_token | | -| cluster\_name | Cluster name | -| ip\_range\_pods | The secondary IP range used for pods | -| ip\_range\_services | The secondary IP range used for services | -| kubernetes\_endpoint | | -| location | | -| master\_kubernetes\_version | The master Kubernetes version | -| network | | -| project\_id | | -| region | | -| service\_account | The service account to default running nodes as if not overridden in `node_pools`. | -| subnetwork | | -| zones | List of zones in which the cluster resides | - - - -To provision this example, run the following from within this directory: -- `terraform init` to get the plugins -- `terraform plan` to see the infrastructure plan -- `terraform apply` to apply the infrastructure build -- `terraform destroy` to destroy the built infrastructure diff --git a/examples/create_service_account/main.tf b/examples/create_service_account/main.tf deleted file mode 100644 index f278bb79d6..0000000000 --- a/examples/create_service_account/main.tf +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright 2018 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 { - cluster_type = "create-service-account" -} - -provider "google" { - version = "~> 2.12.0" - region = var.region -} - -data "google_compute_subnetwork" "subnetwork" { - name = var.subnetwork - project = var.project_id - region = var.region -} - -module "gke" { - source = "../../modules/private-cluster/" - project_id = var.project_id - name = "${local.cluster_type}-cluster${var.cluster_name_suffix}" - regional = false - region = var.region - zones = var.zones - network = var.network - subnetwork = var.subnetwork - ip_range_pods = var.ip_range_pods - ip_range_services = var.ip_range_services - create_service_account = true - grant_registry_access = true - registry_project_id = var.registry_project_id - enable_private_endpoint = true - enable_private_nodes = true - master_ipv4_cidr_block = "172.16.0.0/28" - - master_authorized_networks_config = [ - { - cidr_blocks = [ - { - cidr_block = data.google_compute_subnetwork.subnetwork.ip_cidr_range - display_name = "VPC" - }, - ] - }, - ] -} - -data "google_client_config" "default" { -} diff --git a/examples/create_service_account/outputs.tf b/examples/create_service_account/outputs.tf deleted file mode 100644 index 0d972dcd88..0000000000 --- a/examples/create_service_account/outputs.tf +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2018 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 "kubernetes_endpoint" { - sensitive = true - value = module.gke.endpoint -} - -output "client_token" { - sensitive = true - value = base64encode(data.google_client_config.default.access_token) -} - -output "ca_certificate" { - value = module.gke.ca_certificate -} - -output "service_account" { - description = "The service account to default running nodes as if not overridden in `node_pools`." - value = module.gke.service_account -} - diff --git a/examples/create_service_account/test_outputs.tf b/examples/create_service_account/test_outputs.tf deleted file mode 120000 index 17b34213ba..0000000000 --- a/examples/create_service_account/test_outputs.tf +++ /dev/null @@ -1 +0,0 @@ -../../test/fixtures/all_examples/test_outputs.tf \ No newline at end of file diff --git a/examples/create_service_account/variables.tf b/examples/create_service_account/variables.tf deleted file mode 100644 index dfdea6bedd..0000000000 --- a/examples/create_service_account/variables.tf +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2018 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 "project_id" { - description = "The project ID to host the cluster in" -} - -variable "cluster_name_suffix" { - description = "A suffix to append to the default cluster name" - default = "" -} - -variable "region" { - description = "The region to host the cluster in" -} - -variable "zones" { - type = list(string) - description = "The zone to host the cluster in (required if is a zonal cluster)" -} - -variable "network" { - description = "The VPC network to host the cluster in" -} - -variable "subnetwork" { - description = "The subnetwork to host the cluster in" -} - -variable "ip_range_pods" { - description = "The secondary ip range to use for pods" -} - -variable "ip_range_services" { - description = "The secondary ip range to use for pods" -} - -variable "registry_project_id" { - description = "Project name for the GCR registry" -} - diff --git a/examples/workload_metadata_config/main.tf b/examples/workload_metadata_config/main.tf index 11cae808d4..f9fb25da5b 100644 --- a/examples/workload_metadata_config/main.tf +++ b/examples/workload_metadata_config/main.tf @@ -40,8 +40,9 @@ module "gke" { subnetwork = var.subnetwork ip_range_pods = var.ip_range_pods ip_range_services = var.ip_range_services - create_service_account = false - service_account = var.compute_engine_service_account + create_service_account = true + grant_registry_access = true + registry_project_id = var.registry_project_id enable_private_endpoint = true enable_private_nodes = true master_ipv4_cidr_block = "172.16.0.0/28" diff --git a/examples/workload_metadata_config/variables.tf b/examples/workload_metadata_config/variables.tf index 040c78d2c4..eaa8c36e83 100644 --- a/examples/workload_metadata_config/variables.tf +++ b/examples/workload_metadata_config/variables.tf @@ -48,7 +48,6 @@ variable "ip_range_services" { description = "The secondary ip range to use for pods" } -variable "compute_engine_service_account" { - description = "Service account to associate to the nodes in the cluster" +variable "registry_project_id" { + description = "Project name for the GCR registry" } - diff --git a/test/ci/create-service-account.yml b/test/ci/create-service-account.yml deleted file mode 100644 index 6bfa98bd77..0000000000 --- a/test/ci/create-service-account.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- - -platform: linux - -inputs: -- name: pull-request - path: terraform-google-kubernetes-engine - -run: - path: make - args: ['test_integration'] - dir: terraform-google-kubernetes-engine - -params: - SUITE: "create-service-account-local" - COMPUTE_ENGINE_SERVICE_ACCOUNT: "" - REGION: "us-east4" - ZONES: '["us-east4-a", "us-east4-b", "us-east4-c"]' diff --git a/test/fixtures/create_service_account/example.tf b/test/fixtures/create_service_account/example.tf deleted file mode 100644 index 9dbaa83e93..0000000000 --- a/test/fixtures/create_service_account/example.tf +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2018 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. - */ - -module "example" { - source = "../../../examples/create_service_account" - - project_id = var.project_id - cluster_name_suffix = "-${random_string.suffix.result}" - region = var.region - zones = slice(var.zones, 0, 1) - network = google_compute_network.main.name - subnetwork = google_compute_subnetwork.main.name - ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name - ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name - registry_project_id = var.registry_project_id -} - diff --git a/test/fixtures/create_service_account/network.tf b/test/fixtures/create_service_account/network.tf deleted file mode 100644 index 76d33f6bfc..0000000000 --- a/test/fixtures/create_service_account/network.tf +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2018 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. - */ - -resource "random_string" "suffix" { - length = 4 - special = false - upper = false -} - - -resource "google_compute_network" "main" { - project = var.project_id - name = "cft-gke-test-${random_string.suffix.result}" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "main" { - project = var.project_id - name = "cft-gke-test-${random_string.suffix.result}" - ip_cidr_range = "10.0.0.0/17" - region = var.region - network = google_compute_network.main.self_link - - secondary_ip_range { - range_name = "cft-gke-test-pods-${random_string.suffix.result}" - ip_cidr_range = "192.168.0.0/18" - } - - secondary_ip_range { - range_name = "cft-gke-test-services-${random_string.suffix.result}" - ip_cidr_range = "192.168.64.0/18" - } -} - diff --git a/test/fixtures/create_service_account/outputs.tf b/test/fixtures/create_service_account/outputs.tf deleted file mode 120000 index 726bdc722f..0000000000 --- a/test/fixtures/create_service_account/outputs.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/outputs.tf \ No newline at end of file diff --git a/test/fixtures/create_service_account/terraform.tfvars b/test/fixtures/create_service_account/terraform.tfvars deleted file mode 120000 index 08ac6f4724..0000000000 --- a/test/fixtures/create_service_account/terraform.tfvars +++ /dev/null @@ -1 +0,0 @@ -../shared/terraform.tfvars \ No newline at end of file diff --git a/test/fixtures/create_service_account/variables.tf b/test/fixtures/create_service_account/variables.tf deleted file mode 120000 index c113c00a3d..0000000000 --- a/test/fixtures/create_service_account/variables.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/variables.tf \ No newline at end of file diff --git a/test/fixtures/workload_metadata_config/example.tf b/test/fixtures/workload_metadata_config/example.tf index 4d4a98e119..f813059ed7 100644 --- a/test/fixtures/workload_metadata_config/example.tf +++ b/test/fixtures/workload_metadata_config/example.tf @@ -25,5 +25,5 @@ module "example" { subnetwork = google_compute_subnetwork.main.name ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name - compute_engine_service_account = var.compute_engine_service_account + registry_project_id = var.registry_project_id } diff --git a/test/integration/create_service_account/controls/gcloud.rb b/test/integration/create_service_account/controls/gcloud.rb deleted file mode 100644 index 830e85667a..0000000000 --- a/test/integration/create_service_account/controls/gcloud.rb +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2018 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. - -project_id = attribute('project_id') -registry_project_id = attribute('registry_project_id') -location = attribute('location') -cluster_name = attribute('cluster_name') -service_account = attribute('service_account') - -control "gcloud" do - title "Google Compute Engine GKE configuration" - - describe command("gcloud --project=#{project_id} container clusters --zone=#{location} describe #{cluster_name} --format=json") do - its(:exit_status) { should eq 0 } - its(:stderr) { should eq '' } - - let!(:data) do - if subject.exit_status == 0 - JSON.parse(subject.stdout) - else - {} - end - end - - describe "cluster" do - it "is running" do - expect(data['status']).to eq 'RUNNING' - end - - - it "node config has service account" do - expect(data['nodeConfig']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ - end - - end - - describe "default node pool" do - it "exists" do - expect(data['nodePools']).to include( - including( - "name" => "default-pool", - ) - ) - end - end - - describe "node pool" do - let(:node_pools) { data['nodePools'].reject { |p| p['name'] == "default-pool" } } - - it "has the expected minimum node count" do - expect(node_pools).to include( - including( - "autoscaling" => including( - "minNodeCount" => 1, - ), - ) - ) - end - - it "has the expected maximum node count" do - expect(node_pools).to include( - including( - "autoscaling" => including( - "maxNodeCount" => 100, - ), - ) - ) - end - - it "has the expected labels" do - expect(node_pools).to include( - including( - "config" => including( - "labels" => including( - "cluster_name" => cluster_name, - "node_pool" => "default-node-pool", - ), - ), - ) - ) - end - - it "has service account" do - expect(node_pools[0]['config']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ - end - end - end - - describe command("gcloud projects get-iam-policy #{registry_project_id} --format=json") do - its(:exit_status) { should eq 0 } - its(:stderr) { should eq '' } - - let!(:iam) do - if subject.exit_status == 0 - JSON.parse(subject.stdout) - else - {} - end - end - it "has expected registry roles" do - expect(iam['bindings']).to include("members" => ["serviceAccount:#{service_account}"], "role" => "roles/storage.objectViewer") - end - end - -end \ No newline at end of file diff --git a/test/integration/create_service_account/inspec.yml b/test/integration/create_service_account/inspec.yml deleted file mode 100644 index c9e8ee336e..0000000000 --- a/test/integration/create_service_account/inspec.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: create_service_account -attributes: - - name: project_id - required: true - type: string - - name: registry_project_id - required: false - type: string - - name: location - required: true - type: string - - name: cluster_name - required: true - type: string - - name: kubernetes_endpoint - required: true - type: string - - name: client_token - required: true - type: string - - name: service_account - required: true - type: string diff --git a/test/integration/workload_metadata_config/controls/gcloud.rb b/test/integration/workload_metadata_config/controls/gcloud.rb index ea9c3627ce..387ea8731e 100644 --- a/test/integration/workload_metadata_config/controls/gcloud.rb +++ b/test/integration/workload_metadata_config/controls/gcloud.rb @@ -13,8 +13,10 @@ # limitations under the License. project_id = attribute('project_id') +registry_project_id = attribute('registry_project_id') location = attribute('location') cluster_name = attribute('cluster_name') +service_account = attribute('service_account') control "gcloud" do title "Google Compute Engine GKE configuration" @@ -55,4 +57,20 @@ end end end + + describe command("gcloud projects get-iam-policy #{registry_project_id} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:iam) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + it "has expected registry roles" do + expect(iam['bindings']).to include("members" => ["serviceAccount:#{service_account}"], "role" => "roles/storage.objectViewer") + end + end end diff --git a/test/integration/workload_metadata_config/inspec.yml b/test/integration/workload_metadata_config/inspec.yml index f6f3811afa..4f2b7d40d6 100644 --- a/test/integration/workload_metadata_config/inspec.yml +++ b/test/integration/workload_metadata_config/inspec.yml @@ -9,3 +9,9 @@ attributes: - name: project_id required: true type: string + - name: service_account + required: true + type: string + - name: registry_project_id + required: false + type: string From bc0769d81eb625987a7112b17a0ce64a181a4c49 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Mon, 30 Sep 2019 17:56:10 -0700 Subject: [PATCH 4/9] Add a parameter 'registry_project_id' The PR allows configuring the project holding the GCR registry when used in connection with 'create_service_account'=true and grant_registry_access=true. Holding the GCR is a project with other resources increases the risk of exposing sensitive data to the service account running the nodes, as the required permissions of role roles/storage.objectViewer provide access to all storage objects in the project. --- .kitchen.yml | 17 +++ README.md | 6 +- autogen/README.md | 3 + autogen/sa.tf | 2 +- autogen/variables.tf | 8 +- examples/create_service_account/README.md | 45 +++++++ examples/create_service_account/main.tf | 63 ++++++++++ examples/create_service_account/outputs.tf | 35 ++++++ .../create_service_account/test_outputs.tf | 1 + examples/create_service_account/variables.tf | 54 ++++++++ modules/beta-private-cluster/README.md | 6 +- modules/beta-private-cluster/sa.tf | 2 +- modules/beta-private-cluster/variables.tf | 8 +- modules/beta-public-cluster/README.md | 6 +- modules/beta-public-cluster/sa.tf | 2 +- modules/beta-public-cluster/variables.tf | 8 +- modules/private-cluster/README.md | 6 +- modules/private-cluster/sa.tf | 2 +- modules/private-cluster/variables.tf | 8 +- sa.tf | 2 +- test/ci/create-service-account.yml | 18 +++ .../create_service_account/example.tf | 30 +++++ .../create_service_account/network.tf | 47 +++++++ .../create_service_account/outputs.tf | 1 + .../create_service_account/terraform.tfvars | 1 + .../create_service_account/variables.tf | 1 + test/fixtures/shared/outputs.tf | 3 + test/fixtures/shared/terraform.tfvars | 6 + test/fixtures/shared/terraform.tfvars.sample | 6 + test/fixtures/shared/variables.tf | 4 + .../create_service_account/controls/gcloud.rb | 116 ++++++++++++++++++ .../create_service_account/inspec.yml | 23 ++++ variables.tf | 8 +- 33 files changed, 534 insertions(+), 14 deletions(-) create mode 100644 examples/create_service_account/README.md create mode 100644 examples/create_service_account/main.tf create mode 100644 examples/create_service_account/outputs.tf create mode 120000 examples/create_service_account/test_outputs.tf create mode 100644 examples/create_service_account/variables.tf create mode 100644 test/ci/create-service-account.yml create mode 100644 test/fixtures/create_service_account/example.tf create mode 100644 test/fixtures/create_service_account/network.tf create mode 120000 test/fixtures/create_service_account/outputs.tf create mode 120000 test/fixtures/create_service_account/terraform.tfvars create mode 120000 test/fixtures/create_service_account/variables.tf create mode 100644 test/fixtures/shared/terraform.tfvars create mode 100644 test/fixtures/shared/terraform.tfvars.sample create mode 100644 test/integration/create_service_account/controls/gcloud.rb create mode 100644 test/integration/create_service_account/inspec.yml diff --git a/.kitchen.yml b/.kitchen.yml index 9f5df5a03e..baae693fd9 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -29,6 +29,7 @@ platforms: - name: local suites: +<<<<<<< HEAD # Disabled due to issue #274 # (https://github.com/terraform-google-modules/terraform-google-kubernetes-engine/issues/274) # - name: "deploy_service" @@ -38,6 +39,22 @@ suites: # systems: # - name: deploy_service # backend: local +======= + - name: "create_service_account" + driver: + root_module_directory: test/fixtures/create_service_account + verifier: + systems: + - name: create_service_account + backend: local + - name: "deploy_service" + driver: + root_module_directory: test/fixtures/deploy_service + verifier: + systems: + - name: deploy_service + backend: local +>>>>>>> Add a parameter 'registry_project_id' - name: "disable_client_cert" driver: root_module_directory: test/fixtures/disable_client_cert diff --git a/README.md b/README.md index 50e2afd63b..da77cb5971 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Then perform the following commands on the root folder: | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | @@ -151,6 +151,7 @@ Then perform the following commands on the root folder: | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | service\_account | The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created. | string | `""` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | map(list(string)) | `` | no | @@ -212,6 +213,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/autogen/README.md b/autogen/README.md index 421e4a2605..dc0b63b003 100644 --- a/autogen/README.md +++ b/autogen/README.md @@ -269,6 +269,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/autogen/sa.tf b/autogen/sa.tf index 62b31f457a..eaebeb2a22 100644 --- a/autogen/sa.tf +++ b/autogen/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/autogen/variables.tf b/autogen/variables.tf index 0fedacb2af..b9a29a1613 100644 --- a/autogen/variables.tf +++ b/autogen/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({cidr_blocks = list(object({cidr_block = string, display_name = string}))})) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -269,6 +269,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/examples/create_service_account/README.md b/examples/create_service_account/README.md new file mode 100644 index 0000000000..ee2f605d18 --- /dev/null +++ b/examples/create_service_account/README.md @@ -0,0 +1,45 @@ +# Simple Regional Cluster + +This example illustrates how to create a simple private cluster. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| cluster\_name\_suffix | A suffix to append to the default cluster name | string | `""` | no | +| ip\_range\_pods | The secondary ip range to use for pods | string | n/a | yes | +| ip\_range\_services | The secondary ip range to use for pods | string | n/a | yes | +| network | The VPC network to host the cluster in | string | n/a | yes | +| project\_id | The project ID to host the cluster in | string | n/a | yes | +| region | The region to host the cluster in | string | n/a | yes | +| registry\_project\_id | Project name for the GCR registry | string | n/a | yes | +| subnetwork | The subnetwork to host the cluster in | string | n/a | yes | +| zones | The zone to host the cluster in (required if is a zonal cluster) | list(string) | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| ca\_certificate | | +| client\_token | | +| cluster\_name | Cluster name | +| ip\_range\_pods | The secondary IP range used for pods | +| ip\_range\_services | The secondary IP range used for services | +| kubernetes\_endpoint | | +| location | | +| master\_kubernetes\_version | The master Kubernetes version | +| network | | +| project\_id | | +| region | | +| service\_account | The service account to default running nodes as if not overridden in `node_pools`. | +| subnetwork | | +| zones | List of zones in which the cluster resides | + + + +To provision this example, run the following from within this directory: +- `terraform init` to get the plugins +- `terraform plan` to see the infrastructure plan +- `terraform apply` to apply the infrastructure build +- `terraform destroy` to destroy the built infrastructure diff --git a/examples/create_service_account/main.tf b/examples/create_service_account/main.tf new file mode 100644 index 0000000000..f278bb79d6 --- /dev/null +++ b/examples/create_service_account/main.tf @@ -0,0 +1,63 @@ +/** + * Copyright 2018 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 { + cluster_type = "create-service-account" +} + +provider "google" { + version = "~> 2.12.0" + region = var.region +} + +data "google_compute_subnetwork" "subnetwork" { + name = var.subnetwork + project = var.project_id + region = var.region +} + +module "gke" { + source = "../../modules/private-cluster/" + project_id = var.project_id + name = "${local.cluster_type}-cluster${var.cluster_name_suffix}" + regional = false + region = var.region + zones = var.zones + network = var.network + subnetwork = var.subnetwork + ip_range_pods = var.ip_range_pods + ip_range_services = var.ip_range_services + create_service_account = true + grant_registry_access = true + registry_project_id = var.registry_project_id + enable_private_endpoint = true + enable_private_nodes = true + master_ipv4_cidr_block = "172.16.0.0/28" + + master_authorized_networks_config = [ + { + cidr_blocks = [ + { + cidr_block = data.google_compute_subnetwork.subnetwork.ip_cidr_range + display_name = "VPC" + }, + ] + }, + ] +} + +data "google_client_config" "default" { +} diff --git a/examples/create_service_account/outputs.tf b/examples/create_service_account/outputs.tf new file mode 100644 index 0000000000..0d972dcd88 --- /dev/null +++ b/examples/create_service_account/outputs.tf @@ -0,0 +1,35 @@ +/** + * Copyright 2018 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 "kubernetes_endpoint" { + sensitive = true + value = module.gke.endpoint +} + +output "client_token" { + sensitive = true + value = base64encode(data.google_client_config.default.access_token) +} + +output "ca_certificate" { + value = module.gke.ca_certificate +} + +output "service_account" { + description = "The service account to default running nodes as if not overridden in `node_pools`." + value = module.gke.service_account +} + diff --git a/examples/create_service_account/test_outputs.tf b/examples/create_service_account/test_outputs.tf new file mode 120000 index 0000000000..17b34213ba --- /dev/null +++ b/examples/create_service_account/test_outputs.tf @@ -0,0 +1 @@ +../../test/fixtures/all_examples/test_outputs.tf \ No newline at end of file diff --git a/examples/create_service_account/variables.tf b/examples/create_service_account/variables.tf new file mode 100644 index 0000000000..dfdea6bedd --- /dev/null +++ b/examples/create_service_account/variables.tf @@ -0,0 +1,54 @@ +/** + * Copyright 2018 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 "project_id" { + description = "The project ID to host the cluster in" +} + +variable "cluster_name_suffix" { + description = "A suffix to append to the default cluster name" + default = "" +} + +variable "region" { + description = "The region to host the cluster in" +} + +variable "zones" { + type = list(string) + description = "The zone to host the cluster in (required if is a zonal cluster)" +} + +variable "network" { + description = "The VPC network to host the cluster in" +} + +variable "subnetwork" { + description = "The subnetwork to host the cluster in" +} + +variable "ip_range_pods" { + description = "The secondary ip range to use for pods" +} + +variable "ip_range_services" { + description = "The secondary ip range to use for pods" +} + +variable "registry_project_id" { + description = "Project name for the GCR registry" +} + diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md index 988d48ead8..ef885f77c9 100644 --- a/modules/beta-private-cluster/README.md +++ b/modules/beta-private-cluster/README.md @@ -169,7 +169,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | @@ -190,6 +190,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | resource\_usage\_export\_dataset\_id | The dataset id for which network egress metering for this cluster will be enabled. If enabled, a daemonset will be created in the cluster to meter network egress traffic. | string | `""` | no | | sandbox\_enabled | (Beta) Enable GKE Sandbox (Do not forget to set `image_type` = `COS_CONTAINERD` and `node_version` = `1.12.7-gke.17` or later to use it). | bool | `"false"` | no | @@ -258,6 +259,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/beta-private-cluster/sa.tf b/modules/beta-private-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/beta-private-cluster/sa.tf +++ b/modules/beta-private-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf index 9a869a830f..586e7020c2 100644 --- a/modules/beta-private-cluster/variables.tf +++ b/modules/beta-private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -267,6 +267,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md index 7d59e927bf..53eb985f67 100644 --- a/modules/beta-public-cluster/README.md +++ b/modules/beta-public-cluster/README.md @@ -161,7 +161,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | @@ -181,6 +181,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | resource\_usage\_export\_dataset\_id | The dataset id for which network egress metering for this cluster will be enabled. If enabled, a daemonset will be created in the cluster to meter network egress traffic. | string | `""` | no | | sandbox\_enabled | (Beta) Enable GKE Sandbox (Do not forget to set `image_type` = `COS_CONTAINERD` and `node_version` = `1.12.7-gke.17` or later to use it). | bool | `"false"` | no | @@ -249,6 +250,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/beta-public-cluster/sa.tf b/modules/beta-public-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/beta-public-cluster/sa.tf +++ b/modules/beta-public-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf index 0ae2b75661..f1d0f26239 100644 --- a/modules/beta-public-cluster/variables.tf +++ b/modules/beta-public-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -267,6 +267,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md index d823f640fa..1f264f22f5 100644 --- a/modules/private-cluster/README.md +++ b/modules/private-cluster/README.md @@ -158,7 +158,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | @@ -176,6 +176,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | project\_id | The project ID to host the cluster in (required) | string | n/a | yes | | region | The region to host the cluster in (required) | string | n/a | yes | | regional | Whether is a regional cluster (zonal cluster if set false. WARNING: changing this after cluster creation is destructive!) | bool | `"true"` | no | +| registry\_project\_id | Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project. | string | `""` | no | | remove\_default\_node\_pool | Remove default node pool while setting up the cluster | bool | `"false"` | no | | service\_account | The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created. | string | `""` | no | | stub\_domains | Map of stub domains and their resolvers to forward DNS queries for a certain domain to an external DNS server | map(list(string)) | `` | no | @@ -237,6 +238,9 @@ following project roles: - roles/iam.serviceAccountUser - roles/resourcemanager.projectIamAdmin (only required if `service_account` is set to `create`) +Additionally, if `service_account` is set to `create` and `grant_registry_access` is requested, the service account requires the following role on the `registry_project_id` project: +- roles/resourcemanager.projectIamAdmin + ### Enable APIs In order to operate with the Service Account you must activate the following APIs on the project where the Service Account was created: diff --git a/modules/private-cluster/sa.tf b/modules/private-cluster/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/modules/private-cluster/sa.tf +++ b/modules/private-cluster/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf index 8008e08975..871b785816 100644 --- a/modules/private-cluster/variables.tf +++ b/modules/private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -257,6 +257,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." diff --git a/sa.tf b/sa.tf index 9e063fcc22..c7f34e4fbb 100644 --- a/sa.tf +++ b/sa.tf @@ -64,7 +64,7 @@ resource "google_project_iam_member" "cluster_service_account-monitoring_viewer" resource "google_project_iam_member" "cluster_service_account-gcr" { count = var.create_service_account && var.grant_registry_access ? 1 : 0 - project = var.project_id + project = var.registry_project_id == "" ? var.project_id : var.registry_project_id role = "roles/storage.objectViewer" member = "serviceAccount:${google_service_account.cluster_service_account[0].email}" } diff --git a/test/ci/create-service-account.yml b/test/ci/create-service-account.yml new file mode 100644 index 0000000000..6bfa98bd77 --- /dev/null +++ b/test/ci/create-service-account.yml @@ -0,0 +1,18 @@ +--- + +platform: linux + +inputs: +- name: pull-request + path: terraform-google-kubernetes-engine + +run: + path: make + args: ['test_integration'] + dir: terraform-google-kubernetes-engine + +params: + SUITE: "create-service-account-local" + COMPUTE_ENGINE_SERVICE_ACCOUNT: "" + REGION: "us-east4" + ZONES: '["us-east4-a", "us-east4-b", "us-east4-c"]' diff --git a/test/fixtures/create_service_account/example.tf b/test/fixtures/create_service_account/example.tf new file mode 100644 index 0000000000..9dbaa83e93 --- /dev/null +++ b/test/fixtures/create_service_account/example.tf @@ -0,0 +1,30 @@ +/** + * Copyright 2018 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. + */ + +module "example" { + source = "../../../examples/create_service_account" + + project_id = var.project_id + cluster_name_suffix = "-${random_string.suffix.result}" + region = var.region + zones = slice(var.zones, 0, 1) + network = google_compute_network.main.name + subnetwork = google_compute_subnetwork.main.name + ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name + ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name + registry_project_id = var.registry_project_id +} + diff --git a/test/fixtures/create_service_account/network.tf b/test/fixtures/create_service_account/network.tf new file mode 100644 index 0000000000..76d33f6bfc --- /dev/null +++ b/test/fixtures/create_service_account/network.tf @@ -0,0 +1,47 @@ +/** + * Copyright 2018 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. + */ + +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + + +resource "google_compute_network" "main" { + project = var.project_id + name = "cft-gke-test-${random_string.suffix.result}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "main" { + project = var.project_id + name = "cft-gke-test-${random_string.suffix.result}" + ip_cidr_range = "10.0.0.0/17" + region = var.region + network = google_compute_network.main.self_link + + secondary_ip_range { + range_name = "cft-gke-test-pods-${random_string.suffix.result}" + ip_cidr_range = "192.168.0.0/18" + } + + secondary_ip_range { + range_name = "cft-gke-test-services-${random_string.suffix.result}" + ip_cidr_range = "192.168.64.0/18" + } +} + diff --git a/test/fixtures/create_service_account/outputs.tf b/test/fixtures/create_service_account/outputs.tf new file mode 120000 index 0000000000..726bdc722f --- /dev/null +++ b/test/fixtures/create_service_account/outputs.tf @@ -0,0 +1 @@ +../shared/outputs.tf \ No newline at end of file diff --git a/test/fixtures/create_service_account/terraform.tfvars b/test/fixtures/create_service_account/terraform.tfvars new file mode 120000 index 0000000000..08ac6f4724 --- /dev/null +++ b/test/fixtures/create_service_account/terraform.tfvars @@ -0,0 +1 @@ +../shared/terraform.tfvars \ No newline at end of file diff --git a/test/fixtures/create_service_account/variables.tf b/test/fixtures/create_service_account/variables.tf new file mode 120000 index 0000000000..c113c00a3d --- /dev/null +++ b/test/fixtures/create_service_account/variables.tf @@ -0,0 +1 @@ +../shared/variables.tf \ No newline at end of file diff --git a/test/fixtures/shared/outputs.tf b/test/fixtures/shared/outputs.tf index 1c2eb5e9ba..71b4b250de 100644 --- a/test/fixtures/shared/outputs.tf +++ b/test/fixtures/shared/outputs.tf @@ -79,3 +79,6 @@ output "service_account" { value = module.example.service_account } +output "registry_project_id" { + value = var.registry_project_id +} diff --git a/test/fixtures/shared/terraform.tfvars b/test/fixtures/shared/terraform.tfvars new file mode 100644 index 0000000000..8595587132 --- /dev/null +++ b/test/fixtures/shared/terraform.tfvars @@ -0,0 +1,6 @@ +project_id = "mm-kitchen-test-1" +registry_project_id = "mm-kitchen-test-2" +region = "us-east4" +zones = ["us-east4-a", "us-east4-b", "us-east4-c"] +compute_engine_service_account = "1039498062444-compute@developer.gserviceaccount.com" + diff --git a/test/fixtures/shared/terraform.tfvars.sample b/test/fixtures/shared/terraform.tfvars.sample new file mode 100644 index 0000000000..d83b4ca3d5 --- /dev/null +++ b/test/fixtures/shared/terraform.tfvars.sample @@ -0,0 +1,6 @@ +project_id="" +registry_project_id="" +region="us-east4" +zones=["us-east4-a","us-east4-b","us-east4-c"] +compute_engine_service_account="" + diff --git a/test/fixtures/shared/variables.tf b/test/fixtures/shared/variables.tf index 76280e0065..5dff24dbd4 100644 --- a/test/fixtures/shared/variables.tf +++ b/test/fixtures/shared/variables.tf @@ -33,3 +33,7 @@ variable "compute_engine_service_account" { description = "The email address of the service account to associate with the GKE cluster" } +variable "registry_project_id" { + description = "Project to use for granting access to the GCR registry, if requested" +} + diff --git a/test/integration/create_service_account/controls/gcloud.rb b/test/integration/create_service_account/controls/gcloud.rb new file mode 100644 index 0000000000..830e85667a --- /dev/null +++ b/test/integration/create_service_account/controls/gcloud.rb @@ -0,0 +1,116 @@ +# Copyright 2018 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. + +project_id = attribute('project_id') +registry_project_id = attribute('registry_project_id') +location = attribute('location') +cluster_name = attribute('cluster_name') +service_account = attribute('service_account') + +control "gcloud" do + title "Google Compute Engine GKE configuration" + + describe command("gcloud --project=#{project_id} container clusters --zone=#{location} describe #{cluster_name} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:data) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + + describe "cluster" do + it "is running" do + expect(data['status']).to eq 'RUNNING' + end + + + it "node config has service account" do + expect(data['nodeConfig']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ + end + + end + + describe "default node pool" do + it "exists" do + expect(data['nodePools']).to include( + including( + "name" => "default-pool", + ) + ) + end + end + + describe "node pool" do + let(:node_pools) { data['nodePools'].reject { |p| p['name'] == "default-pool" } } + + it "has the expected minimum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "minNodeCount" => 1, + ), + ) + ) + end + + it "has the expected maximum node count" do + expect(node_pools).to include( + including( + "autoscaling" => including( + "maxNodeCount" => 100, + ), + ) + ) + end + + it "has the expected labels" do + expect(node_pools).to include( + including( + "config" => including( + "labels" => including( + "cluster_name" => cluster_name, + "node_pool" => "default-node-pool", + ), + ), + ) + ) + end + + it "has service account" do + expect(node_pools[0]['config']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ + end + end + end + + describe command("gcloud projects get-iam-policy #{registry_project_id} --format=json") do + its(:exit_status) { should eq 0 } + its(:stderr) { should eq '' } + + let!(:iam) do + if subject.exit_status == 0 + JSON.parse(subject.stdout) + else + {} + end + end + it "has expected registry roles" do + expect(iam['bindings']).to include("members" => ["serviceAccount:#{service_account}"], "role" => "roles/storage.objectViewer") + end + end + +end \ No newline at end of file diff --git a/test/integration/create_service_account/inspec.yml b/test/integration/create_service_account/inspec.yml new file mode 100644 index 0000000000..c9e8ee336e --- /dev/null +++ b/test/integration/create_service_account/inspec.yml @@ -0,0 +1,23 @@ +name: create_service_account +attributes: + - name: project_id + required: true + type: string + - name: registry_project_id + required: false + type: string + - name: location + required: true + type: string + - name: cluster_name + required: true + type: string + - name: kubernetes_endpoint + required: true + type: string + - name: client_token + required: true + type: string + - name: service_account + required: true + type: string diff --git a/variables.tf b/variables.tf index 460bdeaeff..bf20907042 100644 --- a/variables.tf +++ b/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." default = [] } @@ -257,6 +257,12 @@ variable "grant_registry_access" { default = false } +variable "registry_project_id" { + type = string + description = "Project holding the Google Container Registry. If empty, we use the cluster project. If grant_registry_access is true, storage.objectViewer role is assigned on this project." + default = "" +} + variable "service_account" { type = string description = "The service account to run nodes as if not overridden in `node_pools`. The create_service_account variable default value (true) will cause a cluster-specific service account to be created." From ec9d46b046b0991e304bf8fa05c009a1c1a46c7a Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Tue, 1 Oct 2019 16:05:01 -0700 Subject: [PATCH 5/9] Fix an accidentally removed part of a comment. --- README.md | 2 +- autogen/variables.tf | 2 +- modules/beta-private-cluster/README.md | 2 +- modules/beta-private-cluster/variables.tf | 2 +- modules/beta-public-cluster/README.md | 2 +- modules/beta-public-cluster/variables.tf | 2 +- modules/private-cluster/README.md | 2 +- modules/private-cluster/variables.tf | 2 +- variables.tf | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index da77cb5971..84787d3124 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ Then perform the following commands on the root folder: | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | diff --git a/autogen/variables.tf b/autogen/variables.tf index b9a29a1613..17566d238f 100644 --- a/autogen/variables.tf +++ b/autogen/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({cidr_blocks = list(object({cidr_block = string, display_name = string}))})) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md index ef885f77c9..c2920e4b28 100644 --- a/modules/beta-private-cluster/README.md +++ b/modules/beta-private-cluster/README.md @@ -169,7 +169,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf index 586e7020c2..2c53d06b90 100644 --- a/modules/beta-private-cluster/variables.tf +++ b/modules/beta-private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md index 53eb985f67..f013439240 100644 --- a/modules/beta-public-cluster/README.md +++ b/modules/beta-public-cluster/README.md @@ -161,7 +161,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | | network | The VPC network to host the cluster in (required) | string | n/a | yes | diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf index f1d0f26239..07771a27a9 100644 --- a/modules/beta-public-cluster/variables.tf +++ b/modules/beta-public-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md index 1f264f22f5..f7f8fef179 100644 --- a/modules/private-cluster/README.md +++ b/modules/private-cluster/README.md @@ -158,7 +158,7 @@ In either case, upgrading to module version `v1.0.0` will trigger a recreation o | kubernetes\_version | The Kubernetes version of the masters. If set to 'latest' it will pull latest available version in the selected region. | string | `"latest"` | no | | logging\_service | The logging service that the cluster should write logs to. Available options include logging.googleapis.com, logging.googleapis.com/kubernetes (beta), and none | string | `"logging.googleapis.com"` | no | | maintenance\_start\_time | Time window specified for daily maintenance operations in RFC3339 format | string | `"05:00"` | no | -| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | +| master\_authorized\_networks\_config | The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists). | object | `` | no | | master\_ipv4\_cidr\_block | (Beta) The IP range in CIDR notation to use for the hosted master network | string | `"10.0.0.0/28"` | no | | monitoring\_service | The monitoring service that the cluster should write metrics to. Automatically send metrics from pods in the cluster to the Google Cloud Monitoring API. VM metrics will be collected by Google Compute Engine regardless of this setting Available options include monitoring.googleapis.com, monitoring.googleapis.com/kubernetes (beta) and none | string | `"monitoring.googleapis.com"` | no | | name | The name of the cluster (required) | string | n/a | yes | diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf index 871b785816..00d7779e83 100644 --- a/modules/private-cluster/variables.tf +++ b/modules/private-cluster/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } diff --git a/variables.tf b/variables.tf index bf20907042..da9c744646 100644 --- a/variables.tf +++ b/variables.tf @@ -79,7 +79,7 @@ variable "node_version" { variable "master_authorized_networks_config" { type = list(object({ cidr_blocks = list(object({ cidr_block = string, display_name = string })) })) - description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external (except the cluster node IPs, which GKE automatically whitelists)." + description = "The desired configuration options for master authorized networks. The object format is {cidr_blocks = list(object({cidr_block = string, display_name = string}))}. Omit the nested cidr_blocks attribute to disallow external access (except the cluster node IPs, which GKE automatically whitelists)." default = [] } From 5258f8917a43990bf5346b84cc4a1ec52908a7e0 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Fri, 4 Oct 2019 13:27:30 -0700 Subject: [PATCH 6/9] Removing a few conflicting files. --- test/fixtures/shared/terraform.tfvars | 6 ------ test/fixtures/shared/terraform.tfvars.sample | 6 ------ .../fixtures/workload_metadata_config/example.tf | 16 ++++++++-------- 3 files changed, 8 insertions(+), 20 deletions(-) delete mode 100644 test/fixtures/shared/terraform.tfvars delete mode 100644 test/fixtures/shared/terraform.tfvars.sample diff --git a/test/fixtures/shared/terraform.tfvars b/test/fixtures/shared/terraform.tfvars deleted file mode 100644 index 8595587132..0000000000 --- a/test/fixtures/shared/terraform.tfvars +++ /dev/null @@ -1,6 +0,0 @@ -project_id = "mm-kitchen-test-1" -registry_project_id = "mm-kitchen-test-2" -region = "us-east4" -zones = ["us-east4-a", "us-east4-b", "us-east4-c"] -compute_engine_service_account = "1039498062444-compute@developer.gserviceaccount.com" - diff --git a/test/fixtures/shared/terraform.tfvars.sample b/test/fixtures/shared/terraform.tfvars.sample deleted file mode 100644 index d83b4ca3d5..0000000000 --- a/test/fixtures/shared/terraform.tfvars.sample +++ /dev/null @@ -1,6 +0,0 @@ -project_id="" -registry_project_id="" -region="us-east4" -zones=["us-east4-a","us-east4-b","us-east4-c"] -compute_engine_service_account="" - diff --git a/test/fixtures/workload_metadata_config/example.tf b/test/fixtures/workload_metadata_config/example.tf index f813059ed7..3568cfa404 100644 --- a/test/fixtures/workload_metadata_config/example.tf +++ b/test/fixtures/workload_metadata_config/example.tf @@ -17,13 +17,13 @@ module "example" { source = "../../../examples/workload_metadata_config" - project_id = var.project_id - cluster_name_suffix = "-${random_string.suffix.result}" - region = var.region - zones = slice(var.zones, 0, 1) - network = google_compute_network.main.name - subnetwork = google_compute_subnetwork.main.name - ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name - ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name + project_id = var.project_id + cluster_name_suffix = "-${random_string.suffix.result}" + region = var.region + zones = slice(var.zones, 0, 1) + network = google_compute_network.main.name + subnetwork = google_compute_subnetwork.main.name + ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name + ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name registry_project_id = var.registry_project_id } From 04a1a8c487ccbfb867c18f1168c35cb8796ffe46 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Fri, 4 Oct 2019 13:35:41 -0700 Subject: [PATCH 7/9] Removed tests for create_service_account --- .kitchen.yml | 10 -- examples/create_service_account/README.md | 45 ------- examples/create_service_account/main.tf | 63 ---------- examples/create_service_account/outputs.tf | 35 ------ .../create_service_account/test_outputs.tf | 1 - examples/create_service_account/variables.tf | 54 -------- test/ci/create-service-account.yml | 18 --- .../create_service_account/terraform.tfvars | 1 - .../create_service_account/controls/gcloud.rb | 116 ------------------ .../create_service_account/inspec.yml | 23 ---- 10 files changed, 366 deletions(-) delete mode 100644 examples/create_service_account/README.md delete mode 100644 examples/create_service_account/main.tf delete mode 100644 examples/create_service_account/outputs.tf delete mode 120000 examples/create_service_account/test_outputs.tf delete mode 100644 examples/create_service_account/variables.tf delete mode 100644 test/ci/create-service-account.yml delete mode 120000 test/fixtures/create_service_account/terraform.tfvars delete mode 100644 test/integration/create_service_account/controls/gcloud.rb delete mode 100644 test/integration/create_service_account/inspec.yml diff --git a/.kitchen.yml b/.kitchen.yml index baae693fd9..d072a969cb 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -29,7 +29,6 @@ platforms: - name: local suites: -<<<<<<< HEAD # Disabled due to issue #274 # (https://github.com/terraform-google-modules/terraform-google-kubernetes-engine/issues/274) # - name: "deploy_service" @@ -39,14 +38,6 @@ suites: # systems: # - name: deploy_service # backend: local -======= - - name: "create_service_account" - driver: - root_module_directory: test/fixtures/create_service_account - verifier: - systems: - - name: create_service_account - backend: local - name: "deploy_service" driver: root_module_directory: test/fixtures/deploy_service @@ -54,7 +45,6 @@ suites: systems: - name: deploy_service backend: local ->>>>>>> Add a parameter 'registry_project_id' - name: "disable_client_cert" driver: root_module_directory: test/fixtures/disable_client_cert diff --git a/examples/create_service_account/README.md b/examples/create_service_account/README.md deleted file mode 100644 index ee2f605d18..0000000000 --- a/examples/create_service_account/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Simple Regional Cluster - -This example illustrates how to create a simple private cluster. - - -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|:----:|:-----:|:-----:| -| cluster\_name\_suffix | A suffix to append to the default cluster name | string | `""` | no | -| ip\_range\_pods | The secondary ip range to use for pods | string | n/a | yes | -| ip\_range\_services | The secondary ip range to use for pods | string | n/a | yes | -| network | The VPC network to host the cluster in | string | n/a | yes | -| project\_id | The project ID to host the cluster in | string | n/a | yes | -| region | The region to host the cluster in | string | n/a | yes | -| registry\_project\_id | Project name for the GCR registry | string | n/a | yes | -| subnetwork | The subnetwork to host the cluster in | string | n/a | yes | -| zones | The zone to host the cluster in (required if is a zonal cluster) | list(string) | n/a | yes | - -## Outputs - -| Name | Description | -|------|-------------| -| ca\_certificate | | -| client\_token | | -| cluster\_name | Cluster name | -| ip\_range\_pods | The secondary IP range used for pods | -| ip\_range\_services | The secondary IP range used for services | -| kubernetes\_endpoint | | -| location | | -| master\_kubernetes\_version | The master Kubernetes version | -| network | | -| project\_id | | -| region | | -| service\_account | The service account to default running nodes as if not overridden in `node_pools`. | -| subnetwork | | -| zones | List of zones in which the cluster resides | - - - -To provision this example, run the following from within this directory: -- `terraform init` to get the plugins -- `terraform plan` to see the infrastructure plan -- `terraform apply` to apply the infrastructure build -- `terraform destroy` to destroy the built infrastructure diff --git a/examples/create_service_account/main.tf b/examples/create_service_account/main.tf deleted file mode 100644 index f278bb79d6..0000000000 --- a/examples/create_service_account/main.tf +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright 2018 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 { - cluster_type = "create-service-account" -} - -provider "google" { - version = "~> 2.12.0" - region = var.region -} - -data "google_compute_subnetwork" "subnetwork" { - name = var.subnetwork - project = var.project_id - region = var.region -} - -module "gke" { - source = "../../modules/private-cluster/" - project_id = var.project_id - name = "${local.cluster_type}-cluster${var.cluster_name_suffix}" - regional = false - region = var.region - zones = var.zones - network = var.network - subnetwork = var.subnetwork - ip_range_pods = var.ip_range_pods - ip_range_services = var.ip_range_services - create_service_account = true - grant_registry_access = true - registry_project_id = var.registry_project_id - enable_private_endpoint = true - enable_private_nodes = true - master_ipv4_cidr_block = "172.16.0.0/28" - - master_authorized_networks_config = [ - { - cidr_blocks = [ - { - cidr_block = data.google_compute_subnetwork.subnetwork.ip_cidr_range - display_name = "VPC" - }, - ] - }, - ] -} - -data "google_client_config" "default" { -} diff --git a/examples/create_service_account/outputs.tf b/examples/create_service_account/outputs.tf deleted file mode 100644 index 0d972dcd88..0000000000 --- a/examples/create_service_account/outputs.tf +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2018 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 "kubernetes_endpoint" { - sensitive = true - value = module.gke.endpoint -} - -output "client_token" { - sensitive = true - value = base64encode(data.google_client_config.default.access_token) -} - -output "ca_certificate" { - value = module.gke.ca_certificate -} - -output "service_account" { - description = "The service account to default running nodes as if not overridden in `node_pools`." - value = module.gke.service_account -} - diff --git a/examples/create_service_account/test_outputs.tf b/examples/create_service_account/test_outputs.tf deleted file mode 120000 index 17b34213ba..0000000000 --- a/examples/create_service_account/test_outputs.tf +++ /dev/null @@ -1 +0,0 @@ -../../test/fixtures/all_examples/test_outputs.tf \ No newline at end of file diff --git a/examples/create_service_account/variables.tf b/examples/create_service_account/variables.tf deleted file mode 100644 index dfdea6bedd..0000000000 --- a/examples/create_service_account/variables.tf +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2018 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 "project_id" { - description = "The project ID to host the cluster in" -} - -variable "cluster_name_suffix" { - description = "A suffix to append to the default cluster name" - default = "" -} - -variable "region" { - description = "The region to host the cluster in" -} - -variable "zones" { - type = list(string) - description = "The zone to host the cluster in (required if is a zonal cluster)" -} - -variable "network" { - description = "The VPC network to host the cluster in" -} - -variable "subnetwork" { - description = "The subnetwork to host the cluster in" -} - -variable "ip_range_pods" { - description = "The secondary ip range to use for pods" -} - -variable "ip_range_services" { - description = "The secondary ip range to use for pods" -} - -variable "registry_project_id" { - description = "Project name for the GCR registry" -} - diff --git a/test/ci/create-service-account.yml b/test/ci/create-service-account.yml deleted file mode 100644 index 6bfa98bd77..0000000000 --- a/test/ci/create-service-account.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- - -platform: linux - -inputs: -- name: pull-request - path: terraform-google-kubernetes-engine - -run: - path: make - args: ['test_integration'] - dir: terraform-google-kubernetes-engine - -params: - SUITE: "create-service-account-local" - COMPUTE_ENGINE_SERVICE_ACCOUNT: "" - REGION: "us-east4" - ZONES: '["us-east4-a", "us-east4-b", "us-east4-c"]' diff --git a/test/fixtures/create_service_account/terraform.tfvars b/test/fixtures/create_service_account/terraform.tfvars deleted file mode 120000 index 08ac6f4724..0000000000 --- a/test/fixtures/create_service_account/terraform.tfvars +++ /dev/null @@ -1 +0,0 @@ -../shared/terraform.tfvars \ No newline at end of file diff --git a/test/integration/create_service_account/controls/gcloud.rb b/test/integration/create_service_account/controls/gcloud.rb deleted file mode 100644 index 830e85667a..0000000000 --- a/test/integration/create_service_account/controls/gcloud.rb +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2018 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. - -project_id = attribute('project_id') -registry_project_id = attribute('registry_project_id') -location = attribute('location') -cluster_name = attribute('cluster_name') -service_account = attribute('service_account') - -control "gcloud" do - title "Google Compute Engine GKE configuration" - - describe command("gcloud --project=#{project_id} container clusters --zone=#{location} describe #{cluster_name} --format=json") do - its(:exit_status) { should eq 0 } - its(:stderr) { should eq '' } - - let!(:data) do - if subject.exit_status == 0 - JSON.parse(subject.stdout) - else - {} - end - end - - describe "cluster" do - it "is running" do - expect(data['status']).to eq 'RUNNING' - end - - - it "node config has service account" do - expect(data['nodeConfig']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ - end - - end - - describe "default node pool" do - it "exists" do - expect(data['nodePools']).to include( - including( - "name" => "default-pool", - ) - ) - end - end - - describe "node pool" do - let(:node_pools) { data['nodePools'].reject { |p| p['name'] == "default-pool" } } - - it "has the expected minimum node count" do - expect(node_pools).to include( - including( - "autoscaling" => including( - "minNodeCount" => 1, - ), - ) - ) - end - - it "has the expected maximum node count" do - expect(node_pools).to include( - including( - "autoscaling" => including( - "maxNodeCount" => 100, - ), - ) - ) - end - - it "has the expected labels" do - expect(node_pools).to include( - including( - "config" => including( - "labels" => including( - "cluster_name" => cluster_name, - "node_pool" => "default-node-pool", - ), - ), - ) - ) - end - - it "has service account" do - expect(node_pools[0]['config']['serviceAccount']).to match /tf-gke-.*@#{project_id}.iam.gserviceaccount.com/ - end - end - end - - describe command("gcloud projects get-iam-policy #{registry_project_id} --format=json") do - its(:exit_status) { should eq 0 } - its(:stderr) { should eq '' } - - let!(:iam) do - if subject.exit_status == 0 - JSON.parse(subject.stdout) - else - {} - end - end - it "has expected registry roles" do - expect(iam['bindings']).to include("members" => ["serviceAccount:#{service_account}"], "role" => "roles/storage.objectViewer") - end - end - -end \ No newline at end of file diff --git a/test/integration/create_service_account/inspec.yml b/test/integration/create_service_account/inspec.yml deleted file mode 100644 index c9e8ee336e..0000000000 --- a/test/integration/create_service_account/inspec.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: create_service_account -attributes: - - name: project_id - required: true - type: string - - name: registry_project_id - required: false - type: string - - name: location - required: true - type: string - - name: cluster_name - required: true - type: string - - name: kubernetes_endpoint - required: true - type: string - - name: client_token - required: true - type: string - - name: service_account - required: true - type: string From 22231516f022fbd43875a4ab8f478a7f69a1de56 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Fri, 4 Oct 2019 13:40:52 -0700 Subject: [PATCH 8/9] Remove another section of the test. --- README.md | 16 +++++++ .../create_service_account/example.tf | 30 ------------ .../create_service_account/network.tf | 47 ------------------- .../create_service_account/outputs.tf | 1 - .../create_service_account/variables.tf | 1 - 5 files changed, 16 insertions(+), 79 deletions(-) delete mode 100644 test/fixtures/create_service_account/example.tf delete mode 100644 test/fixtures/create_service_account/network.tf delete mode 120000 test/fixtures/create_service_account/outputs.tf delete mode 120000 test/fixtures/create_service_account/variables.tf diff --git a/README.md b/README.md index 84787d3124..02f020d54a 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,22 @@ Then perform the following commands on the root folder: - `terraform apply` to apply the infrastructure build - `terraform destroy` to destroy the built infrastructure +## Upgrade to v3.0.0 + +v3.0.0 is a breaking release. Refer to the +[Upgrading to v3.0 guide][upgrading-to-v3.0] for details. + +## Upgrade to v2.0.0 + +v2.0.0 is a breaking release. Refer to the +[Upgrading to v2.0 guide][upgrading-to-v2.0] for details. + +## Upgrade to v1.0.0 + +Version 1.0.0 of this module introduces a breaking change: adding the `disable-legacy-endpoints` metadata field to all node pools. This metadata is required by GKE and [determines whether the `/0.1/` and `/v1beta1/` paths are available in the nodes' metadata server](https://cloud.google.com/kubernetes-engine/docs/how-to/protecting-cluster-metadata#disable-legacy-apis). If your applications do not require access to the node's metadata server, you can leave the default value of `true` provided by the module. If your applications require access to the metadata server, be sure to read the linked documentation to see if you need to set the value for this field to `false` to allow your applications access to the above metadata server paths. + +In either case, upgrading to module version `v1.0.0` will trigger a recreation of all node pools in the cluster. + ## Inputs diff --git a/test/fixtures/create_service_account/example.tf b/test/fixtures/create_service_account/example.tf deleted file mode 100644 index 9dbaa83e93..0000000000 --- a/test/fixtures/create_service_account/example.tf +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2018 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. - */ - -module "example" { - source = "../../../examples/create_service_account" - - project_id = var.project_id - cluster_name_suffix = "-${random_string.suffix.result}" - region = var.region - zones = slice(var.zones, 0, 1) - network = google_compute_network.main.name - subnetwork = google_compute_subnetwork.main.name - ip_range_pods = google_compute_subnetwork.main.secondary_ip_range[0].range_name - ip_range_services = google_compute_subnetwork.main.secondary_ip_range[1].range_name - registry_project_id = var.registry_project_id -} - diff --git a/test/fixtures/create_service_account/network.tf b/test/fixtures/create_service_account/network.tf deleted file mode 100644 index 76d33f6bfc..0000000000 --- a/test/fixtures/create_service_account/network.tf +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2018 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. - */ - -resource "random_string" "suffix" { - length = 4 - special = false - upper = false -} - - -resource "google_compute_network" "main" { - project = var.project_id - name = "cft-gke-test-${random_string.suffix.result}" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "main" { - project = var.project_id - name = "cft-gke-test-${random_string.suffix.result}" - ip_cidr_range = "10.0.0.0/17" - region = var.region - network = google_compute_network.main.self_link - - secondary_ip_range { - range_name = "cft-gke-test-pods-${random_string.suffix.result}" - ip_cidr_range = "192.168.0.0/18" - } - - secondary_ip_range { - range_name = "cft-gke-test-services-${random_string.suffix.result}" - ip_cidr_range = "192.168.64.0/18" - } -} - diff --git a/test/fixtures/create_service_account/outputs.tf b/test/fixtures/create_service_account/outputs.tf deleted file mode 120000 index 726bdc722f..0000000000 --- a/test/fixtures/create_service_account/outputs.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/outputs.tf \ No newline at end of file diff --git a/test/fixtures/create_service_account/variables.tf b/test/fixtures/create_service_account/variables.tf deleted file mode 120000 index c113c00a3d..0000000000 --- a/test/fixtures/create_service_account/variables.tf +++ /dev/null @@ -1 +0,0 @@ -../shared/variables.tf \ No newline at end of file From da7629ec763980b7c59ddb3f523c56699417cb62 Mon Sep 17 00:00:00 2001 From: Mirko Montanari Date: Fri, 4 Oct 2019 13:43:22 -0700 Subject: [PATCH 9/9] Added the registry_project_id variable to the test script. --- test/setup/make_source.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/setup/make_source.sh b/test/setup/make_source.sh index b39944af41..ad3f57165a 100755 --- a/test/setup/make_source.sh +++ b/test/setup/make_source.sh @@ -19,6 +19,9 @@ echo "#!/usr/bin/env bash" > ../source.sh project_id=$(terraform output project_id) echo "export TF_VAR_project_id='$project_id'" >> ../source.sh +# We use the same project for registry project in the tests. +echo "export TF_VAR_registry_project_id='$project_id'" >> ../source.sh + sa_json=$(terraform output sa_key) # shellcheck disable=SC2086 echo "export SERVICE_ACCOUNT_JSON='$(echo $sa_json | base64 --decode)'" >> ../source.sh