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"
+}