Cloud DNSの一般公開ゾーンのDNSクエリログを観察してみた
概要
Cloud DNSにはCloud MonitoringとCloud Loggingを利用して、DNSゾーンとDNSクエリのパフォーマンスやステータスを監視できます。これにより、DNSの動作状況をリアルタイムで把握し、問題が発生した場合に迅速に対応できます。
というようなリファレンスの説明を読んでどんなもんじゃいと気になったので実際にCloud DNSの一般公開ゾーンのLoggingを有効にしてDNSクエリのログを観察してみました。
この記事の対象者
- Cloud DNSでLoggingを有効にした場合にDNSクエリがどんな感じで出力されるのかざっくり知りたい人
やってみる
今回は一般公開のマネージドゾーンのLoggingをオンにして以下の条件で観察してみました。
- Cloud Shellからdig
- ローカルPC(Google Cloud NW外)からdig
- default VPC内のGCEインスタンスからdig
※一般公開のマネージドゾーンを作成してあることを前提にしています。作成したことがないよ、という方は以下のブログも併せてご確認ください。
お名前.comで取得したドメインをCloud DNSで管理できるようにする
それではやってみます。
準備:一般公開のマネージドゾーンでのLogging
まずは以下のコマンドでLoggingをオンにします。ゾーン作成時にLoggingをオンにしていれば不要です。
gcloud dns --project=プロジェクトID managed-zones update ゾーン名 --log-dns-queries
Updating managed zone [ゾーン名]...done.
と出力されたらオンになっています。
Cloud Shellからdig
まずはCloud Shellからdigしてみます。
dig ドメイン名
するとCloud Loggingにログが書き込まれているはずです。
ログエクスプローラで以下でログを検索します。
resource.type="dns_query"
上記のようにログが出力されていたのでみてみます。
{
"insertId": "1xzjheyepcs53",
"jsonPayload": {
"serverLatency": 0,
"structuredRdata": [
{
"rvalue": "**.**.**.**",
"type": "A",
"ttl": "300",
"class": "IN",
"domainName": "ドメイン名."
}
],
"sourceIP": "送信元IP",
"protocol": "UDP",
"responseCode": "NOERROR",
"queryType": "A",
"queryName": "ドメイン名.",
"authAnswer": true,
"dns64Translated": false,
"destinationIP": "216.239.36.*"
},
"resource": {
"type": "dns_query",
"labels": {
"target_name": "ゾーン名",
"project_id": "プロジェクトID",
"target_type": "public-zone",
"source_type": "internet",
"location": "global"
}
},
"timestamp": "2024-11-05T16:09:59.042643071Z",
"severity": "INFO",
"logName": "projects/プロジェクトID/logs/dns.googleapis.com%2Fdns_queries",
"receiveTimestamp": "2024-11-05T16:09:59.528230991Z"
}
意味をざっくりと翻訳すると以下となります。
フィールド | 説明 |
---|---|
insertId |
ログエントリの一意の識別子。このIDはログエントリが重複しないようにするために使用されます。 |
jsonPayload |
ログの内容を表すJSONオブジェクト。DNSクエリに関する詳細な情報が含まれています。 |
jsonPayload.serverLatency |
DNSサーバーの応答時間(ミリ秒)。今回の例では0ミリ秒。 |
jsonPayload.structuredRdata |
応答データの詳細を含む配列。 |
jsonPayload.structuredRdata[].rvalue |
レコードの値(IPアドレス)。 |
jsonPayload.structuredRdata[].type |
DNSレコードのタイプ。この例では「Aレコード」。 |
jsonPayload.structuredRdata[].ttl |
レコードの有効期間(Time To Live)。この例では「300秒」。 |
jsonPayload.structuredRdata[].class |
DNSクラス。通常は「IN」(インターネット)。 |
jsonPayload.structuredRdata[].domainName |
クエリされたドメイン名。マスクしています。 |
jsonPayload.sourceIP |
クエリを送信したクライアントのIPアドレス。 |
jsonPayload.protocol |
使用されたプロトコル。この例では「UDP」。 |
jsonPayload.responseCode |
DNS応答のステータスコード。「NOERROR」はエラーなしを示す。 |
jsonPayload.queryType |
クエリのタイプ。この例では「Aレコード」。 |
jsonPayload.queryName |
クエリされたドメイン名。マスクしています。 |
jsonPayload.authAnswer |
権威あるDNSサーバーからの応答かどうか。この例では「true」。 |
jsonPayload.dns64Translated |
DNS64変換が行われたかどうか。この例では「false」。 |
jsonPayload.destinationIP |
クエリが送信されたDNSサーバーのIPアドレス。この例では「216.239.36.*」。これはGoogle CloudのIPです。 |
resource |
ログエントリに関連するリソース情報。 |
resource.type |
リソースのタイプ。この例では「dns_query」。 |
resource.labels |
リソースに関連するラベル情報。 |
resource.labels.target_name |
クエリ対象のゾーン名。マスクしています。 |
resource.labels.project_id |
プロジェクトのID。マスクしています。 |
resource.labels.target_type |
クエリ対象のゾーンタイプ。この例では「public-zone」(パブリックゾーン)。 |
resource.labels.source_type |
クエリの送信元タイプ。この例では「internet」(インターネット)。 |
resource.labels.location |
リソースの場所。この例では「global」(グローバル)。 |
timestamp |
ログエントリのタイムスタンプ。この例では「2024-11-05T16:09:59.042643071Z」。 |
severity |
ログの重大度レベル。この例では「INFO」。 |
logName |
ログの名前とパス。マスクしています。 |
receiveTimestamp |
ログが受信されたタイムスタンプ。。 |
いろいろなフィールドが出ていますね。
jsonPayload.structuredRdata[].type
でA
と出ていたり(digと一致)、
jsonPayload.destinationIP
が216.239.36.*
→公開されているGoogle CloudのIPに合致。
他にもいろいろな情報が出ていますがとりあえずDNSクエリログをLoggingで見ることができました。
ローカルPC(Google Cloud NW外)からdig
ローカルPCからもdigしてみました。
ほぼ同じだったので差分だけ以下にまとました。
フィールド | 最初のログ | 最新のログ | 差分 |
---|---|---|---|
insertId |
"1xzjheyepcs53" | "152xrd3e5cwkp" | IDが異なる |
jsonPayload.sourceIP |
"..." | "..." | クエリを送信したIPアドレスが異なる。 |
jsonPayload.destinationIP |
"216.239.36.*" | "216.239.34.*" | IPアドレスが異なる |
timestamp |
"2024-11-05T16:09:59.042643071Z" | "2024-11-05T16:31:27.300364098Z" | タイムスタンプが異なる |
receiveTimestamp |
"2024-11-05T16:09:59.528230991Z" | "2024-11-05T16:31:28.735056393Z" | 受信タイムスタンプが異なる |
sourceIP
は自分のPCのIPでした。またdestinationIP
が異なっていることが確認できました。Google Cloud DNSは、複数のDNSサーバーを使用して高可用性と負荷分散を実現しているので異なるdestinationIPは、異なるDNSサーバーにクエリが送信されたからと考えられます。
default VPC内のGCEインスタンスからdig
ほぼ同じだったので今度はGCEインスタンスからTXTレコード
をクエリしてみます。
dig ドメイン名 TXT
{
"insertId": "1jteezwe1hgek",
"jsonPayload": {
"queryName": "ドメイン名.",
"dns64Translated": false,
"structuredRdata": [
{
"ttl": "60",
"type": "TXT",
"domainName": "ドメイン名.",
"class": "IN",
"rvalue": "\\# 19 1248656c6c6f20436c6f756420444e53212121"
}
],
"sourceIP": "送信元IP",
"destinationIP": "216.239.32.110",
"protocol": "UDP",
"queryType": "TXT",
"authAnswer": true,
"serverLatency": 0,
"responseCode": "NOERROR"
},
"resource": {
"type": "dns_query",
"labels": {
"project_id": "プロジェクトID",
"target_name": "ゾーン名",
"target_type": "public-zone",
"location": "global",
"source_type": "internet"
}
},
"timestamp": "2024-11-05T16:44:48.675909291Z",
"severity": "INFO",
"logName": "projects/プロジェクトID/logs/dns.googleapis.com%2Fdns_queries",
"receiveTimestamp": "2024-11-05T16:44:49.832018041Z"
}
面白そうなところをピックします。
フィールド | 説明 |
---|---|
type | クエリのタイプ。この例では「TXT」。 |
rvalue | \\# 19 1248656c6c6f20436c6f756420444e53212121 はバイナリ形式のデータです。\\# はバイナリ形式のデータが続くことを示します。19 はデータのバイト数(16進数)ですので10進数だと25バイトとなります。 |
TXTレコードをクエリした場合は当然ながらDNSクエリのタイプがTXT
になることが確認できました。
rvalue
を解読してみる。
おまけ:rvalue
の16進数データ1248656c6c6f20436c6f756420444e53212121
をASCII文字に変換してみます。
16進数 | 10進数 | ASCII文字 |
---|---|---|
12 | 18 | (制御文字) |
48 | 72 | H |
65 | 101 | e |
6c | 108 | l |
6c | 108 | l |
6f | 111 | o |
20 | 32 | (スペース) |
43 | 67 | C |
6c | 108 | l |
6f | 111 | o |
75 | 117 | u |
64 | 100 | d |
20 | 32 | (スペース) |
44 | 68 | D |
4e | 78 | N |
53 | 83 | S |
21 | 33 | ! |
21 | 33 | ! |
21 | 33 | ! |
上記よりHello Cloud DNS!!!
という文字列と判明しました。
ちなみにこの値は私がTXTレコードに設定している値なので、みなさんの環境ではまた違った値になりますのでご注意ください。
ログの観察が終わって満足しましたら以下のコマンドを打ってLoggingをオフにしておきます。
gcloud dns managed-zones update ゾーン名 --no-log-dns-queries
まとめ
今回3つのパターンを試してみましたがレコードタイプを除けば特にログに違いはありませんでした。とはいえDNSクエリログでどういった様子で出力されるかが実際に見れたのでとても良い検証でした。
限定公開ゾーンに対してのDNSクエリログは今回は試せていないので今度試してみます。
それではまた。ナマステー
参考