레코드 세트에 대한 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 개념에 대한 기본 이해

설정

Duration: 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)가 무조건 충족되는 반면 실제 레코드 수정은 조건에 따라 엄격하게 제어됩니다.

맞춤 역할 만들기

Duration: 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: 정확한 레코드 일치

Duration: 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: 하위 도메인 위임

Duration: 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: 일괄 변경 및 거래

Duration: 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 플래그를 사용했습니다.

추가 자료