Crea instancias de VM solo con IPv6 y habilita NAT64/DNS64

1. Introducción

Uno de los principales desafíos de la migración a IPv6 es mantener la accesibilidad a las redes y los extremos solo IPv4. Una tecnología líder para abordar este desafío es combinar el uso de DNS64 (definido en RFC6147) para traducir registros A en registros AAAA para los clientes, que luego se combina con NAT64 (definido en RFC6146) para traducir direcciones IPv6 con formato especial en IPv4, donde la dirección IPv4 está integrada en la dirección IPv6 especial. En este codelab, se guía al usuario para que configure ambas funciones en una nube privada virtual (VPC) de Google Cloud Platform (GCP). Cuando se configuran juntos, GCP NAT64 y DNS64 permiten que las instancias solo IPv6 se comuniquen con los servidores solo IPv4 en Internet.

En este lab, configurarás una VPC con diferentes tipos de subredes e instancias de IPv6 : GUA (dirección de unidifusión global) solo IPv6, ULA (dirección local única) solo IPv6 y ULA de pila doble. Luego, configurarás y probarás los servicios administrados de DNS64 y NAT64 de Google Cloud para acceder a sitios web solo para IPv4 desde ellos.

2. Qué aprenderás

  • Cómo crear subredes e instancias de solo IPv6
  • Cómo habilitar el servicio DNS64 administrado de Google Cloud para una VPC
  • Cómo crear una puerta de enlace de Cloud NAT de Google Cloud configurada para NAT64
  • Cómo probar la resolución de DNS64 desde instancias solo IPv6 a destinos solo IPv4
  • Cómo se diferencia el comportamiento de DNS64 y NAT64 entre las instancias de pila única y de pila doble
  • Cómo configurar una puerta de enlace NAT para NAT64
  • Cómo probar la conectividad de NAT64 desde instancias solo IPv6 a destinos solo IPv4

3. Antes de comenzar

Actualiza el proyecto para que sea compatible con el codelab

En este codelab, se usan variables para facilitar la implementación de la configuración de gcloud en Cloud Shell.

Dentro de Cloud Shell, haz lo siguiente:

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]

Arquitectura general del lab

63e4293e033da8d3.png

Para demostrar cómo NAT64 y DNS64 interactúan con diferentes tipos de subredes IPv6, crearás una sola VPC con subredes IPv6 en formatos GUA y ULA. También crearás una subred de pila doble (con direccionamiento ULA) para demostrar que DNS64 y NAT64 no se aplican a las VMs de pila doble.

Luego, configurarás DNS64 y NAT64, y probarás la conectividad a destinos IPv6 e IPv4 en Internet.

4. Pasos de preparación

Primero, configura la cuenta de servicio, IAM, infraestructura de red y las instancias necesarias en tu proyecto de Google Cloud.

Crea una cuenta de servicio y vinculaciones de IAM

Comenzaremos por crear una cuenta de servicio nueva para permitir que las instancias se conecten entre sí a través de SSH con gcloud. Necesitaremos esta capacidad porque no podemos usar IAP para acceder a la instancia solo para IPv6 de GUA, y Cloud Shell aún no permite el acceso directo a IPv6. Ejecuta los siguientes comandos en 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

Crea una VPC y habilita la ULA

Ejecuta los siguientes comandos en Cloud Shell para crear una red de VPC con el modo de subred personalizado y el IPv6 interno de ULA habilitado.

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

Crea reglas de firewall

Crea reglas de firewall para permitir el acceso SSH. Una regla permite SSH desde el rango ULA general (fd20::/20). Dos reglas más permiten el tráfico desde los rangos IPv6 e IPv4 predefinidos de IAP (2600:2d00:1:7::/64 y 35.235.240.0/20, respectivamente).

Ejecuta los siguientes comandos en 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 

Crea subredes

Crea una subred de solo GUA v6, una subred de solo ULA v6 y una subred de ULA de pila doble. Ejecuta los siguientes comandos en 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 

Crea instancias

Crea instancias en cada una de las subredes que acabas de crear. La instancia de ULA solo IPv6 se especifica con la plataforma de Cloud para permitirnos usarla como jumpbox en la instancia de GUA solo IPv6. Ejecuta los siguientes comandos en 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

Configuración y acceso inicial a la instancia

Conéctate por SSH a la instancia de ULA, que usará IAP de forma predeterminada. Usa el siguiente comando en Cloud Shell para establecer una conexión SSH a la instancia de ULA:

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

<username>@ula-instance:~$ 

También usaremos la instancia de ULA como jumpbox para la instancia de GUA (porque IAP no funciona con instancias de GUA y las VMs de Cloud Shell no pueden acceder a destinos IPv6).

Aún dentro del shell de la instancia de ULA. Intenta aplicar SSH a la instancia de la GUA con el siguiente comando de gcloud.

La primera vez que ejecutes un comando SSH dentro de una instancia, se te pedirá que configures un par de claves SSH. Sigue presionando Intro hasta que se cree la clave y se ejecute el comando SSH. Esto creará un nuevo par de claves sin frase de contraseña.

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]-----+

Si se ejecuta correctamente, el comando SSH se completará y te conectarás a la instancia de GUA a través de 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. Examina las instancias que solo admiten IPv6.

Examinemos ambas instancias solo con IPv6 a través de SSH y analicemos sus tablas de enrutamiento.

Examina la instancia de GUA

Establece una conexión SSH a "gua-instance" primero a través de "ula-instance".

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

Veamos la tabla de enrutamiento de IPv6 de la instancia con el siguiente comando:

<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

Observamos tres entradas en la tabla de enrutamiento.

  1. Una ruta /65 para la subred de GUA a la que pertenece la instancia con un siguiente salto derivado que usa una dirección local de vínculo para la puerta de enlace predeterminada. Recuerda que el /65 superior está reservado para los balanceadores de cargas de red de transferencia de IPv6.
  2. Una ruta /64 integrada para el prefijo unicast local de vínculo fe80::/64
  3. Una ruta predeterminada que apunta a la dirección local del vínculo de la puerta de enlace predeterminada de la subred

Veamos la tabla de enrutamiento IPv4 con este comando

<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

¿Te sorprende? De hecho, mantenemos una tabla de enrutamiento IPv4 en instancias solo IPv6 estrictamente para permitir el acceso al servidor de metadatos de Compute (169.254.169.154), ya que sigue siendo un extremo solo IPv4.

Dado que la instancia adopta la IP 169.254.1.2 cuando es una instancia solo de IPv6. Esta IP no se puede enrutar a ningún lugar, excepto al servidor de metadatos de Compute, por lo que la instancia está aislada de todas las redes IPv4.

Pruebas de cURL

Probemos la conectividad real a sitios web solo para IPv4 y solo para IPv6 con curl.

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

A continuación, se muestra un ejemplo de resultado.

<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

Como se esperaba, no hay accesibilidad a un extremo de Internet IPv4 desde una instancia solo IPv6. Sin el aprovisionamiento de DNS64 y NAT64, la instancia solo IPv6 no tiene una ruta a un destino IPv4. La accesibilidad a un destino IPv6 funciona normalmente, ya que la instancia tiene una dirección IPv6 de GUA.

Examina la instancia de ULA

Establece una conexión SSH a la instancia "ula-instance" (usa IAP de forma predeterminada).

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

Veamos la tabla de enrutamiento de IPv6 de la instancia con el siguiente comando:

<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

Observamos tres entradas en la tabla de enrutamiento, similares a la instancia de GUA, con la excepción de que la máscara es /64 en lugar de /65. Además, la ruta de subred pertenece a un rango de ULA. (en el agregado fd20::/20)

Veamos la tabla de enrutamiento IPv4 con este comando

<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

Lo que muestra una situación similar a la de la instancia de GUA.

Pruebas de cURL

Repetir las pruebas de conectividad a sitios web solo para IPv4 y solo para IPv6 con curl

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

A continuación, se muestra un ejemplo de resultado.

<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

En el caso de la instancia de ULA, no hay accesibilidad a ambos extremos de Internet, ya que, para el extremo IPv6, no podemos usar una dirección de ULA para comunicarnos, y la instancia no tiene accesibilidad a IPv4 como instancia solo IPv6.

6. Habilita NAT64 y DNS64

Configura los servicios administrados de DNS64 y NAT64 para tu VPC.

DNS64

Habilita la política del servidor DNS64 para tu VPC . Esto le indica al agente de resolución de DNS de la VPC que sintetice registros AAAA para las respuestas solo A. Ejecuta los siguientes comandos en Cloud Shell:

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

NAT64

Crea un Cloud Router, que es necesario para Cloud NAT . Luego, crea una puerta de enlace de Cloud NAT configurada para NAT64, habilítala para todos los rangos de IP de subred solo IPv6 y asigna automáticamente IPs externas. Ejecuta los siguientes comandos en 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. Prueba NAT64 y DNS64

Ahora, probemos la configuración de NAT64 y DNS64 desde las instancias solo para IPv6, comenzando con la instancia de GUA y, luego, con la instancia de ULA.

Prueba de DNS64/NAT64 desde una instancia de GUA

Establece una conexión SSH a "gua-instance" primero a través de "ula-instance".

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

Pruebas de DNS

Prueba la resolución de DNS de un sitio web solo para IPv6 (p.ej., v6.ipv6test.app, pero cualquier sitio web solo para IPv6 debería arrojar un resultado similar).

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

Esperamos que solo se muestren respuestas AAAA de IPv6.

Ejemplo de resultado:

<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

Prueba la resolución de DNS de un sitio web solo para IPv4 (p.ej., v4.ipv6test.app) . Se espera un registro A (el IPv4 original) y un registro AAAA sintetizado por DNS64 con el prefijo conocido 64:ff9b::/96 .

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

Ejemplo de resultado:

<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

En el ejemplo anterior, la dirección IPv4 (54.192.51.38) en decimal se traduciría a (36 c0 33 26) en hexadecimal, por lo que esperaríamos que la respuesta para el registro AAAA sea (64:ff9b::36c0:3326), que coincide con una de las respuestas AAAA que recibimos.

Pruebas de cURL

Probemos la conectividad real a los mismos extremos solo para IPv4 y solo para IPv6 con curl a través de IPv6.

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

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

A continuación, se muestra un ejemplo de resultado.

<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>
##

Ambos comandos curl se ejecutan correctamente. Observa cómo fue posible conectarse a un sitio web solo IPv4 a través de IPv6 gracias a que NAT64 y DNS64 trabajaron en conjunto para habilitar la conectividad correctamente.

Verificar las IPs de origen

Usemos un servicio de reflexión de IP para verificar la IP de origen que observó el destino .

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

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

Ejemplo de resultado

<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::

La dirección IPv6 informada debe coincidir con la dirección IPv6 de la instancia . Esta dirección debe coincidir con el resultado del comando "ip -6 address" en la instancia. Por ejemplo:

<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

Sin embargo, la dirección IPv4 informada debe coincidir con la dirección IP externa de la puerta de enlace de Cloud NAT, ya que realiza la función de NAT64 antes de salir a Internet. Esto se puede verificar ejecutando este comando de gcloud en Cloud Shell

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

Ejemplo de resultado

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

Ten en cuenta que la "natIp" que se informa en el resultado coincide con el resultado que se recibe del sitio web de reflexión de IP.

Prueba de DNS64/NAT64 desde una instancia de ULA

Primero, establece una conexión SSH a la instancia de ULA "ula-instance".

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

<username>@ula-instance:~$

Pruebas de DNS

Prueba la resolución de DNS de un sitio web solo para IPv6 (p.ej., v6.ipv6test.app, pero cualquier sitio web solo para IPv6 debería arrojar un resultado similar).

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

Esperamos que solo se muestren respuestas AAAA de IPv6.

Ejemplo de resultado:

<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

Prueba la resolución de DNS de un sitio web solo para IPv4 (p.ej., v4.ipv6test.app) . Se espera un registro A (el IPv4 original) y un registro AAAA sintetizado por DNS64 con el prefijo conocido 64:ff9b::/96 .

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

Ejemplo de resultado:

<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

En el ejemplo anterior, la dirección IPv4 (54.192.51.38) en decimal se traduciría a (36 c0 33 26) en hexadecimal, por lo que esperaríamos que la respuesta para el registro AAAA sea (64:ff9b::36c0:3326), que coincide con una de las respuestas AAAA que recibimos.

Pruebas de cURL

Probemos la conectividad real a los mismos extremos solo para IPv4 y solo para IPv6 con curl.

Como punto de partida, demostremos que no es posible acceder a través de IPv4, ya que la instancia es solo de IPv6.

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

Si bien ambos comandos curl fallarán. Fallarán por diferentes motivos. A continuación, se muestra un ejemplo de resultado.

<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

El comando curl de IPv4 a un extremo solo de IPv6 falla porque falla la resolución de DNS para el registro A (como se demostró durante las pruebas de DNS). El comando curl de IPv4 a un extremo solo de IPv4 falla porque una instancia solo de IPv6 no tiene accesibilidad a ninguna dirección IPv4, y se produce un tiempo de espera debido a eso.

Ahora probemos la accesibilidad a través de IPv6.

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

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

A continuación, se muestra un ejemplo de resultado.

<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>
##

Si bien la solicitud curl al sitio web solo para IPv6 falla porque las subredes de ULA no tienen accesibilidad directa a Internet. La operación curl en el sitio web solo IPv4 se realiza correctamente porque DNS64 y NAT64 funcionan de la misma manera para las instancias de GUA y ULA. El único requisito es que la instancia sea solo IPv6.

Prueba de DNS64/NAT64 desde una instancia de ULA de doble pila

Primero, establece una conexión SSH a la instancia de ULA de doble pila "dualstack-ula-instance". Debemos usar la marca "–tunnel-through-iap" para forzar a gcloud a usar la dirección IPv4 para IAP.

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

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

Ahora probemos DNS64 con la utilidad "host".

<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

Observa cómo el sitio web solo IPv4 ahora devuelve solo direcciones IPv4 y ya no las respuestas sintéticas de DNS64. Esto se debe a que DNS64 solo se aplica a las instancias que solo admiten IPv6 y no se evalúa para las instancias de pila doble.

Para evitar la necesidad de DNS64, agreguemos una entrada al archivo /etc/hosts para probar si NAT64 funciona. Ejecuta el siguiente comando dentro de la instancia de doble pila:

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

Luego, usemos curl para probar el acceso al sitio web de IPv4 a través de IPv6.

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

Este es un ejemplo del resultado del comando anterior:

<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

El comando curl debería agotar el tiempo de espera porque, al igual que DNS64, NAT64 también requiere que la instancia sea solo IPv6 para aplicarse.

Para confirmar que NAT64 no se aplica a la instancia de pila doble, usemos el comando "get-nat-mapping" para enumerar todas las asignaciones de puertos que aplica la puerta de enlace de NAT. Ejecuta los siguientes comandos en Cloud Shell:

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

Deberías obtener un resultado similar al siguiente fragmento:

---
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

El resultado de NAT muestra que la puerta de enlace NAT64 solo asignó puertos para las instancias de GUA y ULA solo IPv6, pero no para la instancia de pila doble.

8. Limpia

Limpia Cloud Router

En Cloud Shell, haz lo siguiente:

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

Desvincula y limpia la política de DNS

En Cloud Shell, haz lo siguiente:

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

Limpia instancias

Dentro de Cloud Shell, haz lo siguiente: (ten en cuenta que se usa gcloud beta para permitirnos usar la marca no-graceful-shutdown para una operación de eliminación de instancias más rápida)

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

Limpia las subredes

En Cloud Shell, haz lo siguiente:

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

Cómo limpiar reglas de firewall

En Cloud Shell, haz lo siguiente:

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

Limpia la VPC

En Cloud Shell, haz lo siguiente:

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

Limpia los permisos de IAM y la cuenta de servicio

En Cloud Shell, haz lo siguiente:

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. Felicitaciones

Usaste correctamente NAT64 y DNS64 para permitir que las instancias solo IPv6 lleguen a destinos solo IPv4 en Internet.

Próximos pasos

Consulta algunos codelabs sobre los siguientes temas:

Lecturas y videos adicionales

Documentos de referencia