Young Leaves

Azure DNS で子ゾーンを作成しリソースグループ単位でDNS ゾーンを分割する

パブリックに公開するDNS ゾーンについて、DNS ゾーンを他のサービスなどに管理を委任したい場合はありませんか?今回は、Azure DNS で親ゾーンのドメインを子ゾーンに関連付けし、DNS ゾーンごとに管理を分担する方法について説明します。

実施環境

Azure CLI

2.57.0

前提条件

今回Azure リソースの作成に利用するAzure CLI はAzure CloudShell からコマンドを実行したものとします。また、Azure DNS 用にレジストラから購入済みのドメインを持っているものとします。本記事ではドメイン名を「kdkwakaba.site」で関連付けるため、自身の環境に合わせたドメイン名を利用してください。

ドメイン設計について

Web サイトやアプリケーション、メールなどでドメインを利用する場合、どのようなレコードを作成するか、ドメイン、サブドメインの管理は誰が担当するのか、など様々なことを考慮する必要があります。個人のサービスや小規模の企業であればあまり気にならないかもしれませんが、ある程度の規模で何も考えずにレコードを作成すると将来的に管理や拡張が難しくなってしまいます。そこで、ドメインをDNS サーバーに関連付けて利用する前にあらかじめどのようなレコードを作成するのか、ドメインの管理は誰が担当するのか、サブドメインの管理は委任するのか、などのドメイン設計が大事となります。

ドメイン設計では一例として以下のような管理方法があります。

  • サブドメインを作成しない
  • サブドメインを作成せず、各ドメインごとに管理を委任する
  • サブドメインは作成するが、ドメインの管理は委任しない
  • サブドメインを作成し、ドメインの管理を委任する

サブドメインを作成しない

個人でWeb サイトを公開する、企業内でもコーポレートサイトとメールサーバー程度しか外部公開しない、などドメイン自体をそこまで利用しない場合、サブドメインを作成せずレコードの種類でドメインを使い分けることもあります。この場合、ドメイン管理は特定の管理者または複数の管理者が1つのドメインを管理します。最低限のドメインのみ管理するため管理工数は少なくなりますが、サブドメインを作成して拡張したいときのレコードの修正などが負担となることもあります。

サブドメインを作成せず、各ドメインごとに管理を委任する

1つの会社で複数のWeb サイトやサービスなどを公開したい、特定のドメインからサブドメインを作成せずサービス名などに合わせたドメインを利用したい、各チームごとに管理を委任したい時があります。この場合、特定の管理者が複数のドメインを管理するか各チームの管理者がそれぞれのドメインを管理します。サービスごとに合わせたドメインを利用できたり、特定の管理者への負担が少なくなる反面、各ドメインの全体が把握しにくくなるなどのデメリットもあります。

サブドメインは作成するが、ドメインの管理は委任しない

小規模の企業など1つのドメインで複数の用途に利用したい、管理は委任せず一元管理したい時があります。この場合、特定の管理者やチームが複数のサブドメインを管理します。レコード数があまり多くない場合や将来的な拡張が少ない場合は管理の負担も少なくなる反面、特定の管理者やチームへの属人化を起こす可能性もあります。

サブドメインを作成し、ドメインの管理を委任する

ある程度規模の大きい企業では、特定の部署や支店、サービスをサブドメインで分割し、それぞれに管理を委任したい場合があります。この場合、サブドメインごとに管理を委任し全体の管理は特定の管理者で管理したり、管理の委任が必要なサブドメインのみ管理を委任し、残りのサブドメインは特定の担当者で管理する方法もあります。管理を委任するため、特定の管理者への負担が少なくなりますが、細かく分割しすぎると全体の管理が複雑になる可能性もあります。

今回の構成

今回は以下の構成でAzure リソースを作成します。ゴールは子ゾーンのドメインで仮想マシン上のApache 初期ページを表示できるまでとします。

今回はリソースグループごとに子ゾーンを分割していますが、サブスクリプションごとに子ゾーンを分割することもできます。このようにリソースグループやサブスクリプションごとに子ゾーンを分割することで、Azure DNS以外のリソースへの各種権限を分けることができます。また、子ゾーンについては異なるリージョンやリソースグループにも作成できます。

変数の定義、リソースグループの作成

初めにAzure リソース作成用の変数の定義とリソースグループを作成します。

# 必要な変数を定義する
ROOT_RESOURCE_GROUP_NAME="rg-test-dev-001"
SUB1_RESOURCE_GROUP_NAME="rg-test-dev-002"
SUB2_RESOURCE_GROUP_NAME="rg-test-dev-003"
SUB1_VNET_NAME="vnet-test-dev-001"
SUB2_VNET_NAME="vnet-test-dev-002"
SUB1_SUBNET_NAME="snet-test-dev-001"
SUB2_SUBNET_NAME="snet-test-dev-002"
ROOT_DOMAIN="kdkwakaba.site"
SUB1_DOMAIN="dev.kdkwakaba.site"
SUB2_DOMAIN="global.kdkwakaba.site"
SUB1_NSG_NAME="nsg-test-dev-001"
SUB2_NSG_NAME="nsg-test-dev-002"
NSG_SSH_RULE_NAME="allow_http_port"
SUB1_PIP_NAME="pip-test-dev-001"
SUB2_PIP_NAME="pip-test-dev-002"
SUB1_NIC_NAME="vnic-test-dev-001"
SUB2_NIC_NAME="vnic-test-dev-002"
SUB1_VM_NAME="vm-test-dev-001"
SUB2_VM_NAME="vm-test-dev-002"
LOCATION_JP="japaneast"
LOCATION_US="eastus"

# リソースグループを作成する
az group create --name $ROOT_RESOURCE_GROUP_NAME -l $LOCATION_JP
az group create --name $SUB1_RESOURCE_GROUP_NAME -l $LOCATION_JP
az group create --name $SUB2_RESOURCE_GROUP_NAME -l $LOCATION_US

仮想ネットワークの作成

リソースグループ作成後、各リソースグループに仮想ネットワークを作成します。今回は仮想ネットワークごとにピアリングを確立しませんがIP アドレス帯は重複しないようにしておきます。

# 仮想ネットワークを作成する
# 各仮想ネットワークでIPアドレス帯が重複しないようにする
az network vnet create \
    --name $SUB1_VNET_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --location $LOCATION_JP \
    --address-prefix 10.10.0.0/16 \
    --subnet-name $SUB1_SUBNET_NAME \
    --subnet-prefixes 10.10.0.0/24

az network vnet create \
    --name $SUB2_VNET_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --location $LOCATION_US \
    --address-prefix 10.20.0.0/16 \
    --subnet-name $SUB2_SUBNET_NAME \
    --subnet-prefixes 10.20.0.0/24

Azure DNS の親ゾーンを作成

仮想ネットワーク作成後、親ゾーン用のAzure DNS の親ゾーンを作成します。作成時にAzure DNS のネームサーバーが表示されるため、nameServers の項目を控えておきます。

# Azure DNSの親ゾーンを作成する
az network dns zone create \
    --name $ROOT_DOMAIN \
    --resource-group $ROOT_RESOURCE_GROUP_NAME

Azure DNS 作成後、控えておいたnameServers の値をレジストラの親ゾーンに登録します。登録方法は各レジストラごとに異なりますので各レジストラのマニュアルを確認してください。また、登録後は反映まで数時間かかることがありますので登録されるまで待ちます。

Azure DNS の子ゾーンを作成

親ゾーンの作成、レジストラへの登録完了後は子ゾーンを作成します。Azure CLI では子ゾーン作成時に親ゾーンへ自動的にネームサーバーが登録されないこと、NS レコード追加時に複数のネームサーバーを登録できないことから、子ゾーンを作成後に親ゾーンへNS レコードの追加を行います(ちなみにAzure Portal から親ゾーンを指定して小ゾーンを作成すると親ゾーン側に自動で小ゾーンのNS レコードを追加してくれます)

# 親ドメインのAzure DNSのIDを取得する
ROOT_DOMAIN_ID=$(az network dns zone show --name $ROOT_DOMAIN --resource-group $ROOT_RESOURCE_GROUP_NAME --query id)

# rg-test-dev-002にAzure DNSの子ゾーンを作成し親ゾーンにNSレコードを作成する
# NSレコードを後々追加するため、nameServersの値を控えておく
# NS_SERVER_LISTには控えたnameServersの値を4つ配列として格納する
az network dns zone create \
    --name $SUB1_DOMAIN \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --parent-name $ROOT_DOMAIN_ID

az network dns record-set ns create \
    --name dev \
    --resource-group $ROOT_RESOURCE_GROUP_NAME \
    --zone-name $ROOT_DOMAIN \
    --ttl 172800

SUB1_NS_SERVER_LIST=($(az network dns zone show --name $SUB1_DOMAIN --resource-group $SUB1_RESOURCE_GROUP_NAME --query nameServers -o tsv))
for NS_SERVER_NAME in "${SUB1_NS_SERVER_LIST[@]}"
do
    az network dns record-set ns add-record \
        --zone-name $ROOT_DOMAIN \
        --resource-group $ROOT_RESOURCE_GROUP_NAME \
        --record-set-name dev \
        --nsdname $NS_SERVER_NAME \
        --ttl 172800
done

# rg-test-dev-003にAzure DNSの子ゾーンを作成し親ゾーンにNSレコードを作成する
# NSレコードを後々追加するため、nameServersの値を控えておく
# NS_SERVER_LISTには控えたnameServersの値を4つ配列として格納する
az network dns zone create \
    --name $SUB2_DOMAIN \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --parent-name $ROOT_DOMAIN_ID

az network dns record-set ns create \
    --name global \
    --resource-group $ROOT_RESOURCE_GROUP_NAME \
    --zone-name $ROOT_DOMAIN_ID \
    --ttl 172800

SUB2_NS_SERVER_LIST=($(az network dns zone show --name $SUB2_DOMAIN --resource-group $SUB2_RESOURCE_GROUP_NAME --query nameServers -o tsv))
for NS_SERVER_NAME in "${SUB2_NS_SERVER_LIST[@]}"
do
    az network dns record-set ns add-record \
        --zone-name $ROOT_DOMAIN \
        --resource-group $ROOT_RESOURCE_GROUP_NAME \
        --record-set-name global \
        --nsdname $NS_SERVER_NAME \
        --ttl 172800
done

子ゾーンのリソースグループ内に仮想マシンを作成

子ゾーンの作成完了後、子ゾーンのリソースグループ内に仮想マシンを作成します。ここで作成するAzure リソースは以下のとおりです。

  • 仮想マシン
  • 80番ポートを許可するNSG
  • パブリックIP アドレス
  • NSG、パブリックIP を関連付けるNIC
  • apache2 をインストールするカスタムデータ

初めにカスタムデータ用のcloud-init ファイルを作成します。

# apache2をインストールするcloud-initファイルを作成する
cat << EOF > cloud-init.txt
#cloud-config
package_upgrade: true
packages:
  - apache2
EOF

cloud-init 用ファイルを作成後、仮想マシンおよび関連するAzure リソースを作成します。

# 80番ポート接続用のNSGおよび許可設定を作成する
az network nsg create \
    --name $SUB1_NSG_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME

az network nsg rule create -n $NSG_SSH_RULE_NAME \
    --nsg-name  $SUB1_NSG_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --priority 100 \
    --source-address-prefixes '*' \
    --destination-port 80 \
    --access Allow \
    --protocol Tcp \
    --description "Allow ports 80."

az network nsg create \
    --name $SUB2_NSG_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME

az network nsg rule create -n $NSG_SSH_RULE_NAME \
    --nsg-name  $SUB2_NSG_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --priority 100 \
    --source-address-prefixes '*' \
    --destination-port 80 \
    --access Allow \
    --protocol Tcp \
    --description "Allow ports 80."

# パブリックIPアドレスを作成する
# DNSレコード用にパブリックIPアドレスの値は変数に格納する
az network public-ip create \
    --name $SUB1_PIP_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME
SUB1_PUBLIC_IP=$(az network public-ip show --name $SUB1_PIP_NAME --resource-group $SUB1_RESOURCE_GROUP_NAME --query ipAddress -o tsv)

az network public-ip create \
    --name $SUB2_PIP_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME
SUB2_PUBLIC_IP=$(az network public-ip show --name $SUB2_PIP_NAME --resource-group $SUB2_RESOURCE_GROUP_NAME --query ipAddress -o tsv)

# NSGとパブリックIPアドレスを関連付けるNICを作成する
az network nic create \
    --name $SUB1_NIC_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --vnet-name $SUB1_VNET_NAME\
    --subnet $SUB1_SUBNET_NAME \
    --network-security-group $SUB1_NSG_NAME \
    --public-ip-address $SUB1_PIP_NAME

az network nic create \
    --name $SUB2_NIC_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --vnet-name $SUB2_VNET_NAME\
    --subnet $SUB2_SUBNET_NAME \
    --network-security-group $SUB2_NSG_NAME \
    --public-ip-address $SUB2_PIP_NAME

# 仮想マシンを作成する
az vm create \
    --name $SUB1_VM_NAME \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --image Ubuntu2204 \
    --nics $SUB1_NIC_NAME \
    --admin-username azuretestuser \
    --generate-ssh-keys \
    --custom-data cloud-init.txt

az vm create \
    --name $SUB2_VM_NAME \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --image Ubuntu2204 \
    --nics $SUB2_NIC_NAME \
    --admin-username azuretestuser \
    --generate-ssh-keys \
    --custom-data cloud-init.txt

子ゾーンにA レコードを作成

仮想マシンを作成後、仮想マシンのパブリックIP アドレスのA レコードを作成します。IP アドレスはパブリックIP アドレス作成時に設定した変数を使用します。

# 子ゾーンにAレコードを作成する
az network dns record-set a add-record \
    --zone-name $SUB1_DOMAIN \
    --resource-group $SUB1_RESOURCE_GROUP_NAME \
    --record-set-name @ \
    --ipv4-address $SUB1_PUBLIC_IP

az network dns record-set a add-record \
    --zone-name $SUB2_DOMAIN \
    --resource-group $SUB2_RESOURCE_GROUP_NAME \
    --record-set-name @ \
    --ipv4-address $SUB2_PUBLIC_IP

動作確認

子ゾーンにA レコードを作成後、ブラウザから「http://<設定したドメイン>」でアクセスし、Ubuntu 用のApache のデフォルトページが表示されることを確認します。

リソースのクリーンアップ

動作確認後、各リソースグループを削除します。Azure リソースをそのままにしたい人はこの手順をスキップしてください。

# リソースグループを削除する
az group delete --name $ROOT_RESOURCE_GROUP_NAME
az group delete --name $SUB1_RESOURCE_GROUP_NAME
az group delete --name $SUB2_RESOURCE_GROUP_NAME

まとめ

  • DNS を利用する場合、事前にドメイン設計を行い要件に合った構成を作成する
  • Azure DNS では親ゾーンを関連付けて子ゾーンを作成できる
  • Azure CLI で子ゾーンとの関連付けを行う場合、Azure Portal と違い自動で親ゾーンにNS レコードが追加されないため別途追加する必要がある

参考資料