diff --git a/examples/simple_zonal_with_asm/README.md b/examples/simple_zonal_with_asm/README.md index e6ffd9bc6..ce486ec50 100644 --- a/examples/simple_zonal_with_asm/README.md +++ b/examples/simple_zonal_with_asm/README.md @@ -13,7 +13,6 @@ This example illustrates how to create a simple zonal cluster with ASM. | network | The VPC network to host the cluster in | `any` | n/a | yes | | project\_id | The project ID to host the cluster in | `any` | n/a | yes | | region | The region to host the cluster in | `any` | n/a | yes | -| service\_account | The GCP Service Account email address used to deploy ASM. | `string` | `""` | no | | subnetwork | The subnetwork to host the cluster in | `any` | n/a | yes | | zones | The zone to host the cluster in (required if is a zonal cluster) | `list(string)` | n/a | yes | diff --git a/examples/simple_zonal_with_asm/main.tf b/examples/simple_zonal_with_asm/main.tf index 3b68190c7..fef74b418 100644 --- a/examples/simple_zonal_with_asm/main.tf +++ b/examples/simple_zonal_with_asm/main.tf @@ -24,7 +24,7 @@ provider "google-beta" { } provider "google" { - version = "~> 3.42.0" + version = "~> 3.63.0" region = var.region } @@ -75,7 +75,6 @@ module "asm" { enable_cluster_roles = true enable_cluster_labels = true enable_gcp_apis = true - enable_gcp_iam_roles = true enable_gcp_components = true options = ["envoy-access-log"] outdir = "./${module.gke.name}-outdir" diff --git a/examples/simple_zonal_with_asm/variables.tf b/examples/simple_zonal_with_asm/variables.tf index 8e275434c..6dd142621 100644 --- a/examples/simple_zonal_with_asm/variables.tf +++ b/examples/simple_zonal_with_asm/variables.tf @@ -47,9 +47,3 @@ variable "ip_range_pods" { variable "ip_range_services" { description = "The secondary ip range to use for services" } - -variable "service_account" { - description = "The GCP Service Account email address used to deploy ASM." - type = string - default = "" -} diff --git a/modules/asm/README.md b/modules/asm/README.md index 10100b628..2a81e42a1 100644 --- a/modules/asm/README.md +++ b/modules/asm/README.md @@ -61,9 +61,10 @@ To deploy this config: | enable\_cluster\_roles | Sets `--enable_cluster_roles` option if true. | `bool` | `false` | no | | enable\_gcp\_apis | Sets `--enable_gcp_apis` option if true. | `bool` | `false` | no | | enable\_gcp\_components | Sets --enable\_gcp\_components option if true. Can be true or false. Available versions are documented in https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages | `bool` | `false` | no | -| enable\_gcp\_iam\_roles | Sets `--enable_gcp_iam_roles` option if true. | `bool` | `false` | no | +| enable\_gcp\_iam\_roles | Grants IAM roles required for ASM if true. If enable\_gcp\_iam\_roles, one of impersonate\_service\_account, service\_account, or iam\_member must be set. | `bool` | `false` | no | | enable\_registration | Sets `--enable_registration` option if true. | `bool` | `false` | no | | gcloud\_sdk\_version | The gcloud sdk version to use. Minimum required version is 293.0.0 | `string` | `"296.0.1"` | no | +| iam\_member | The GCP member email address to grant IAM roles to. If impersonate\_service\_account or service\_account is set, roles are granted to that SA. | `string` | `""` | no | | impersonate\_service\_account | An optional service account to impersonate for gcloud commands. If this service account is not specified, the module will use Application Default Credentials. | `string` | `""` | no | | key\_file | The GCP Service Account credentials file path used to deploy ASM. | `string` | `""` | no | | location | The location (zone or region) this cluster has been created in. | `string` | n/a | yes | diff --git a/modules/asm/main.tf b/modules/asm/main.tf index 9bb9fb917..00d66694c 100644 --- a/modules/asm/main.tf +++ b/modules/asm/main.tf @@ -28,12 +28,63 @@ locals { ca_key = lookup(var.ca_certs, "ca_key", "none") root_cert = lookup(var.ca_certs, "root_cert", "none") cert_chain = lookup(var.ca_certs, "cert_chain", "none") + # https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages/blob/1cf61b679cd369f42a0e735f8e201de1a6a6433b/scripts/asm-installer/install_asm#L1970 + iam_roles = [ + "roles/container.admin", + "roles/meshconfig.admin", + "roles/gkehub.admin", + ] + # https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages/blob/1cf61b679cd369f42a0e735f8e201de1a6a6433b/scripts/asm-installer/install_asm#L1958 + mcp_iam_roles = [ + "roles/serviceusage.serviceUsageConsumer", + "roles/container.admin", + "roles/monitoring.metricWriter", + "roles/logging.logWriter", + "roles/gkehub.viewer", + "roles/gkehub.gatewayAdmin", + ] + # if enable_gcp_iam_roles is set, grant IAM roles to first non null principal in the order below + asm_iam_member = var.enable_gcp_iam_roles ? coalesce(var.impersonate_service_account, var.service_account, var.iam_member) : "" + # compute any additonal resources that ASM provisioner should depend on + additional_depends_on = concat(var.enable_gcp_apis ? [module.asm-services[0].project_id] : [], local.asm_iam_member != "" ? [for k, v in google_project_iam_member.asm_iam : v.etag] : []) +} + +resource "google_project_iam_member" "asm_iam" { + for_each = toset(local.asm_iam_member != "" ? (var.managed_control_plane ? local.mcp_iam_roles : local.iam_roles) : []) + project = var.project_id + role = each.value + member = "serviceAccount:${local.asm_iam_member}" +} + +module "asm-services" { + source = "terraform-google-modules/project-factory/google//modules/project_services" + version = "~> 10.0" + count = var.enable_gcp_apis ? 1 : 0 + + project_id = var.project_id + disable_services_on_destroy = false + disable_dependent_services = false + + # https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages/blob/1cf61b679cd369f42a0e735f8e201de1a6a6433b/scripts/asm-installer/install_asm#L2005 + activate_apis = [ + "container.googleapis.com", + "monitoring.googleapis.com", + "logging.googleapis.com", + "cloudtrace.googleapis.com", + "meshtelemetry.googleapis.com", + "meshconfig.googleapis.com", + "iamcredentials.googleapis.com", + "gkeconnect.googleapis.com", + "gkehub.googleapis.com", + "cloudresourcemanager.googleapis.com", + "stackdriver.googleapis.com", + ] } module "asm_install" { source = "terraform-google-modules/gcloud/google//modules/kubectl-wrapper" version = "~> 2.1.0" - module_depends_on = [var.cluster_endpoint] + module_depends_on = concat([var.cluster_endpoint], local.additional_depends_on) gcloud_sdk_version = var.gcloud_sdk_version upgrade = true @@ -44,6 +95,6 @@ module "asm_install" { service_account_key_file = var.service_account_key_file impersonate_service_account = var.impersonate_service_account - kubectl_create_command = "${path.module}/scripts/install_asm.sh ${var.project_id} ${var.cluster_name} ${var.location} ${var.asm_version} ${var.mode} ${var.managed_control_plane} ${var.skip_validation} ${local.options_string} ${local.custom_overlays_string} ${var.enable_all} ${var.enable_cluster_roles} ${var.enable_cluster_labels} ${var.enable_gcp_apis} ${var.enable_gcp_iam_roles} ${var.enable_gcp_components} ${var.enable_registration} ${var.outdir} ${var.ca} ${local.ca_cert} ${local.ca_key} ${local.root_cert} ${local.cert_chain} ${local.service_account_string} ${local.key_file_string} ${local.asm_git_tag_string}" + kubectl_create_command = "${path.module}/scripts/install_asm.sh ${var.project_id} ${var.cluster_name} ${var.location} ${var.asm_version} ${var.mode} ${var.managed_control_plane} ${var.skip_validation} ${local.options_string} ${local.custom_overlays_string} ${var.enable_all} ${var.enable_cluster_roles} ${var.enable_cluster_labels} ${var.enable_gcp_components} ${var.enable_registration} ${var.outdir} ${var.ca} ${local.ca_cert} ${local.ca_key} ${local.root_cert} ${local.cert_chain} ${local.service_account_string} ${local.key_file_string} ${local.asm_git_tag_string}" kubectl_destroy_command = "kubectl delete ns istio-system" } diff --git a/modules/asm/scripts/install_asm.sh b/modules/asm/scripts/install_asm.sh index b6a461a3d..b65cbafed 100755 --- a/modules/asm/scripts/install_asm.sh +++ b/modules/asm/scripts/install_asm.sh @@ -33,19 +33,17 @@ CUSTOM_OVERLAYS_LIST=$9 ENABLE_ALL=${10} ENABLE_CLUSTER_ROLES=${11} ENABLE_CLUSTER_LABELS=${12} -ENABLE_GCP_APIS=${13} -ENABLE_GCP_IAM_ROLES=${14} -ENABLE_GCP_COMPONENTS=${15} -ENABLE_REGISTRATION=${16} -OUTDIR=${17} -CA=${18} -CA_CERT=${19} -CA_KEY=${20} -ROOT_CERT=${21} -CERT_CHAIN=${22} -SERVICE_ACCOUNT=${23} -KEY_FILE=${24} -ASM_GIT_TAG=${25} +ENABLE_GCP_COMPONENTS=${13} +ENABLE_REGISTRATION=${14} +OUTDIR=${15} +CA=${16} +CA_CERT=${17} +CA_KEY=${18} +ROOT_CERT=${19} +CERT_CHAIN=${20} +SERVICE_ACCOUNT=${21} +KEY_FILE=${22} +ASM_GIT_TAG=${23} # Set SKIP_VALIDATION variable if [[ ${SKIP_VALIDATION} = "true" ]]; then @@ -86,8 +84,6 @@ echo -e "CUSTOM_OVERLAYS_COMMAND is $CUSTOM_OVERLAYS_COMMAND" echo -e "ENABLE_ALL is $ENABLE_ALL" echo -e "ENABLE_CLUSTER_ROLES is $ENABLE_CLUSTER_ROLES" echo -e "ENABLE_CLUSTER_LABELS is $ENABLE_CLUSTER_LABELS" -echo -e "ENABLE_GCP_APIS is $ENABLE_GCP_APIS" -echo -e "ENABLE_GCP_IAM_ROLES is $ENABLE_GCP_IAM_ROLES" echo -e "ENABLE_GCP_COMPONENTS is $ENABLE_GCP_COMPONENTS" echo -e "ENABLE_REGISTRATION is $ENABLE_REGISTRATION" echo -e "OUTDIR is $OUTDIR" @@ -158,18 +154,6 @@ else ENABLE_CLUSTER_LABELS_COMMAND_SNIPPET="--enable_cluster_labels" fi -if [[ "${ENABLE_GCP_APIS}" = false ]]; then - ENABLE_GCP_APIS_COMMAND_SNIPPET="" -else - ENABLE_GCP_APIS_COMMAND_SNIPPET="--enable_gcp_apis" -fi - -if [[ "${ENABLE_GCP_IAM_ROLES}" = false ]]; then - ENABLE_GCP_IAM_ROLES_COMMAND_SNIPPET="" -else - ENABLE_GCP_IAM_ROLES_COMMAND_SNIPPET="--enable_gcp_iam_roles" -fi - if [[ "${ENABLE_GCP_COMPONENTS}" = false ]]; then ENABLE_GCP_COMPONENTS_COMMAND_SNIPPET="" else @@ -196,8 +180,8 @@ else fi # Echo the command before executing -echo -e "install_asm_${ASM_VERSION} --verbose --project_id ${PROJECT_ID} --cluster_name ${CLUSTER_NAME} --cluster_location ${CLUSTER_LOCATION} --mode ${MODE} ${MCP_COMMAND_SNIPPET} ${OPTIONS_COMMAND_SNIPPET} ${CUSTOM_OVERLAYS_COMMAND_SNIPPET} ${OUTDIR_COMMAND_SNIPPET} ${ENABLE_ALL_COMMAND_SNIPPET} ${ENABLE_CLUSTER_ROLES_COMMAND_SNIPPET} ${ENABLE_CLUSTER_LABELS_COMMAND_SNIPPET} ${ENABLE_GCP_APIS_COMMAND_SNIPPET} ${ENABLE_GCP_IAM_ROLES_COMMAND_SNIPPET} ${ENABLE_GCP_COMPONENTS_COMMAND_SNIPPET} ${ENABLE_REGISTRATION_COMMAND_SNIPPET} ${CA_COMMAND_SNIPPET} ${SERVICE_ACCOUNT_COMMAND_SNIPPET} ${KEY_FILE_COMMAND_SNIPPET}" +echo -e "install_asm_${ASM_VERSION} --verbose --project_id ${PROJECT_ID} --cluster_name ${CLUSTER_NAME} --cluster_location ${CLUSTER_LOCATION} --mode ${MODE} ${MCP_COMMAND_SNIPPET} ${OPTIONS_COMMAND_SNIPPET} ${CUSTOM_OVERLAYS_COMMAND_SNIPPET} ${OUTDIR_COMMAND_SNIPPET} ${ENABLE_ALL_COMMAND_SNIPPET} ${ENABLE_CLUSTER_ROLES_COMMAND_SNIPPET} ${ENABLE_CLUSTER_LABELS_COMMAND_SNIPPET} ${ENABLE_GCP_COMPONENTS_COMMAND_SNIPPET} ${ENABLE_REGISTRATION_COMMAND_SNIPPET} ${CA_COMMAND_SNIPPET} ${SERVICE_ACCOUNT_COMMAND_SNIPPET} ${KEY_FILE_COMMAND_SNIPPET}" # run the script with appropriate flags # shellcheck disable=SC2086 -./install_asm_${ASM_VERSION} --verbose --project_id ${PROJECT_ID} --cluster_name ${CLUSTER_NAME} --cluster_location ${CLUSTER_LOCATION} --mode ${MODE} ${MCP_COMMAND_SNIPPET} ${OPTIONS_COMMAND_SNIPPET} ${CUSTOM_OVERLAYS_COMMAND_SNIPPET} ${OUTDIR_COMMAND_SNIPPET} ${ENABLE_ALL_COMMAND_SNIPPET} ${ENABLE_CLUSTER_ROLES_COMMAND_SNIPPET} ${ENABLE_CLUSTER_LABELS_COMMAND_SNIPPET} ${ENABLE_GCP_APIS_COMMAND_SNIPPET} ${ENABLE_GCP_IAM_ROLES_COMMAND_SNIPPET} ${ENABLE_GCP_COMPONENTS_COMMAND_SNIPPET} ${ENABLE_REGISTRATION_COMMAND_SNIPPET} ${CA_COMMAND_SNIPPET} ${SERVICE_ACCOUNT_COMMAND_SNIPPET} ${KEY_FILE_COMMAND_SNIPPET} +./install_asm_${ASM_VERSION} --verbose --project_id ${PROJECT_ID} --cluster_name ${CLUSTER_NAME} --cluster_location ${CLUSTER_LOCATION} --mode ${MODE} ${MCP_COMMAND_SNIPPET} ${OPTIONS_COMMAND_SNIPPET} ${CUSTOM_OVERLAYS_COMMAND_SNIPPET} ${OUTDIR_COMMAND_SNIPPET} ${ENABLE_ALL_COMMAND_SNIPPET} ${ENABLE_CLUSTER_ROLES_COMMAND_SNIPPET} ${ENABLE_CLUSTER_LABELS_COMMAND_SNIPPET} ${ENABLE_GCP_COMPONENTS_COMMAND_SNIPPET} ${ENABLE_REGISTRATION_COMMAND_SNIPPET} ${CA_COMMAND_SNIPPET} ${SERVICE_ACCOUNT_COMMAND_SNIPPET} ${KEY_FILE_COMMAND_SNIPPET} diff --git a/modules/asm/variables.tf b/modules/asm/variables.tf index 1c53e5eb6..3d878cb22 100644 --- a/modules/asm/variables.tf +++ b/modules/asm/variables.tf @@ -136,7 +136,7 @@ variable "enable_gcp_apis" { } variable "enable_gcp_iam_roles" { - description = "Sets `--enable_gcp_iam_roles` option if true." + description = "Grants IAM roles required for ASM if true. If enable_gcp_iam_roles, one of impersonate_service_account, service_account, or iam_member must be set." type = bool default = false } @@ -176,3 +176,9 @@ variable "ca_certs" { # "cert_chain" = "none" # } } + +variable "iam_member" { + description = "The GCP member email address to grant IAM roles to. If impersonate_service_account or service_account is set, roles are granted to that SA." + type = string + default = "" +} diff --git a/test/fixtures/simple_zonal_with_asm/.gitignore b/test/fixtures/simple_zonal_with_asm/.gitignore new file mode 100644 index 000000000..f78a088f6 --- /dev/null +++ b/test/fixtures/simple_zonal_with_asm/.gitignore @@ -0,0 +1,4 @@ +# asm outdir +simple-zonal-* +# install asm script +install_asm* diff --git a/test/fixtures/simple_zonal_with_asm/network.tf b/test/fixtures/simple_zonal_with_asm/network.tf index b221dae8a..22c0c9723 100644 --- a/test/fixtures/simple_zonal_with_asm/network.tf +++ b/test/fixtures/simple_zonal_with_asm/network.tf @@ -21,7 +21,7 @@ resource "random_string" "suffix" { } provider "google" { - version = "~> 3.42.0" + version = "~> 3.63.0" project = var.project_ids[2] } diff --git a/test/fixtures/simple_zonal_with_asm/variables.tf b/test/fixtures/simple_zonal_with_asm/variables.tf index 5096c09ca..a1961c0ab 100644 --- a/test/fixtures/simple_zonal_with_asm/variables.tf +++ b/test/fixtures/simple_zonal_with_asm/variables.tf @@ -30,8 +30,3 @@ variable "zones" { default = ["us-central1-a", "us-central1-b", "us-central1-c"] } -variable "service_account" { - description = "The GCP Service Account email address used to deploy ASM." - type = string - default = "" -}