This blueprint shows how to leverage Service Directory and Cloud DNS Service Directory private zones, to implement fine-grained IAM controls on DNS by
- creating a Service Directory namespace with two services and their endpoints
- creating a Cloud DNS private zone that uses the namespace as its authoritative source
- creating two service accounts and assigning them the
roles/servicedirectory.editor
role on the namespace and on one service respectively - creating two VMs and setting 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 blueprint are shown in the high level diagram below:
A companion Medium article has been published for this blueprint, you can refer to it for more details on the context, and the specifics of running the blueprint.
Clone this repository or open it in cloud shell, 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.
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.
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.
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.
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.
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
name | description | type | required | default |
---|---|---|---|---|
project_id | Existing project id. | string |
✓ | |
name | Arbitrary string used to name created resources. | string |
"dns-sd-test" |
|
project_create | Create project instead ofusing an existing one. | bool |
false |
|
region | Compute region used in the example. | string |
"europe-west1" |
|
zone_domain | Domain name used for the DNS zone. | string |
"svc.example.org." |
name | description | sensitive |
---|---|---|
gcloud_commands | Commands used to SSH to the VMs. | |
vms | VM names. |
module "test1" {
source = "./fabric/blueprints/cloud-operations/dns-fine-grained-iam"
name = "dns-sd-test"
project_create = true
project_id = "test"
}
# tftest modules=9 resources=32