diff --git a/cloud-operations/asset-inventory-feed-remediation/README.md b/cloud-operations/asset-inventory-feed-remediation/README.md index bc59129bb..7309501d7 100644 --- a/cloud-operations/asset-inventory-feed-remediation/README.md +++ b/cloud-operations/asset-inventory-feed-remediation/README.md @@ -9,6 +9,8 @@ The Cloud Function can then be used for different purposes: - adapting the configuration of separate related resources - implementing remediation steps that enforce policy compliance by tweaking or reverting the changes. +A [companion Medium article](https://medium.com/google-cloud/using-cloud-asset-inventory-feeds-for-dynamic-configuration-and-policy-enforcement-c37b6a590c49) has been published for this example, refer to it for more details on the context and the specifics of running the example. + This example shows a simple remediation use case: how to enforce policies on instance tags and revert non-compliant changes in near-real time, thus adding an additional measure of control when using tags for firewall rule scoping. Changing the [monitored asset](https://cloud.google.com/asset-inventory/docs/supported-asset-types) and the function logic allows simple adaptation to other common use cases: - enforcing a centrally defined Cloud Armor policy in backend services diff --git a/cloud-operations/asset-inventory-feed-remediation/main.tf b/cloud-operations/asset-inventory-feed-remediation/main.tf index 7367269ed..2586965cc 100644 --- a/cloud-operations/asset-inventory-feed-remediation/main.tf +++ b/cloud-operations/asset-inventory-feed-remediation/main.tf @@ -20,7 +20,7 @@ locals { } module "project" { - source = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/project?ref=v2.3.0" + source = "../../modules/project" name = var.project_id project_create = false services = [ @@ -43,7 +43,7 @@ module "project" { } module "vpc" { - source = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/net-vpc?ref=v2.3.0" + source = "../../modules/net-vpc" project_id = module.project.project_id name = var.name subnets = [{ @@ -55,7 +55,7 @@ module "vpc" { } module "pubsub" { - source = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/pubsub?ref=v2.3.0" + source = "../../modules/pubsub" project_id = module.project.project_id name = var.name subscriptions = { "${var.name}-default" = null } @@ -70,14 +70,14 @@ module "pubsub" { } module "service-account" { - source = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/iam-service-accounts?ref=v2.3.0" + source = "../../modules/iam-service-accounts" project_id = module.project.project_id names = ["${var.name}-cf"] iam_project_roles = { (module.project.project_id) = [local.role_id] } } module "cf" { - source = "github.com/terraform-google-modules/cloud-foundation-fabric//modules/cloud-function?ref=v2.3.0" + source = "../../modules/cloud-function" project_id = module.project.project_id name = var.name bucket_name = "${var.name}-${random_pet.random.id}" diff --git a/cloud-operations/dns-fine-grained-iam/README.md b/cloud-operations/dns-fine-grained-iam/README.md new file mode 100644 index 000000000..3876c3496 --- /dev/null +++ b/cloud-operations/dns-fine-grained-iam/README.md @@ -0,0 +1,121 @@ +# Fine-grained Cloud DNS IAM via Service Directory + +This example shows how to leverage [Service Directory](https://cloud.google.com/blog/products/networking/introducing-service-directory) and Cloud DNS Service Directory private zones, to implement fine-grained IAM controls on DNS. + + + +This example: + +- creates a Service Directory namespace with two services and their endpoints +- creates a Cloud DNS private zone that uses the namespace as its authoritative source +- creates two service accounts and assigns them the `roles/servicedirectory.editor` role on the namespace and on one service respectively +- creates two VMs and sets them to use the two service accounts, so that DNS queries and `gcloud` commands can be used to verify the setup + +The resources created in this example are shown in the high level diagram below: + + + + +## Running the example + +Clone this repository or [open it in cloud shell](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fcloud-foundation-fabric&cloudshell_print=cloud-shell-readme.txt&cloudshell_working_dir=cloud-operations%2Fcloud-operations/dns-fine-grained-iam), then go through the following steps to create resources: + +- `terraform init` +- `terraform apply -var project_id=my-project-id` + +Once done testing, you can clean up resources by running `terraform destroy`. To persist state, check out the `backend.tf.sample` file. + +## Testing the example + +The terraform outputs generate preset `gcloud compute ssh` commands that you can copy and run in the console to connect to each VM. Remember to adapt the testing commands below if you changed the default values for the `name`, `region`, or `zone_domain` variables. + +Connect via SSH to the `ns` VM and query the Service Directory namespace via DNS. + +```bash +gcloud compute ssh dns-sd-test-ns-1 \ + --zone europe-west1-b \ + --tunnel-through-iap + +dig app1.svc.example.org +short +# 127.0.0.2 +# 127.0.0.3 +# 127.0.0.7 +dig app2.svc.example.org +short +# 127.0.0.4 +# 127.0.0.5 +dig _app1._tcp.app1.svc.example.org srv +short +# 10 10 80 vm1.app1.svc.example.org. +# 10 10 80 vm2.app1.svc.example.org. +# 10 10 80 vm3.app1.svc.example.org. +``` + +The DNS answers should match the ones in the comments above, after each command. Note the special format used to query `SRV` records. + +If the above looks good, let's verify that the `ns` VM service account has edit rights on the namespace by creating a new service, and then verifying it via DNS. + +```bash +gcloud beta service-directory services create app3 \ + --location europe-west1 \ + --namespace dns-sd-test +# Created service [app3]. + +gcloud beta service-directory endpoints create vm1 \ + --service app3 \ + --location europe-west1 \ + --namespace dns-sd-test \ + --address 127.0.0.6 \ + --port 80 +# Created endpoint [vm1]. + +dig app3.svc.example.org +short +# 127.0.0.6 +``` + +Log out from the `ns` VM and log in to the `svc` VM, then verify that its service account has no permissions on the whole namespace. + +```bash +gcloud compute ssh dns-sd-test-svc-1 \ + --zone europe-west1-b \ + --tunnel-through-iap + +gcloud beta service-directory services delete app3 \ + --location europe-west1 \ + --namespace dns-sd-test +# Deleted service [app3]. +# ERROR: (gcloud.beta.service-directory.services.delete) PERMISSION_DENIED: Permission 'servicedirectory.services.delete' denied on resource 'projects/my-project/locations/europe-west1/namespaces/dns-sd-test/services/app3'. +``` + +Ignoring the `deleted` message which is clearly a bug (the service is still in beta after all), the error message shows that this identity has no rights to operate on the namespace. What it can do is operate on the single service we gave it access to. + +```bash +gcloud beta service-directory endpoints create vm3 \ + --service app1 \ + --location europe-west1 \ + --namespace dns-sd-test \ + --address 127.0.0.7 \ + --port 80 +# Created endpoint [vm3]. + +dig app1.svc.example.org +short +# 127.0.0.2 +# 127.0.0.3 +# 127.0.0.7 +``` + + +## Variables + +| name | description | type | required | default | +|---|---|:---: |:---:|:---:| +| project_id | Existing project id. | string | ✓ | | +| *name* | Arbitrary string used to name created resources. | string | | dns-sd-test | +| *region* | Compute region used in the example. | string | | europe-west1 | +| *zone_domain* | Domain name used for the DNS zone. | string | | svc.example.org. | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| gcloud_commands | Commands used to SSH to the VMs. | | +| vms | VM names. | | + diff --git a/cloud-operations/dns-fine-grained-iam/backend.tf.sample b/cloud-operations/dns-fine-grained-iam/backend.tf.sample new file mode 100644 index 000000000..a006a2871 --- /dev/null +++ b/cloud-operations/dns-fine-grained-iam/backend.tf.sample @@ -0,0 +1,23 @@ +# 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 +# +# https://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. + +# set a valid bucket below and rename this file to backend.tf + +terraform { + backend "gcs" { + bucket = "" + prefix = "fabric/operations/service-directory-dns" + } +} + diff --git a/cloud-operations/dns-fine-grained-iam/cloud-shell-readme.txt b/cloud-operations/dns-fine-grained-iam/cloud-shell-readme.txt new file mode 100644 index 000000000..62e65af94 --- /dev/null +++ b/cloud-operations/dns-fine-grained-iam/cloud-shell-readme.txt @@ -0,0 +1,9 @@ + + +################################# Quickstart ################################# + +- terraform init +- terraform apply -var project_id=$GOOGLE_CLOUD_PROJECT + +Refer to the README.md file for more info and testing flow. + diff --git a/cloud-operations/dns-fine-grained-iam/diagram.png b/cloud-operations/dns-fine-grained-iam/diagram.png new file mode 100644 index 000000000..57d3ebb03 Binary files /dev/null and b/cloud-operations/dns-fine-grained-iam/diagram.png differ diff --git a/cloud-operations/dns-fine-grained-iam/main.tf b/cloud-operations/dns-fine-grained-iam/main.tf new file mode 100644 index 000000000..bc74864b5 --- /dev/null +++ b/cloud-operations/dns-fine-grained-iam/main.tf @@ -0,0 +1,139 @@ +/** + * 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 { + startup-script = <