概要 #
Private Zoneは「指定したVPCからだけ名前解決できる」という仕組みです。ただしZoneとRecordを作っただけでは、それが本当に機能しているかわかりません。紐づけていないVPCやインターネットから引けてしまえば、Private Zoneを使う意味がなくなります。
Terraformで最小構成のPrivate ZoneとA Recordを作成します。3つの経路から実際に名前解決を試して確認します。紐づけたVPC内のVM、紐づけていない別VPCのVM、手元の端末の3つです。
Terraformの基本操作と、gcloud compute sshでのVM接続は前提としています。
Public ZoneやDNS Peeringは扱いません。Forwarding Zone、Split Horizon DNS、カスタムドメインの取得も扱いません。
検証すること #
- Private Cloud DNS ZoneをVPCへ関連付けられること
- Private ZoneへA Recordを登録できること
- 紐づけたVPC内のVMからは名前解決できること
- 紐づけていない別VPCのVMからは名前解決できないこと(Zone作成の確認とは別)
- インターネット経由(手元の端末)でも名前解決できないこと
今回の構成 #
Private ZoneはGlobalなResourceですが、名前を引けるVPCを指定します。指定していないVPCやインターネットからは見えません。それを確かめるため、検証用VMを紐づけたVPCと紐づけていない別VPCに1台ずつ作成します。
flowchart TB
User["手元の端末
(インターネット経由)"]
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
subgraph DNS["Cloud DNS(Global)"]
Zone["Managed Zone: example.internal.
visibility: private"]
Rec["A Record: app.example.internal. → 10.10.0.10"]
Zone --- Rec
end
subgraph Region["asia-northeast1"]
subgraph VPC["VPC: tf-example-dns-vpc"]
VMIn["VM: vm-in-zone"]
end
subgraph ExtVPC["VPC: tf-example-dns-external-vpc"]
VMOut["VM: vm-outside-zone"]
end
end
end
end
Zone -.->|"公開先として指定"| VPC
点線が公開範囲の指定です。tf-example-dns-external-vpcは指定されていません。実際に3つの経路で問い合わせると、次のようになります。
sequenceDiagram
participant VMIn as VM(紐づくVPC)
participant VMOut as VM(別VPC)
participant Local as 手元の端末
participant DNS as Private Zone
VMIn->>DNS: getent hosts app.example.internal.
DNS-->>VMIn: 10.10.0.10
VMOut->>DNS: getent hosts app.example.internal.
DNS--xVMOut: 解決できない
Local->>DNS: getent hosts app.example.internal.
DNS--xLocal: 解決できない
前提環境 #
- Google Cloud CLIとApplication Default Credentials(ADC)
- Terraform 1.10以降
- Cloud DNSとVPC、Compute Engineを操作できる検証用Google Cloud Project
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0
使用するTerraformコード #
Private Managed Zone #
resource "google_dns_managed_zone" "private" {
name = var.managed_zone_name
dns_name = var.dns_name
visibility = "private"
private_visibility_config {
networks {
network_url = google_compute_network.dns.id
}
}
}
visibility = "private"とし、private_visibility_configで参照を許可するVPC(tf-example-dns-vpc)を指定します。このZoneはPublic Internetから名前解決できません。
DNS suffixは末尾のDotを含む完全修飾形式で指定します。
variable "dns_name" {
default = "example.internal."
validation {
condition = endswith(var.dns_name, ".")
error_message = "dns_name must end with a dot."
}
}
A Record #
locals {
record_fqdn = "${var.record_name}.${var.dns_name}"
}
resource "google_dns_record_set" "example" {
name = local.record_fqdn
managed_zone = google_dns_managed_zone.private.name
type = "A"
ttl = var.record_ttl
rrdatas = [var.record_ip]
}
デフォルトではapp.example.internal.を10.10.0.10へ対応付け、TTLを300秒にします。このIPに対応する実体は無く、名前解決の確認だけが目的です。
検証用VM #
resource "google_compute_instance" "vm_in_zone" {
name = var.vm_in_zone_name
machine_type = var.machine_type
zone = var.zone
tags = ["iap-ssh"]
network_interface {
subnetwork = google_compute_subnetwork.dns.id
}
scheduling {
provisioning_model = "SPOT"
preemptible = true
automatic_restart = false
}
}
Zoneに紐づけたVPCへ1台、紐づけていない別VPCへ1台、同じ設定でVMを作成します。どちらも外部IPを持たず、IAP経由でのみSSHします。設定はBasic-Examples/04-compute-engineと同じです。
設定と実行 #
cd Basic-Examples/08-cloud-dns
cp terraform.tfvars.example terraform.tfvars
project_id = "your-project-id"
dns_name = "example.internal."
record_ip = "10.10.0.10"
terraform init
terraform fmt -check
terraform validate
terraform plan
terraform apply
VPC・Subnet・Firewallに加え、Zone・Record・VM2台が作成されます。合わせて12リソースです。
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
Outputs:
dns_name = "example.internal."
managed_zone_name = "tf-example-private-zone"
record_fqdn = "app.example.internal."
record_ip = "10.10.0.10"
vm_in_zone_name = "tf-example-dns-vm-in-zone"
vm_outside_zone_name = "tf-example-dns-vm-outside-zone"
zone = "asia-northeast1-a"
GCP側で確認する #
gcloud dns managed-zones describe \
"$(terraform output -raw managed_zone_name)" \
--project=YOUR_PROJECT_ID
dnsName: example.internal.
name: tf-example-private-zone
privateVisibilityConfig:
networks:
- networkUrl: .../networks/tf-example-dns-vpc
visibility: private
gcloud dns record-sets list \
--zone="$(terraform output -raw managed_zone_name)" \
--name="$(terraform output -raw record_fqdn)" \
--project=YOUR_PROJECT_ID
NAME TYPE TTL DATA
app.example.internal. A 300 10.10.0.10
ZoneとRecordが存在することまでは確認できました。ただし、これは実際に名前解決できることを意味しません。
名前解決を実際に確認する #
3つの経路で試します。
1. 紐づけたVPC内のVMから
gcloud compute ssh "$(terraform output -raw vm_in_zone_name)" \
--zone="$(terraform output -raw zone)" \
--tunnel-through-iap \
--project=YOUR_PROJECT_ID \
--command="getent hosts $(terraform output -raw record_fqdn)"
10.10.0.10 app.example.internal
解決できました。
2. 紐づけていない別VPCのVMから
gcloud compute ssh "$(terraform output -raw vm_outside_zone_name)" \
--zone="$(terraform output -raw zone)" \
--tunnel-through-iap \
--project=YOUR_PROJECT_ID \
--command="getent hosts $(terraform output -raw record_fqdn)"
出力なしで終了コード2(見つからない)でした。同じProject内でも、Zoneに紐づけていないVPCからは解決できません。
3. 手元の端末から(インターネット経由)
getent hosts app.example.internal.
こちらも出力なしで終了コード2でした。この「引けない」ことの確認が重要です。 Private Zoneを使う理由がそこにあるためです。
後片付けと注意点 #
terraform destroy
Destroy complete! Resources: 12 destroyed.
VMが2台起動したままだと課金が続きます。必ずdestroyしてください。 Private Zoneで使うDomain名が既存の社内DNSと競合しないよう注意します。
まとめ #
- VPCに限定したPrivate DNS Zoneを作成できる
- FQDN末尾のDotをValidationできる
- A Record、TTL、Private IPをTerraformで管理できる
- Zoneに紐づけたVPCからは名前解決でき、紐づけていないVPCやインターネットからは解決できないことを実際に確認できる
参考資料 #
次回 #
次はSecret ManagerへSecretとSecret Versionを作成します。