Cloudflare で Internal DNS を使う

# 目的

:::note info
機能の有効化については、Cloudflare アカウントチームにご相談ください。
:::

以下のように Cloudflare で Internal DNS を設定して、問題なく名前解決できることを確認します。

```mermaid:
%%{init: {'themeCSS': 'img {width: 48px; height:48px;}'}}%%
%%<img src='https://cf-icons.pages.dev/calls.svg' width='48' height='48'/><br>

graph LR

subgraph Cloudflare [<img src='https://cf-icons.pages.dev/logo-cloud.svg' width='48' height='48'/><br>]
subgraph InternalDNS [Internal DNS Zone]
kyouhei.internal[<img src='https://cf-icons.pages.dev/dns.svg' width='48' height='48'/><br>kyouhei.internal]
end
subgraph Gatewary [Gatewary DNS Resolver]
ResolverPolicy[<img src='https://cf-icons.pages.dev/gateway.svg' width='48' height='48'/><br>Resolver Policy]
end
end

Client:::hidden

Client --> |DNS Query|Gatewary

ResolverPolicy --> |view|kyouhei.internal

classDef hidden display: none;
classDef transparent fill-opacity:0,stroke-opacity:0;
%%style Cloudflare fill-opacity:0,stroke-opacity:0;
%%style TCPApp fill-opacity:0,stroke-opacity:0;
%%style Future fill:#ffd, stroke:#ccb, fill:#fff,stroke-dasharray: 5 5
```

# 参考 ： `.internal` TLD
以下のような動きを踏まえると、今後、内部 DNS の TLD には `.internal` を使用して統一できると良さそうです。

https://asnokaze.hatenablog.com/entry/2024/08/05/001307

https://jprs.jp/related-info/event/2024/IETF121-03.html

>▽プライベート利用のためのTLD（draft-davies-internal-tld）
プライベートIPアドレス[1]に相当する、組織内で使用するためのトップレベルドメイン（TLD）を定義するための提案です。提案者はIANAのKim Davies氏とICANNのAndrew McConachie氏で、会場ではKim Davies氏が発表しました。
>
>現在、通常のインターネットの利用以外に使われるドメイン名は特殊用途ドメイン名（Special-Use Domain Names）として予約されています。特殊用途ドメイン名の例として、マルチキャストDNSで使われる.local、DNS以外の手段で名前解決されることを示す.alt、家庭用ネットワークで使われる.home.arpaなどが挙げられます。
>
>本提案には2024年1月にIANAが公開した評価結果  を受け、2024年7月にICANN理事会がこのためのTLDとして「.internal」を予約したことが記述されています。
>
>WGでは「フルリゾルバーに.internalのネガティブトラストアンカー[2]を追加する必要がある」「.internalを特殊用途ドメイン名に追加すべき」「IETFでBest Current Practice（BCP）[3]のRFCとすることで重みを持たせるとよい」などのコメントがある一方、「そうしたTLDの予約はIETFではなくICANNで決定すべきだ」という声もあり、継続して作業を進めることとなりました。

# Internal DNS Zone の作成

:::note info
2025 年 2 月 5 日時点では、API 操作のみ対応しています。
:::

`"type": "internal"` として以下のコマンドで作成します。

```shell:
export EMAIL='YOUR_EMAIL'
export APIKEY='YOUR_APIKEY'
export ACCOUNT_ID='YOUR_ACCOUNT_ID'

curl https://api.cloudflare.com/client/v4/zones \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $APIKEY" \
  -d '{
    "account": {
      "id": "'$ACCOUNT_ID'"
    },
    "name": "kyouhei.internal",
    "type": "internal"
  }'
```

# DNS レコードの作成

API もしくは GUI から以下のような DNS レコードを作成します。

```shell:
export INTERNAL_ZONE_ID='YOUR_INTERNAL_ZONE_ID'

curl https://api.cloudflare.com/client/v4/zones/$INTERNAL_ZONE_ID/dns_records \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $APIKEY" \
  -d '{
      "comment": "Internal DNS",
      "content": "10.146.0.12",
      "name": "www.kyouhei.internal",
      "proxied": false,
      "tags": [
        "type:internal-dns"
      ],
      "type": "A"
    }'
```

https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/b353c6dd-ef6f-edc9-0e94-ccde0957d24a.png)


# DNS View の作成

:::note info
2025 年 2 月 5 日時点では、API 操作のみ対応しています。
:::

Resolver Policy との紐付けに必要な DNS View を以下のコマンドで作成します。

```shell:
export INTERNAL_ZONE_ID='YOUR_INTERNAL_ZONE_ID'

curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/dns_settings/views \
  -X POST \
  -H 'Content-Type: application/json' \
  -H "X-Auth-Email: $EMAIL" \
  -H "X-Auth-Key: $APIKEY" \
  -d '{
    "name": "kyouhei-internal-dns-view",
    "zones": [
      "'$INTERNAL_ZONE_ID'"
    ]
  }’
```

# Resolver Policy の作成

API もしくは GUI から以下のような Resolver Policy を作成します。

```shell:
export DNS_VIEW_ID='YOUR_DNS_VIEW_ID'

curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \     
    -H 'Content-Type: application/json' \
    -H "X-Auth-Email: $EMAIL" \
    -H "X-Auth-Key: $APIKEY" \
    -d '{
      "action": "resolve",
      "name": "kyouhei.internal",
      "description": "Internal DNS",
      "enabled": true,
      "rule_settings": {"resolve_dns_internally": {
        "fallback": "none",
        "view_id": "'$DNS_VIEW_ID'"
      }},
      "traffic": "any(dns.domains[*] in {\"kyouhei.internal\"})"
    }'
```

https://developers.cloudflare.com/cloudflare-one/policies/gateway/resolver-policies/

https://qiita.com/khayama/items/6b0c06887922ee52a072

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/9e2eb38c-c79a-3e9d-d568-034b9e04ae9b.png)


# 動作確認

https://qiita.com/khayama/items/3c3f7f6bcadb2d224a38

## DNS over IPv4

```shell:
% dig -4 @172.64.36.1 www.kyouhei.internal A +short
10.146.0.12
```

## DoH

以下のコマンドで自アカウント専用のユニークホスト名が確認できます。

```shell:
export EMAIL='YOUR_EMAIL'
export APIKEY='YOUR_APIKEY'
export ACCOUNT_ID='YOUR_ACCOUNT_ID'

MY_DOH_SUBDOMAIN=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/locations" \
-H "X-Auth-Email: $EMAIL" \
-H "X-Auth-Key: $APIKEY" \
-H "Content-Type: application/json" | jq -r '.result[] | select (.name == "Nuro") | .doh_subdomain')
echo $MY_DOH_SUBDOMAIN
```

自アカウント専用のユニークホスト名への問い合わせで内部 DNS への問い合わせが名前解決されることが確認できます。

```shell:
curl -s -H 'accept: application/dns-json' \
'https://'$MY_DOH_SUBDOMAIN'.cloudflare-gateway.com/dns-query?name=www.kyouhei.internal&type=A' | jq
```

```json:result.json
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": false,
  "CD": false,
  "Question": [
    {
      "name": "www.kyouhei.internal",
      "type": 1
    }
  ],
  "Answer": [
    {
      "name": "www.kyouhei.internal",
      "type": 1,
      "TTL": 300,
      "data": "10.146.0.12"
    }
  ]
}
```

## Proxy Endpoint

:::note info
内部 DNS に AAAA レコードがなく、 A レコードのみの場合は以下の `Force IPv4` DNS ポリシーを設定します。

- [Common DNS policies - Force IPv4 · Cloudflare Zero Trust docs](https://developers.cloudflare.com/cloudflare-one/policies/gateway/dns-policies/common-policies/#force-ipv4)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/b32788f2-c2e6-2f9f-5680-589b4885b1ad.png)
:::

Proxy Endpoint のサブドメインと、Cloudflare Zero Trust で有効なルート CA 証明書を指定して確認できます。

```shell:
curl -4 -p http://www.kyouhei.internal --proxy https://$YOUR_SUBDOMAIN.proxy.cloudflare-gateway.com --cacert certificate.pem                                    
```

```text:result.txt
Accept: */* <br />
User-Agent: curl/8.7.1 <br />
Host: www.kyouhei.internal <br />
```

## Clientless Web Isolation

:::note info
内部 DNS に AAAA レコードがなく、 A レコードのみの場合は以下の `Force IPv4` DNS ポリシーを設定します。

- [Common DNS policies - Force IPv4 · Cloudflare Zero Trust docs](https://developers.cloudflare.com/cloudflare-one/policies/gateway/dns-policies/common-policies/#force-ipv4)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/b32788f2-c2e6-2f9f-5680-589b4885b1ad.png)
:::

チーム名を指定したプレフィックスを付けることで、 Clientless Web Isolation での動作を確認できます。

```shell:
open https://$YOUR_TEAM_NAME.cloudflareaccess.com/browser/http://www.kyouhei.internal/
```

# Gateway DNS ログ

```json:gateway-dns-log.json
{
  "AccountID": "xxx",
  "ApplicationID": 0,
  "ApplicationName": "",
  "AuthoritativeNameServerIPs": [],
  "CNAMECategoryIDs": [],
  "CNAMECategoryNames": [],
  "CNAMEs": [],
  "CNAMEsReversed": [],
  "ColoCode": "NRT",
  "ColoID": 22,
  "CustomResolveDurationMs": 0,
  "CustomResolverAddress": "",
  "CustomResolverPolicyID": "92227d07-15b9-4e60-8019-4f63e9ece970",
  "CustomResolverPolicyName": "kyouhei.internal",
  "CustomResolverResponse": "unknown",
  "Datetime": "2025-02-04T16:26:04Z",
  "DeviceID": "",
  "DeviceName": "",
  "DoHSubdomain": "xxx",
  "DoTSubdomain": "",
  "DstIP": "162.159.36.5",
  "DstPort": 443,
  "EDEErrors": [],
  "Email": "",
  "InitialCategoryIDs": [],
  "InitialCategoryNames": [],
  "IsResponseCached": false,
  "Location": "xxx",
  "LocationID": "76c7ca27-5d1c-4c1b-a3b3-e841a538921f",
  "MatchedCategoryIDs": [],
  "MatchedCategoryNames": [],
  "MatchedIndicatorFeedIDs": [],
  "MatchedIndicatorFeedNames": [],
  "Policy": "",
  "PolicyID": "",
  "PolicyName": "",
  "Protocol": "https",
  "QueryCategoryIDs": [],
  "QueryCategoryNames": [],
  "QueryID": "0603e875-90b0-418e-b803-85cbb630760f",
  "QueryIndicatorFeedIDs": [],
  "QueryIndicatorFeedNames": [],
  "QueryName": "www.kyouhei.internal",
  "QueryNameReversed": "internal.kyouhei.www",
  "QuerySize": 49,
  "QueryType": 1,
  "QueryTypeName": "A",
  "RCode": 0,
  "RData": [
    {
      "type": "1",
      "data": "A3d3dwdreW91aGVpCGludGVybmFsAAABAAEAAAEsAAQKkgAM"
    }
  ],
  "ResolvedIPCategoryIDs": [],
  "ResolvedIPCategoryNames": [],
  "ResolvedIPContinentCodes": [
    ""
  ],
  "ResolvedIPCountryCodes": [
    ""
  ],
  "ResolvedIPs": [
    "10.146.0.12"
  ],
  "ResolverDecision": "allowedOnNoPolicyMatch",
  "ResourceRecords": [
    {
      "type": "1",
      "data": "A3d3dwdreW91aGVpCGludGVybmFsAAABAAEAAAEsAAQKkgAM"
    }
  ],
  "ResourceRecordsJSON": "[{\"name\":\"www.kyouhei.internal\",\"type\":\"A\",\"class\":\"IN\",\"ttl\":300,\"rdata\":\"10.146.0.12\"}]",
  "SrcIP": "x.x.x.x",
  "SrcIPContinentCode": "AS",
  "SrcIPCountryCode": "JP",
  "SrcPort": 0,
  "TimeZone": "",
  "TimeZoneInferredMethod": "noScheduleConfigured",
  "UserID": ""
}
```

# まとめ
内部 DNS を使うには、これまでも以下の選択肢がありました。

- [DNS policies を使った Override](https://developers.cloudflare.com/cloudflare-one/policies/gateway/dns-policies/#override)
- [Local Domain Fallback](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/configure-warp/route-traffic/local-domains/) か [Resolver policies](https://developers.cloudflare.com/cloudflare-one/policies/gateway/resolver-policies/) を使って、自前の [Private DNS](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/private-net/cloudflared/private-dns/) サーバーを活用

これからは Cloudflare で Internal DNS を使えることで、自前の [Private DNS](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/private-net/cloudflared/private-dns/) サーバーを維持する必要がなくなります。

Cloudflare の公開ドメインにおける管理方式と同様に操作ができるため、保守運用性に関しても優れています。

もちろん、Cloudflare の Private LB と合わせて使うことも可能です。

https://qiita.com/khayama/items/fecc4a286e3e2103f5ee

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/0f2ee987-66ea-2e5b-7a78-98d31326d529.png)


ぜひ Internal DNS サービスの活用を検討してみてください。