此 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
如需成功修改 DNS 记录,主账号必须有权对更改资源执行记录修改和关联操作。
您可以通过以下两种方式之一进行配置:
方法 1:标准角色方法(推荐)
您可以将 IAM 条件直接绑定到标准 roles/dns.admin 角色。为了同时支持记录修改和对更改资源的操作,您可以使用更全面的 CEL 条件来授予对所需非记录集资源的访问权限。
- 宽松:允许所有其他 DNS 管理操作。如果补充角色包含所有其他标准管理权限,则此选项等同于选项 2。
cel (resource.type == 'dns.googleapis.com/ResourceRecordSet' && <RRSET_CONDITION>) || (resource.type != 'dns.googleapis.com/ResourceRecordSet') - 限制性:仅允许对记录集进行修改和对“更改”资源执行操作。其他管理操作(包括列出记录集 [
dns.resourceRecordSets.list] 和描述代管式区域)会被阻止。cel (resource.type == 'dns.googleapis.com/ResourceRecordSet' && <RRSET_CONDITION>) || (resource.type == 'dns.googleapis.com/Change')
建议采用此方法,因为无需创建和管理自定义角色。
方法 2:自定义角色方法
如果您希望使用更简单的条件,可以使用两个自定义角色将记录集管理与其他管理任务分开:
- DnsRecordSetAdmin:包含创建、删除、获取和更新资源记录集的权限。此角色将有条件地授予。
- DnsNonRecordSetAdmin:包含所有其他 DNS 管理权限(例如管理地区、列出记录和查看项目详细信息)。系统将无条件授予此角色。
创建自定义角色
时长:05:00
[!NOTE] 仅当您使用“方法 2:自定义角色方法”时,才需要执行此步骤。如果您使用的是“选项 1:标准角色方法”,则可以跳过此步骤。
运行以下命令,在项目中创建所需的自定义角色。
定义权限集
# 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 政策
选择以下选项之一以应用相应政策。
方法 1:标准角色方法(推荐)
此选项使用具有宽松条件的标准 dns.admin 角色。
cat << EOF > policy.json
{
"bindings": [
{
"role": "roles/dns.admin",
"members": ["serviceAccount:${SA_EMAIL}"],
"condition": {
"expression": "(resource.type == 'dns.googleapis.com/ResourceRecordSet' && resource.name.endsWith('/rrsets/api.example.com./A')) || (resource.type != 'dns.googleapis.com/ResourceRecordSet')",
"title": "Exact Record Match (Standard Role)"
}
}
],
"version": 3
}
EOF
gcloud dns managed-zones set-iam-policy example-zone --policy-file=policy.json
方法 2:自定义角色方法
此选项使用您在上一步中创建的自定义角色。
cat << EOF > policy_custom.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 (Custom Roles)"
}
},
{
"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_custom.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 政策
选择以下选项之一来更新政策。
方法 1:标准角色方法(推荐)
cat << EOF > policy_subdomain.json
{
"bindings": [
{
"role": "roles/dns.admin",
"members": ["serviceAccount:${SA_EMAIL}"],
"condition": {
"expression": "(resource.type == 'dns.googleapis.com/ResourceRecordSet' && resource.name.extract('/rrsets/{name}/').endsWith('.p.example.com.')) || (resource.type != 'dns.googleapis.com/ResourceRecordSet')",
"title": "Subdomain Delegation (Standard Role)"
}
}
],
"version": 3
}
EOF
gcloud dns managed-zones set-iam-policy example-zone --policy-file=policy_subdomain.json
方法 2:自定义角色方法
cat << EOF > policy_subdomain_custom.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 (Custom Roles)"
}
},
{
"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_custom.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 (only if you created them in Option 2)
gcloud iam roles delete DnsRecordSetAdmin --project=$(gcloud config get-value project) || true
gcloud iam roles delete DnsNonRecordSetAdmin --project=$(gcloud config get-value project) || true
# Delete service account
gcloud iam service-accounts delete ${SA_EMAIL}
恭喜
恭喜!您已成功了解如何在 Cloud DNS 中实现精细的记录集级 IAM 权限。
所学内容总结
- 创建了自定义角色,以将记录集权限与区域级管理任务分开。
- 针对特定记录名称和类型实现了完全匹配条件。
- 使用 IAM 条件中的字符串提取功能实现了子网域委托。
- 使用
--skip-soa-update标志允许条件用户执行批量更改。