이 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 플래그
트랜잭션 내에서 허용된 레코드를 수정하려면 조건을 적절히 수정하여 SOA 업데이트를 허용하거나 (resource.name.endsWith('/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플래그를 사용하여 조건부 사용자가 일괄 변경을 실행하도록 허용했습니다.