IPv6 専用 VM インスタンスを作成して NAT64/DNS64 を有効にする

1. はじめに

IPv6 への移行における主な課題の 1 つは、IPv4 のみのエンドポイントとネットワークへの到達可能性を維持することです。この課題に対処する主要な技術は、DNS64(RFC6147 で定義)を使用してクライアントの A レコードを AAAA レコードに変換し、NAT64(RFC6146 で定義)を使用して特別な形式の IPv6 アドレスを IPv4 に変換することです。この場合、IPv4 アドレスは特別な IPv6 アドレスに埋め込まれます。この Codelab では、Google Cloud Platform(GCP)の Virtual Private Cloud(VPC)で両方の機能を構成する方法について説明します。GCP NAT64 と DNS64 を一緒に構成すると、IPv6 専用インスタンスがインターネット上の IPv4 専用サーバーと通信できるようになります。

このラボでは、IPv6 のみの GUA(グローバル ユニキャスト アドレス)、IPv6 のみの ULA(一意のローカル アドレス)、デュアルスタック ULA など、さまざまなタイプの IPv6 サブネットとインスタンスを使用して VPC を設定します。次に、Google Cloud のマネージド DNS64 サービスと NAT64 サービスを構成してテストし、それらから IPv4 専用のウェブサイトにアクセスできるようにします。

2. 学習内容

  • IPv6 専用のサブネットとインスタンスを作成する方法
  • VPC で Google Cloud のマネージド DNS64 サービスを有効にする方法。
  • NAT64 用に構成された Google Cloud NAT ゲートウェイを作成する方法。
  • IPv6 専用インスタンスから IPv4 専用宛先への DNS64 解決をテストする方法。
  • シングルスタック インスタンスとデュアルスタック インスタンスで DNS64 と NAT64 の動作がどのように異なるか。
  • NAT64 用に NAT ゲートウェイを構成する方法。
  • IPv6 専用インスタンスから IPv4 専用宛先への NAT64 接続をテストする方法。

3. 始める前に

コードラボをサポートするようにプロジェクトを更新する

この Codelab では、$変数を使用して、Cloud Shell での gcloud 構成の実装を支援します。

Cloud Shell で、次の操作を行います。

gcloud config list project
gcloud config set project [YOUR-PROJECT-ID]
export projectname=$(gcloud config list --format="value(core.project)")
export zonename=[COMPUTE ZONE NAME]
export regionname=[REGION NAME]

ラボの全体的なアーキテクチャ

63e4293e033da8d3.png

NAT64 と DNS64 がさまざまな IPv6 サブネット タイプとどのように連携するかを示すため、GUA と ULA の両方のフレーバーで IPv6 サブネットを含む単一の VPC を作成します。また、デュアルスタック サブネット(ULA アドレス指定を使用)を作成して、DNS64 と NAT64 がデュアルスタック VM に適用されないことを示します。

次に、DNS64 と NAT64 を構成し、インターネット上の IPv6 宛先と IPv4 宛先への接続をテストします。

4. 準備手順

まず、Google Cloud プロジェクトで必要なサービス アカウント、IAM、ネットワーク インフラストラクチャ、インスタンスを設定します。

サービス アカウントと IAM バインディングを作成する

まず、インスタンスが gcloud を使用して相互に SSH 接続できるように、新しいサービス アカウントを作成します。GUA IPv6 専用インスタンスにアクセスするために IAP を使用することはできず、cloudshell ではまだ IPv6 への直接アクセスが許可されていないため、この機能が必要になります。Cloud Shell で次のコマンドを実行します。

gcloud iam service-accounts create ipv6-codelab \
     --description="temporary service account for a codelab" \
     --display-name="ipv6codelabSA" \
     --project $projectname

gcloud projects add-iam-policy-binding  $projectname \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/compute.instanceAdmin.v1

gcloud iam service-accounts add-iam-policy-binding \
    ipv6-codelab@$projectname.iam.gserviceaccount.com \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/iam.serviceAccountUser

VPC を作成して ULA を有効にする

cloudshell で次のコマンドを実行して、カスタム サブネット モードと ULA 内部 IPv6 が有効になっている VPC ネットワークを作成します。

gcloud compute networks create ipv6-only-vpc \
--project=$projectname \
--subnet-mode=custom \
--mtu=1500 --bgp-routing-mode=global \
--enable-ula-internal-ipv6

ファイアウォール ルールの作成

SSH アクセスを許可するファイアウォール ルールを作成します。1 つのルールでは、ULA 範囲全体(fd20::/20)からの SSH が許可されます。さらに 2 つのルールにより、IAP の事前定義された IPv6 範囲と IPv4 範囲(それぞれ 2600:2d00:1:7::/64、35.235.240.0/20)からのトラフィックが許可されます。

Cloud Shell で次のコマンドを実行します。

gcloud compute firewall-rules create allow-v6-ssh-ula \
--direction=INGRESS --priority=200 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp:22 --source-ranges=fd20::/20 \
--project=$projectname 

gcloud compute firewall-rules create allow-v6-iap \
--direction=INGRESS --priority=300 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp --source-ranges=2600:2d00:1:7::/64 \
--project=$projectname 

gcloud compute firewall-rules create allow-v4-iap \
--direction=INGRESS --priority=300 \
--network=ipv6-only-vpc --action=ALLOW \
--rules=tcp --source-ranges=35.235.240.0/20 \
--project=$projectname 

サブネットを作成する

GUA v6 専用サブネット、ULA v6 専用サブネット、デュアルスタック ULA サブネットを作成します。Cloud Shell で次のコマンドを実行します。

gcloud compute networks subnets create gua-v6only-subnet \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV6_ONLY \
--ipv6-access-type=external \
--region=$regionname 

gcloud compute networks subnets create ula-v6only-subnet  \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV6_ONLY \
--ipv6-access-type=internal \
--enable-private-ip-google-access \
--region=$regionname

gcloud compute networks subnets create ula-dualstack-subnet  \
--network=ipv6-only-vpc \
--project=$projectname \
--stack-type=IPV4_IPV6 \
--range=10.120.0.0/16 \
--ipv6-access-type=internal \
--region=$regionname 

インスタンスの作成

作成した各サブネットにインスタンスを作成します。IPv6 のみの ULA インスタンスは、GUA IPv6 のみのインスタンスへのジャンプボックスとして使用できるように、cloud-platform で指定されています。Cloud Shell で次のコマンドを実行します。

gcloud compute instances create gua-instance \
--subnet gua-v6only-subnet \
--stack-type IPV6_ONLY \
--zone $zonename \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--service-account=ipv6-codelab@$projectname.iam.gserviceaccount.com \
--project=$projectname

gcloud compute instances create ula-instance \
--subnet ula-v6only-subnet \
--stack-type IPV6_ONLY \
--zone $zonename \
--scopes=https://www.googleapis.com/auth/cloud-platform \
--service-account=ipv6-codelab@$projectname.iam.gserviceaccount.com \
--project=$projectname

gcloud compute instances create dualstack-ula-instance \
--subnet ula-dualstack-subnet \
--stack-type IPV4_IPV6 \
--zone $zonename \
--project=$projectname

最初のインスタンスのアクセスと設定

デフォルトで IAP を使用する ULA インスタンスに SSH 接続します。cloudshell で次のコマンドを使用して、ULA インスタンスに SSH 接続します。

gcloud compute ssh ula-instance --project $projectname --zone $zonename

<username>@ula-instance:~$ 

また、ULA インスタンスは GUA インスタンスのジャンプボックスとしても使用します(IAP は GUA インスタンスでは機能せず、Cloudshell VM は IPv6 の宛先にアクセスできないため)。

ULA インスタンス シェル内。次の gcloud コマンドを使用して、GUA インスタンスへの SSH 接続を試みます。

インスタンス内で SSH コマンドを初めて実行すると、SSH 認証鍵ペアの設定を求めるプロンプトが表示されます。鍵が作成され、SSH コマンドが実行されるまで Enter キーを押し続けます。これにより、パスフレーズなしで新しい鍵ペアが作成されます。

ula-instance:~$ gcloud compute ssh gua-instance

WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
Generating public/private rsa key pair.

Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/galhabian/.ssh/google_compute_engine
Your public key has been saved in /home/galhabian/.ssh/google_compute_engine.pub
The key fingerprint is:
SHA256:5PYzydjcpWYiFtzetYCBI6vmy9dqyLsxgDORkB9ynqY galhabian@ula-instance
The key's randomart image is:
+---[RSA 3072]----+
|..               |
|+.o      .       |
|o= o  . + .      |
| o=    * o o     |
|+o.   . S o . o  |
|Eo . . . O + = . |
|   .=. .+ @ * .  |
|   +ooo... *     |
|    **..         |
+----[SHA256]-----+

成功すると、SSH コマンドが成功し、GUA インスタンスに SSH 接続されます。

Updating instance ssh metadata...done.                                                                                                                                                                                                                                                                                            
Waiting for SSH key to propagate.
Warning: Permanently added 'compute.3639038240056074485' (ED25519) to the list of known hosts.
Linux gua-instance 6.1.0-34-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.135-1 (2025-04-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

<username>@gua-instance:~$ 

5. IPv6 専用インスタンスを調べます。

IPv6 専用インスタンスに SSH 接続し、ルーティング テーブルを調べてみましょう。

GUA インスタンスを調べる

まず「ula-instance」インスタンスを経由して「gua-instance」に SSH 接続します。

gcloud compute ssh ula-instance --project $projectname --zone $zonename
<username>@ula-instance:~$ gcloud compute ssh gua-instance

次のコマンドを使用して、インスタンスの IPv6 ルーティング テーブルを見てみましょう。

<username>@gua-instance:~$ ip -6 route

2600:1900:4041:461::/65 via fe80::56:11ff:fef9:88c1 dev ens4 proto ra metric 100 expires 81sec pref medium
fe80::/64 dev ens4 proto kernel metric 256 pref medium
default via fe80::56:11ff:fef9:88c1 dev ens4 proto ra metric 100 expires 81sec mtu 1500 pref medium

ルーティング テーブルに 3 つのエントリがあります。

  1. インスタンスが属する GUA サブネットの /65 ルート。デフォルト ゲートウェイのリンクローカル アドレスを使用して派生したネクストホップ。上位 /65 は IPv6 パススルー ネットワーク ロードバランサ用に予約されています。
  2. リンクローカル ユニキャスト プレフィックス fe80::/64 の組み込み /64 ルート
  3. サブネットのデフォルト ゲートウェイのリンクローカル アドレスを指すデフォルト ルート。

次のコマンドを実行して、IPv4 ルーティング テーブルを見てみましょう。

<username>@gua-instance:~$ ip -4 route

default via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100 
169.254.1.1 dev ens4 proto dhcp scope link src 169.254.1.2 metric 100 
169.254.169.254 via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100

驚きましたか?実際、IPv6 専用インスタンスでは、Compute メタデータ サーバー (169.254.169.154)へのアクセスを厳密に許可するために、IPv4 ルーティング テーブルが維持されています。これは、このサーバーがまだ IPv4 専用のエンドポイントであるためです。

インスタンスが IPv6 専用インスタンスの場合、IP 169.254.1.2 を取得するためです。この IP は Compute Metadata サーバー以外にはルーティングできないため、インスタンスは事実上すべての IPv4 ネットワークから分離されます。

Curl テスト

curl を使用して、v4 専用ウェブサイトと v6 専用ウェブサイトへの実際の接続をテストしてみましょう。

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
<username>@gua-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app

以下は出力例です。

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
*   Trying [2600:9000:20be:cc00:9:ec55:a1c0:93a1]:80...
* Connected to v6.ipv6test.app (2600:9000:20be:cc00:9:ec55:a1c0:93a1) port 80 (#0)
> GET / HTTP/1.1
> Host: v6.ipv6test.app
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
!! Rest of output truncated

<username>@gua-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app
*   Trying 3.163.165.4:80...
* ipv4 connect timeout after 4985ms, move on!
*   Trying 3.163.165.50:80...
* ipv4 connect timeout after 2492ms, move on!
*   Trying 3.163.165.127:80...
* ipv4 connect timeout after 1246ms, move on!
*   Trying 3.163.165.37:80...
* ipv4 connect timeout after 1245ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached

想定どおり、IPv6 専用インスタンスから IPv4 インターネット エンドポイントへの到達可能性はありません。DNS64 と NAT64 をプロビジョニングしないと、IPv6 専用インスタンスには IPv4 の宛先へのパスがありません。インスタンスには GUA IPv6 アドレスがあるため、IPv6 宛先への到達可能性は正常に機能します。

ULA インスタンスを調べる

「ula-instance」インスタンスに SSH 接続します(デフォルトで IAP を使用します)。

gcloud compute ssh ula-instance --project $projectname --zone $zonename

次のコマンドを使用して、インスタンスの IPv6 ルーティング テーブルを見てみましょう。

<username>@ula-instance:~$ ip -6 route

fd20:f06:2e5e:2000::/64 via fe80::55:82ff:fe6b:1d7 dev ens4 proto ra metric 100 expires 84sec pref medium
fe80::/64 dev ens4 proto kernel metric 256 pref medium
default via fe80::55:82ff:fe6b:1d7 dev ens4 proto ra metric 100 expires 84sec mtu 1500 pref medium

GUA インスタンスと同様に、ルーティング テーブルに 3 つのエントリがあります。ただし、マスクは /65 ではなく /64 です。サブネット ルートが ULA 範囲に属している。(fd20::/20 集計の下)

次のコマンドを実行して、IPv4 ルーティング テーブルを見てみましょう。

<username>@ula-instance:~$ ip -4 route

default via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100 
169.254.1.1 dev ens4 proto dhcp scope link src 169.254.1.2 metric 100 
169.254.169.254 via 169.254.1.1 dev ens4 proto dhcp src 169.254.1.2 metric 100

GUA インスタンスと同様の状況を示しています。

Curl テスト

curl を使用して、IPv4 専用ウェブサイトと IPv6 専用ウェブサイトへの接続テストを繰り返します。

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
<username>@ula-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app

以下は出力例です。

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v6.ipv6test.app
*   Trying [2600:9000:20be:8400:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 4986ms, move on!
*   Trying [2600:9000:20be:9000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2493ms, move on!
*   Trying [2600:9000:20be:d600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 1246ms, move on!
*   Trying [2600:9000:20be:b000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 622ms, move on!
*   Trying [2600:9000:20be:7200:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 312ms, move on!
*   Trying [2600:9000:20be:8600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 155ms, move on!
*   Trying [2600:9000:20be:7a00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 77ms, move on!
*   Trying [2600:9000:20be:ce00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 77ms, move on!
* Failed to connect to v6.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0

<username>@ula-instance:~$ curl -vv --connect-timeout 10 v4.ipv6test.app
*   Trying 3.163.165.4:80...
* ipv4 connect timeout after 4985ms, move on!
*   Trying 3.163.165.50:80...
* ipv4 connect timeout after 2492ms, move on!
*   Trying 3.163.165.127:80...
* ipv4 connect timeout after 1246ms, move on!
*   Trying 3.163.165.37:80...
* ipv4 connect timeout after 1245ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10000 ms: Timeout was reached

ULA インスタンスの場合、IPv6 エンドポイントでは ULA アドレスを使用して外部と通信できず、インスタンスは IPv6 専用インスタンスとして IPv4 に到達できないため、両方のインターネット エンドポイントに到達できません。

6. NAT64 と DNS64 を有効にする

VPC 用にマネージド DNS64 サービスと NAT64 サービスを構成します。

DNS64

VPC の DNS64 サーバー ポリシーを有効にします。これにより、VPC の DNS リゾルバは A 専用のレスポンスに対して AAAA レコードを合成します。Cloud Shell で次のコマンドを実行します。

gcloud beta dns policies create allow-dns64 \
    --description="Enable DNS64 Policy" \
    --networks=ipv6-only-vpc \
    --enable-dns64-all-queries \
    --project $projectname

NAT64

Cloud NAT に必要な Cloud Router を作成します。次に、NAT64 用に構成された Cloud NAT ゲートウェイを作成し、すべての IPv6 のみのサブネット IP 範囲で有効にして、外部 IP を自動的に割り振ります。Cloud Shell で次のコマンドを実行します。

gcloud compute routers create nat64-router \
--network=ipv6-only-vpc \
--region=$regionname \
--project=$projectname


gcloud beta compute routers nats create nat64-natgw \
--router=nat64-router \
--region=$regionname \
--auto-allocate-nat-external-ips \
--nat64-all-v6-subnet-ip-ranges \
--project=$projectname
 

7. NAT64 と DNS64 をテストする

次に、IPv6 専用インスタンスから NAT64 と DNS64 の構成をテストします。まず GUA インスタンスからテストし、次に ULA インスタンスをテストします。

GUA インスタンスからの DNS64/NAT64 のテスト

まず「ula-instance」インスタンスを経由して「gua-instance」に SSH 接続します。

gcloud compute ssh ula-instance --project $projectname --zone $zonename
<username>@ula-instance:~$ gcloud compute ssh gua-instance

DNS テスト

IPv6 のみのウェブサイト(v6.ipv6test.app(IPv6 のみのウェブサイトであれば、同様の結果が得られます)。

<username>@gua-instance:~$ host -t AAAA v6.ipv6test.app
<username>@gua-instance:~$ host -t A v6.ipv6test.app

IPv6 AAAA 応答のみが返されることが想定されます。

出力例

<username>@gua-instance:~$ host -t AAAA v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:1000:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:6600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:3e00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:9c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1400:9:ec55:a1c0:93a1

<username>@gua-instance:~$ host -t A v6.ipv6test.app
v6.ipv6test.app has no A record

IPv4 専用ウェブサイト(v4.ipv6test.app など)の DNS 解決をテストします。A レコード(元の IPv4)と、既知のプレフィックス 64:ff9b::/96 を使用して DNS64 によって合成された AAAA レコードの両方が返されることが想定されます。

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
<username>@gua-instance:~$ host -t A v4.ipv6test.app

出力例

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3318
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3344
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:333c
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3326

<username>@gua-instance:~$ host -t A v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.60
v4.ipv6test.app has address 54.192.51.38

上記の例では、10 進数の IPv4 アドレス(54.192.51.38)は 16 進数の(36 c0 33 26)に変換されるため、AAAA レコードの回答は(64:ff9b::36c0:3326)になると予想されます。これは、受け取った AAAA 回答の 1 つと一致します。

Curl テスト

IPv6 経由で curl を使用して、同じ v4 のみと v6 のみのエンドポイントへの実際の接続をテストしてみましょう。

<username>@gua-instance:~$ curl -vv -6 v6.ipv6test.app

<username>@gua-instance:~$ curl -vv -6 v4.ipv6test.app

以下は出力例です。

<username>@gua-instance:~$ curl -vv -6 v6.ipv6test.app
*   Trying [2600:9000:269f:1000:9:ec55:a1c0:93a1]:80...
* Connected to v6.ipv6test.app (2600:9000:269f:1000:9:ec55:a1c0:93a1) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

<username>@gua-instance:~$ curl -vv -6 v4.ipv6test.app
*   Trying [64:ff9b::36c0:333c]:80...
* Connected to v4.ipv6test.app (64:ff9b::36c0:333c) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

両方の curl コマンドが成功します。IPv6 経由で IPv4 専用のウェブサイトに接続できたのは、NAT64 と DNS64 が連携して接続を成功させたためです。

送信元 IP を確認する

IP リフレクション サービスを使用して、宛先で観測された送信元 IP を確認してみましょう。

<username>@gua-instance:~$ curl -6 v4.ipv6test.app

<username>@gua-instance:~$ curl -6 v6.ipv6test.app

出力例

<username>@gua-instance:~$ curl -6 v4.ipv6test.app
34.47.60.91

<username>@gua-instance:~$ curl -6 v6.ipv6test.app
2600:1900:40e0:6f:0:1::

報告された IPv6 アドレスは、インスタンスの IPv6 アドレスと一致する必要があります。このアドレスは、インスタンスの「ip -6 address」コマンドの出力と一致する必要があります。例

<username>@gua-instance:~$ ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2600:1900:40e0:6f:0:1::/128 scope global dynamic noprefixroute
       valid_lft 79912sec preferred_lft 79912sec
    inet6 fe80::86:d9ff:fe34:27ed/64 scope link
       valid_lft forever preferred_lft forever

ただし、報告される IPv4 アドレスは、インターネットに送信する前に NAT64 関数を実行するため、Cloud NAT ゲートウェイの外部 IP アドレスと一致する必要があります。これは、cloudshell で次の gcloud コマンドを実行して確認できます。

gcloud compute routers get-nat-ip-info \
       nat64-router \
       --region=$regionname

出力例

result:
- natIpInfoMappings:
  - mode: AUTO
    natIp: 34.47.60.91
    usage: IN_USE
  natName: nat64-natgw

出力で報告された「natIp」は、IP リフレクション ウェブサイトから受け取った出力と一致します。

ULA インスタンスからの DNS64/NAT64 のテスト

まず、ULA インスタンス「ula-instance」に SSH 接続します。

gcloud compute ssh ula-instance --project $projectname --zone $zonename

<username>@ula-instance:~$

DNS テスト

IPv6 のみのウェブサイト(v6.ipv6test.app(IPv6 のみのウェブサイトであれば、同様の結果が得られます)。

<username>@ula-instance:~$ host -t AAAA v6.ipv6test.app
<username>@ula-instance:~$ host -t A v6.ipv6test.app

IPv6 AAAA 応答のみが返されることが想定されます。

出力例

<username>@ula-instance:~$ host -t AAAA v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:1000:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:6600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:3e00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:9c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:b200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a600:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1400:9:ec55:a1c0:93a1

<username>@ula-instance:~$ host -t A v6.ipv6test.app
v6.ipv6test.app has no A record

IPv4 専用ウェブサイト(v4.ipv6test.app など)の DNS 解決をテストします。A レコード(元の IPv4)と、既知のプレフィックス 64:ff9b::/96 を使用して DNS64 によって合成された AAAA レコードの両方が返されることが想定されます。

<username>@ula-instance:~$ host -t AAAA v4.ipv6test.app
<username>@ula-instance:~$ host -t A v4.ipv6test.app

出力例

<username>@gua-instance:~$ host -t AAAA v4.ipv6test.app
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3318
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3344
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:333c
v4.ipv6test.app has IPv6 address 64:ff9b::36c0:3326

<username>@gua-instance:~$ host -t A v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.60
v4.ipv6test.app has address 54.192.51.38

上記の例では、10 進数の IPv4 アドレス(54.192.51.38)は 16 進数の(36 c0 33 26)に変換されるため、AAAA レコードの回答は(64:ff9b::36c0:3326)になると予想されます。これは、受け取った AAAA 回答の 1 つと一致します。

Curl テスト

curl を使用して、同じ v4 専用エンドポイントと v6 専用エンドポイントへの実際の接続をテストしてみましょう。

まず、インスタンスが IPv6 専用インスタンスであるため、IPv4 経由で到達できないことを示します。

<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v6.ipv6test.app
<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v4.ipv6test.app

両方の curl は失敗します。失敗する理由はそれぞれ異なります。以下は出力例です。

<username>@ula-instance:~$ curl -vv -4 v6.ipv6test.app
* Could not resolve host: v6.ipv6test.app
* Closing connection 0
curl: (6) Could not resolve host: v6.ipv6test.app

<username>@ula-instance:~$ curl -vv -4 --connect-timeout 10 v4.ipv6test.app
*   Trying 54.192.51.68:80...
* ipv4 connect timeout after 4993ms, move on!
*   Trying 54.192.51.38:80...
* ipv4 connect timeout after 2496ms, move on!
*   Trying 54.192.51.24:80...
* ipv4 connect timeout after 1248ms, move on!
*   Trying 54.192.51.60:80...
* Connection timeout after 10000 ms
* Closing connection 0
curl: (28) Connection timeout after 10000 ms

IPv6 専用エンドポイントへの IPv4 curl は、A レコードの DNS 解決が失敗するため失敗します(DNS テストで示されているとおり)。IPv6 専用インスタンスには IPv4 アドレスへの到達可能性がないため、IPv4 専用エンドポイントへの IPv4 curl は失敗し、タイムアウトが発生します。

次に、IPv6 経由の到達可能性をテストします。

<username>@ula-instance:~$ curl -vv -6 v6.ipv6test.app

<username>@ula-instance:~$ curl -vv -6 v4.ipv6test.app

以下は出力例です。

<username>@ula-instance:~$ curl -vv -6 v6.ipv6test.app
*   Trying [2600:9000:20be:c000:9:ec55:a1c0:93a1]:80...
* connect to 2600:9000:20be:c000:9:ec55:a1c0:93a1 port 80 failed: Connection timed out
*   Trying [2600:9000:20be:f000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 84507ms, move on!
*   Trying [2600:9000:20be:ae00:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 42253ms, move on!
*   Trying [2600:9000:20be:2000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 21126ms, move on!
*   Trying [2600:9000:20be:b600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 10563ms, move on!
*   Trying [2600:9000:20be:7600:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 5282ms, move on!
*   Trying [2600:9000:20be:b000:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2640ms, move on!
*   Trying [2600:9000:20be:3400:9:ec55:a1c0:93a1]:80...
* ipv6 connect timeout after 2642ms, move on!
* Failed to connect to v6.ipv6test.app port 80 after 300361 ms: Timeout was reached
* Closing connection 0

<username>@ula-instance:~$ curl -vv -6 v4.ipv6test.app
*   Trying [64:ff9b::36c0:333c]:80...
* Connected to v4.ipv6test.app (64:ff9b::36c0:333c) port 80 (#0)
> GET / HTTP/1.1

##
## <Output truncated for brevity>
##

ULA サブネットはインターネットに直接到達できないため、IPv6 専用ウェブサイトへの curl は失敗します。IPv4 専用ウェブサイトへの curl は成功します。これは、DNS64 と NAT64 が GUA インスタンスと ULA インスタンスで同じように動作するためです。唯一の要件は、インスタンスが IPv6 専用であることです。

デュアルスタック ULA インスタンスからの DNS64/NAT64 のテスト

まず、デュアルスタック ULA インスタンス「dualstack-ula-instance」に SSH 接続します。gcloud で IAP に IPv4 アドレスを強制的に使用するには、「--tunnel-through-iap」フラグを使用する必要があります。

gcloud compute ssh dualstack-ula-instance --project $projectname --zone $zonename --tunnel-through-iap 

<username>@dualstack-ula-instance:~$

では、「host」ユーティリティを使用して DNS64 をテストしてみましょう。

<username>@dualstack-ula-instance:~$ host v4.ipv6test.app
v4.ipv6test.app has address 54.192.51.38
v4.ipv6test.app has address 54.192.51.24
v4.ipv6test.app has address 54.192.51.68
v4.ipv6test.app has address 54.192.51.60

<username>@dualstack-ula-instance:~$ host v6.ipv6test.app
v6.ipv6test.app has IPv6 address 2600:9000:269f:fc00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:1c00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:a200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:8a00:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:c800:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:c200:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:5800:9:ec55:a1c0:93a1
v6.ipv6test.app has IPv6 address 2600:9000:269f:dc00:9:ec55:a1c0:93a1

IPv4 のみのウェブサイトが、合成 DNS64 応答ではなく、IPv4 アドレスのみを返すようになっていることに注目してください。これは、DNS64 が IPv6 専用インスタンスにのみ適用され、デュアルスタック インスタンスでは評価されないためです。

DNS64 の必要性を回避するため、/etc/hosts ファイルにエントリを追加して、NAT64 が機能するかどうかをテストしましょう。デュアルスタック インスタンス内で次のコマンドを実行します。

<username>@dualstack-ula-instance:~$ echo '64:ff9b::36c0:3326 v4.ipv6test.app' | sudo tee -a /etc/hosts

次に、curl を使用して、IPv6 経由で IPv4 ウェブサイトにアクセスできるかどうかをテストします。

<username>@dualstack-ula-instance:~$ curl -vv -6 --connect-timeout 10 v4.ipv6test.app

上記のコマンドの出力例を次に示します。

<username>@dualstack-ula-instance:~$ curl -vv -6 --connect-timeout 10 v4.ipv6test.app

*   Trying [64:ff9b::36c0:3326]:80...
* ipv6 connect timeout after 10000ms, move on!
* Failed to connect to v4.ipv6test.app port 80 after 10001 ms: Timeout was reached
* Closing connection 0
curl: (28) Failed to connect to v4.ipv6test.app port 80 after 10001 ms: Timeout was reached

DNS64 と同様に、NAT64 を適用するにはインスタンスが IPv6 専用である必要があるため、curl はタイムアウトします。

NAT64 がデュアルスタック インスタンスに適用されていないことを確認するには、「get-nat-mapping」コマンドを使用して、NAT ゲートウェイが適用しているすべてのポート マッピングを一覧表示します。Cloud Shell で次のコマンドを実行します。

gcloud compute routers get-nat-mapping-info \
      nat64-router --region $regionname \
      --project $projectname

次のような出力が返されるはずです。

---
instanceName: gua-instance
interfaceNatMappings:
- natIpPortRanges:
  - 34.47.60.91:1024-1055
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: '2600:1900:40e0:6f:0:1::'
- natIpPortRanges:
  - 34.47.60.91:32768-32799
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: '2600:1900:40e0:6f:0:1::'
---
instanceName: ula-instance
interfaceNatMappings:
- natIpPortRanges:
  - 34.47.60.91:1056-1087
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: fd20:9c2:93fc:2800:0:0:0:0
- natIpPortRanges:
  - 34.47.60.91:32800-32831
  numTotalDrainNatPorts: 0
  numTotalNatPorts: 32
  sourceAliasIpRange: ''
  sourceVirtualIp: fd20:9c2:93fc:2800:0:0:0:0

NAT の出力には、NAT64 ゲートウェイが IPv6 のみの GUA インスタンスと ULA インスタンスにのみポートを割り当て、デュアルスタック インスタンスには割り当てていないことが示されています。

8. クリーンアップ

Cloud Router をクリーンアップする

Cloud Shell で、次の操作を行います。

gcloud compute routers delete nat64-router \
      --region $regionname \
      --project $projectname --quiet

DNS ポリシーのバインド解除とクリーンアップ

Cloud Shell で、次の操作を行います。

gcloud beta dns policies update allow-dns64 \
    --networks="" \
    --project $projectname
gcloud beta dns policies delete allow-dns64 \
    --project $projectname --quiet

インスタンスをクリーンアップする

Cloud Shell で次の操作を行います(gcloud beta は、インスタンスの削除オペレーションを高速化するために no-graceful-shutdown フラグを使用できるようにするために使用されます)。

gcloud beta compute instances delete gua-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

gcloud beta compute instances delete ula-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

gcloud beta compute instances delete dualstack-ula-instance \
         --zone $zonename \
         --no-graceful-shutdown \
         --project=$projectname --quiet

サブネットをクリーンアップする

Cloud Shell で、次の操作を行います。

gcloud compute networks subnets delete gua-v6only-subnet \
    --project=$projectname --quiet \
    --region=$regionname
 
gcloud compute networks subnets delete ula-v6only-subnet \
    --project=$projectname --quiet \
    --region=$regionname

gcloud compute networks subnets delete ula-dualstack-subnet \
    --project=$projectname --quiet \
    --region=$regionname

ファイアウォール ルールをクリーンアップする

Cloud Shell で、次の操作を行います。

gcloud compute firewall-rules delete allow-v6-iap \
       --project=$projectname \
       --quiet

gcloud compute firewall-rules delete allow-v6-ssh-ula \
       --project=$projectname \
       --quiet

gcloud compute firewall-rules delete allow-v4-iap \
--project=$projectname \
--quiet

VPC をクリーンアップする

Cloud Shell で、次の操作を行います。

gcloud compute networks delete ipv6-only-vpc \
       --project=$projectname \
       --quiet

IAM 権限とサービス アカウントをクリーンアップする

Cloud Shell で、次の操作を行います。

gcloud projects remove-iam-policy-binding  $projectname \
--member=serviceAccount:ipv6-codelab@$projectname.iam.gserviceaccount.com \
--role=roles/compute.instanceAdmin.v1

gcloud iam service-accounts delete \
     ipv6-codelab@$projectname.iam.gserviceaccount.com \
     --quiet \
     --project $projectname

9. 完了

NAT64 と DNS64 を使用して、IPv6 専用インスタンスがインターネット上の IPv4 専用宛先に到達できるようにしました。

次のステップ

以下の Codelab をご覧ください。

その他の資料と動画

リファレンス ドキュメント