Cloud DNS 针对记录集的精细 IAM 权限


此 Codelab 演示了如何使用 IAM 条件和自定义角色在 Cloud DNS 中为各个 DNS 记录集实现精细的访问权限控制。

简介

Cloud DNS 传统上支持在项目级和受管区域级设置 IAM 权限。这样,用户便拥有对可用区内所有记录的广泛访问权限。不过,对于大型企业而言,这并不符合“最小权限原则”。

此 Codelab 将指导您在 Cloud DNS 中配置基于记录集的 IAM 权限。借助此功能,您可以将特定子网域或记录类型的管理权限委托给单个共享受管区域内的不同团队。

学习内容

  • 如何使用 IAM 条件限制 DNS 记录管理。
  • 创建自定义角色的原因和方法。
  • 如何委托子网域和特定记录类型(例如:A、MX)。
  • 如何使用 --skip-soa-update 标志处理具有条件权限的 DNS 事务。

前提条件

  • Google 账号
  • 启用了结算功能的 Google Cloud 项目
  • 已安装并配置最新版本的 Google Cloud CLI
  • 对 DNS 和 IAM 概念有基本的了解

准备工作

时长:03:00

启用 Cloud DNS API

登录 gcloud CLI 并启用该 API。

gcloud auth login
gcloud services enable dns.googleapis.com

创建测试项目

如果您还没有准备好项目,请立即创建一个项目,并将 gcloud 配置设置为该项目,以便所有命令都以该项目为目标。

gcloud projects create my-dns-per-rrset-lab
gcloud config set project my-dns-per-rrset-lab

了解自定义角色方法

时长:02:00

您无法直接将 IAM 条件绑定到标准 roles/dns.admin 角色。您必须使用两个自定义角色将记录集管理与其他管理任务分开:

  1. DnsRecordSetAdmin:包含创建、删除、获取和更新资源记录集的权限。此角色将有条件地授予。
  2. DnsNonRecordSetAdmin:包含所有其他 DNS 管理权限(例如管理区域、列出记录和查看项目详细信息)。此角色将无条件授予。

通过拆分这些角色,您可以确保 Cloud DNS 执行的先决条件检查(例如 dns.changes.create)无条件满足,同时实际的记录修改严格受您的条件控制。

创建自定义角色

时长:05:00

运行以下命令,在项目中创建所需的自定义角色。

定义权限集

# Record set management permissions
rs_perms="dns.resourceRecordSets.create,dns.resourceRecordSets.delete,dns.resourceRecordSets.get,dns.resourceRecordSets.update"

# Complementary administrative permissions
comp_perms="compute.networks.get,compute.networks.list,dns.changes.create,dns.changes.get,dns.changes.list,dns.dnsKeys.get,dns.dnsKeys.list,dns.gkeClusters.bindDNSResponsePolicy,dns.gkeClusters.bindPrivateDNSZone,dns.managedZoneOperations.get,dns.managedZoneOperations.list,dns.managedZones.create,dns.managedZones.delete,dns.managedZones.get,dns.managedZones.getIamPolicy,dns.managedZones.list,dns.managedZones.update,dns.networks.bindDNSResponsePolicy,dns.networks.bindPrivateDNSPolicy,dns.networks.bindPrivateDNSZone,dns.networks.targetWithPeeringZone,dns.networks.useHealthSignals,dns.policies.create,dns.policies.createTagBinding,dns.policies.delete,dns.policies.deleteTagBinding,dns.policies.get,dns.policies.list,dns.policies.listEffectiveTags,dns.policies.listTagBindings,dns.policies.update,dns.projects.get,dns.resourceRecordSets.list,dns.responsePolicies.create,dns.responsePolicies.delete,dns.responsePolicies.get,dns.responsePolicies.list,dns.responsePolicies.update,dns.responsePolicyRules.create,dns.responsePolicyRules.delete,dns.responsePolicyRules.get,dns.responsePolicyRules.list,dns.responsePolicyRules.update,resourcemanager.projects.get"

在 Gcloud 中创建角色

gcloud iam roles create DnsRecordSetAdmin --project=$(gcloud config get-value project) \
    --title="DNS Record Set Admin (Conditional)" --permissions="${rs_perms}"

gcloud iam roles create DnsNonRecordSetAdmin --project=$(gcloud config get-value project) \
    --title="DNS Complimentary Admin" --permissions="${comp_perms}"

情景 1:完全匹配记录

时长:05:00

在此场景中,您希望向团队授予仅管理 api.example.com.A 记录的权限。

创建托管式可用区

gcloud dns managed-zones create example-zone \
    --description="Lab zone for per-RRSet permissions" \
    --dns-name=example.com. --visibility=private \
    --networks=default

创建测试服务账号

您将使用此服务账号来验证受限权限。

gcloud iam service-accounts create dns-restricted-sa \
    --display-name="Restricted DNS SA"

SA_EMAIL="dns-restricted-sa@$(gcloud config get-value project).iam.gserviceaccount.com"

应用有条件的 IAM 政策

无条件授予 DnsNonRecordSetAdmin,并有条件授予 DnsRecordSetAdmin

cat << EOF > policy.json
{
  "bindings": [
    {
      "role": "projects/$(gcloud config get-value project)/roles/DnsRecordSetAdmin",
      "members": ["serviceAccount:${SA_EMAIL}"],
      "condition": {
        "expression": "resource.type == 'dns.googleapis.com/ResourceRecordSet' && resource.name.endsWith('/rrsets/api.example.com./A')",
        "title": "Exact Record Match"
      }
    },
    {
      "role": "projects/$(gcloud config get-value project)/roles/DnsNonRecordSetAdmin",
      "members": ["serviceAccount:${SA_EMAIL}"]
    }
  ],
  "version": 3
}
EOF

gcloud dns managed-zones set-iam-policy example-zone --policy-file=policy.json

验证限制

尝试创建允许的记录,然后尝试创建未经授权的记录。

# ALLOWED: Create the specific A record
gcloud dns record-sets create api.example.com. --zone=example-zone --type=A --rrdatas="1.2.3.4" --ttl=300 --impersonate-service-account=${SA_EMAIL}

# DENIED: Create an unauthorized name
gcloud dns record-sets create www.example.com. --zone=example-zone --type=A --rrdatas="5.6.7.8" --ttl=300 --impersonate-service-account=${SA_EMAIL}

场景 2:子网域委派

时长:05:00

现在,我们来授予管理 p.example.com. 子网域中任何记录的权限。

更新 IAM 政策

修改条件以使用 resource.name.extract() 来匹配子网域后缀。

cat << EOF > policy_subdomain.json
{
  "bindings": [
    {
      "role": "projects/$(gcloud config get-value project)/roles/DnsRecordSetAdmin",
      "members": ["serviceAccount:${SA_EMAIL}"],
      "condition": {
        "expression": "resource.type == 'dns.googleapis.com/ResourceRecordSet' && resource.name.extract('/rrsets/{name}/').endsWith('.p.example.com.')",
        "title": "Subdomain Delegation"
      }
    },
    {
      "role": "projects/$(gcloud config get-value project)/roles/DnsNonRecordSetAdmin",
      "members": ["serviceAccount:${SA_EMAIL}"]
    }
  ],
  "version": 3
}
EOF

gcloud dns managed-zones set-iam-policy example-zone --policy-file=policy_subdomain.json

验证委托

# ALLOWED: Create any record in the subdomain
gcloud dns record-sets create test.p.example.com. --zone=example-zone --type=A --rrdatas="192.168.1.1" --ttl=300 --impersonate-service-account=${SA_EMAIL}

# DENIED: Create a record outside the subdomain
gcloud dns record-sets create news.example.com. --zone=example-zone --type=A --rrdatas="192.168.1.2" --ttl=300 --impersonate-service-account=${SA_EMAIL}

场景 3:批量更改和交易

时长:03:00

使用条件权限时,交易方面有一个重要细节需要注意。默认情况下,DNS 事务会尝试更新 SOA 记录。如果您的 IAM 条件仅允许用户管理特定记录(例如 api.example.com.),则交易会失败,因为用户无权修改 SOA 记录。

--skip-soa-update 标志

如需在交易中修改允许的记录,您应通过相应地修改条件 (resource.name.endsWith('/SOA')) 来允许 SOA 更新,或使用 --skip-soa-update 标志。

gcloud dns record-sets transaction start --zone=example-zone --skip-soa-update
gcloud dns record-sets transaction add --zone=example-zone --name="api.example.com." --type=A --ttl=300 "10.0.0.1"
gcloud dns record-sets transaction execute --zone=example-zone --impersonate-service-account=${SA_EMAIL}

注意:如果交易包含哪怕一条未经授权的记录修改,整个交易都会被拒绝。

清理

时长:01:00

删除在本实验中创建的资源,以避免产生费用。

# Delete record sets
gcloud dns record-sets delete api.example.com. --zone=example-zone --type=A
gcloud dns record-sets delete test.p.example.com. --zone=example-zone --type=A

# Delete managed zone
gcloud dns managed-zones delete example-zone

# Delete custom roles
gcloud iam roles delete DnsRecordSetAdmin --project=$(gcloud config get-value project)
gcloud iam roles delete DnsNonRecordSetAdmin --project=$(gcloud config get-value project)

# Delete service account
gcloud iam service-accounts delete ${SA_EMAIL}

恭喜

恭喜!您已成功了解如何在 Cloud DNS 中实现精细的记录集级 IAM 权限。

所学内容总结

  • 创建了自定义角色,以将记录集权限与区域级管理任务分开。
  • 针对特定记录名称和类型实现了完全匹配条件。
  • 使用 IAM 条件中的字符串提取功能实现了子网域委托
  • 使用 --skip-soa-update 标志允许条件用户执行批量更改。

深入阅读