diff --git a/modules/service-directory/README.md b/modules/service-directory/README.md new file mode 100644 index 00000000..ed94ef9a --- /dev/null +++ b/modules/service-directory/README.md @@ -0,0 +1,99 @@ +# Google Cloud Service Directory Module + +This module allows managing a single [Service Directory](https://cloud.google.com/service-directory) namespace, including multiple services, endpoints and IAM bindings at the namespace and service levels. + +It can be used in conjunction with the [DNS](../dns) module to create service-directory based DNS zones, offloading IAM control of `A` and `SRV` records at the namespace or service level to Service Directory. The last examples shows how to wire the two modules together. + + +## Examples + +### Namespace with IAM + +```hcl +module "service-directory" { + source = "./modules/service-directory" + project_id = "my-project + location = "europe-west1" + name = "sd-1" + iam_members = { + "roles/servicedirectory.editor" = [ + "serviceAccount:namespace-editor@example.com" + ] + } + iam_roles = [ + "roles/servicedirectory.editor" + ] +``` + +### Services with IAM and endpoints + +```hcl +module "service-directory" { + source = "./modules/service-directory" + project_id = "my-project + location = "europe-west1" + name = "sd-1" + services = { + one = { + endpoints = ["first", "second"] + metadata = null + } + } + service_iam_members = { + one = { + "roles/servicedirectory.editor" = [ + "serviceAccount:service-editor.example.com" + ] + } + } + service_iam_roles = { + one = ["roles/servicedirectory.editor"] + } + endpoint_config = { + "one/first" = { address = "127.0.0.1", port = 80, metadata = {} } + "one/second" = { address = "127.0.0.2", port = 80, metadata = {} } + } +} +``` + +### DNS based zone + +TODO + +```hcl +module "service-directory" { + source = "./modules/service-directory" + project_id = "my-project + location = "europe-west1" + name = "sd-1" +} +``` + + +## Variables + +| name | description | type | required | default | +|---|---|:---: |:---:|:---:| +| location | Namespace location. | string | ✓ | | +| name | Namespace name. | string | ✓ | | +| project_id | Project used for resources. | string | ✓ | | +| *endpoint_config* | Map of endpoint attributes, keys are in service/endpoint format. | map(object({...})) | | {} | +| *iam_members* | IAM members for each namespace role. | map(list(string)) | | {} | +| *iam_roles* | IAM roles for the namespace. | list(string) | | [] | +| *labels* | Labels. | map(string) | | {} | +| *service_iam_members* | IAM members for each service and role. | map(map(list(string))) | | {} | +| *service_iam_roles* | IAM roles for each service. | map(list(string)) | | {} | +| *services* | Service configuration, using service names as keys. | map(object({...})) | | {} | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| endpoints | Endpoint resources. | | +| id | Namespace id (short name). | | +| name | Namespace name (long name). | | +| namespace | Namespace resource. | | +| service_id | Service ids (short names). | | +| service_names | Service ids (long names). | | +| services | Service resources. | | + diff --git a/modules/service-directory/main.tf b/modules/service-directory/main.tf new file mode 100644 index 00000000..8348de44 --- /dev/null +++ b/modules/service-directory/main.tf @@ -0,0 +1,81 @@ +/** + * Copyright 2020 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 { + endpoint_list = flatten([ + for name, attrs in var.services : [ + for endpoint in attrs.endpoints : { service : name, endpoint : endpoint } + ] + ]) + endpoints = { + for ep in local.endpoint_list : "${ep.service}/${ep.endpoint}" => ep + } + iam_pairs = var.service_iam_roles == null ? [] : flatten([ + for name, roles in var.service_iam_roles : + [for role in roles : { name = name, role = role }] + ]) + iam_keypairs = { + for pair in local.iam_pairs : + "${pair.name}-${pair.role}" => pair + } + iam_members = ( + var.service_iam_members == null ? {} : var.service_iam_members + ) +} + +resource "google_service_directory_namespace" "default" { + provider = google-beta + project = var.project_id + namespace_id = var.name + location = var.location + labels = var.labels +} + +resource "google_service_directory_namespace_iam_binding" "default" { + provider = google-beta + for_each = toset(var.iam_roles) + name = google_service_directory_namespace.default.name + role = each.value + members = lookup(var.iam_members, each.value, []) +} + +resource "google_service_directory_service" "default" { + provider = google-beta + for_each = var.services + namespace = google_service_directory_namespace.default.id + service_id = each.key + metadata = each.value.metadata +} + +resource "google_service_directory_service_iam_binding" "default" { + provider = google-beta + for_each = local.iam_keypairs + name = google_service_directory_service.default[each.value.name].name + role = each.value.role + members = lookup( + lookup(local.iam_members, each.value.name, {}), each.value.role, [] + ) +} + +resource "google_service_directory_endpoint" "default" { + provider = google-beta + for_each = local.endpoints + endpoint_id = each.value.endpoint + service = google_service_directory_service.default[each.value.service].id + metadata = try(var.endpoint_config[each.key].metadata, null) + address = try(var.endpoint_config[each.key].address, null) + port = try(var.endpoint_config[each.key].port, null) +} diff --git a/modules/service-directory/outputs.tf b/modules/service-directory/outputs.tf new file mode 100644 index 00000000..0fab3996 --- /dev/null +++ b/modules/service-directory/outputs.tf @@ -0,0 +1,66 @@ +/** + * Copyright 2020 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 "endpoints" { + description = "Endpoint resources." + value = google_service_directory_endpoint.default +} + +output "id" { + description = "Namespace id (short name)." + value = google_service_directory_namespace.default.id +} + +output "name" { + description = "Namespace name (long name)." + value = google_service_directory_namespace.default.name +} + +output "namespace" { + description = "Namespace resource." + value = google_service_directory_namespace.default + depends_on = [ + google_service_directory_namespace_iam_binding.default + ] +} + +output "services" { + description = "Service resources." + value = google_service_directory_service.default + depends_on = [ + google_service_directory_service_iam_binding.default + ] +} + +output "service_id" { + description = "Service ids (short names)." + value = { + for k, v in google_service_directory_service.default : k => v.id + } + depends_on = [ + google_service_directory_service_iam_binding.default + ] +} + +output "service_names" { + description = "Service ids (long names)." + value = { + for k, v in google_service_directory_service.default : k => v.name + } + depends_on = [ + google_service_directory_service_iam_binding.default + ] +} diff --git a/modules/service-directory/variables.tf b/modules/service-directory/variables.tf new file mode 100644 index 00000000..8b921d56 --- /dev/null +++ b/modules/service-directory/variables.tf @@ -0,0 +1,80 @@ +/** + * Copyright 2020 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. + */ + +# we need a separate variable as address will be dynamic in most cases +variable "endpoint_config" { + description = "Map of endpoint attributes, keys are in service/endpoint format." + type = map(object({ + address = string + port = number + metadata = map(string) + })) + default = {} +} + +variable "iam_members" { + description = "IAM members for each namespace role." + type = map(list(string)) + default = {} +} + +variable "iam_roles" { + description = "IAM roles for the namespace." + type = list(string) + default = [] +} + +variable "labels" { + description = "Labels." + type = map(string) + default = {} +} + +variable "location" { + description = "Namespace location." + type = string +} + +variable "name" { + description = "Namespace name." + type = string +} + +variable "project_id" { + description = "Project used for resources." + type = string +} + +variable "service_iam_members" { + description = "IAM members for each service and role." + type = map(map(list(string))) + default = {} +} + +variable "service_iam_roles" { + description = "IAM roles for each service." + type = map(list(string)) + default = {} +} + +variable "services" { + description = "Service configuration, using service names as keys." + type = map(object({ + endpoints = list(string) + metadata = map(string) + })) + default = {} +} diff --git a/modules/service-directory/versions.tf b/modules/service-directory/versions.tf new file mode 100644 index 00000000..ce6918e0 --- /dev/null +++ b/modules/service-directory/versions.tf @@ -0,0 +1,19 @@ +/** + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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. + */ + +terraform { + required_version = ">= 0.12.6" +}