La lección anterior terminó con una constatación incómoda: todo lo que ha desplegado Contoso Airlines hasta ahora —las VM del motor heredado, el conjunto de escalado de la API, las aplicaciones de App Service y la cuenta de almacenamiento de tarjetas— se comunica por internet. Funciona, pero ninguna arquitectura seria se queda así. Y arreglarlo después es mucho más caro que hacerlo bien desde el principio, porque el espacio de direcciones de una red virtual condiciona todo lo que se conecte a ella durante años.

Por eso toda arquitectura seria empieza por la red. Cambiar el tamaño de una VM cuesta dos minutos; cambiar el rango de direcciones de una red virtual con cien recursos dentro y una VPN contra dos oficinas es un proyecto con corte de servicio.

En esta lección diseñarás y desplegarás la red completa de Contoso: el espacio de direcciones de vnet-contoso-pro con la aritmética CIDR explicada desde cero, sus cuatro subredes, los grupos de seguridad de red que abren solo lo imprescindible, la resolución DNS privada, el emparejamiento entre redes con el patrón hub-and-spoke, la diferencia decisiva entre puntos de conexión de servicio y Azure Private Link, cómo se conecta App Service a la red y por qué nadie debería exponer SSH a internet teniendo Azure Bastion.

Aviso de coste: las redes virtuales, las subredes y los NSG no cuestan nada. Sí cuestan los puntos de conexión privados (por hora y por datos procesados), las IP públicas estáticas y, sobre todo, Azure Bastion, que se factura por hora desde el momento en que existe. Al final tienes la limpieza.

Contenido

  1. Por qué la red va primero
  2. Redes virtuales y espacio de direcciones
  3. Aritmética CIDR sin dolor
  4. Diseño de subredes de vnet-contoso-pro
  5. Direcciones reservadas por Azure en cada subred
  6. Grupos de seguridad de red (NSG)
  7. Etiquetas de servicio y grupos de seguridad de aplicación
  8. IP públicas y privadas, estáticas y dinámicas
  9. DNS en Azure y zonas DNS privadas
  10. Emparejamiento de redes virtuales y hub-and-spoke
  11. Puntos de conexión de servicio frente a Azure Private Link
  12. Integración de App Service con la red virtual
  13. Azure Bastion frente a exponer SSH y RDP
  14. Verificación con Network Watcher
  15. Topología completa y limpieza
  16. Errores Comunes y Consejos
  17. Ejercicios
  18. Conclusión

  1. Por qué la red va primero

Una red virtual (VNet) es tu red privada dentro de Azure: un espacio de direcciones IP aislado y controlado por ti, en el que colocas recursos que se ven entre sí y por el que decides qué entra y qué sale.

Lo que la red determina, y por eso va primero:

Decisión de red Qué condiciona
Espacio de direcciones Con qué redes locales podrás conectarte sin solapamientos, para siempre
Tamaño de las subredes Cuántos recursos caben; ampliar una subred con recursos dentro es problemático
Segmentación Qué puede hablar con qué cuando alguien entre donde no debe
Conectividad privada Si tus datos viajan por internet o no salen nunca de la red de Microsoft
Región Una VNet vive en una región; se conecta a otras por emparejamiento

Y un aviso sobre lo que no puedes hacer: dos redes con espacios de direcciones solapados no se pueden emparejar ni unir por VPN. Si eliges 10.0.0.0/16 porque es el ejemplo de todos los tutoriales, y tu oficina de Barcelona usa 10.0.0.0/16, has creado un problema que solo se arregla renumerando una de las dos.

  1. Redes virtuales y espacio de direcciones

Una VNet tiene uno o varios espacios de direcciones en notación CIDR, tomados de los rangos privados de la RFC 1918:

Rango privado Direcciones Uso habitual
10.0.0.0/8 16,7 millones Redes corporativas grandes; el más usado en Azure
172.16.0.0/12 1 millón Redes medianas
192.168.0.0/16 65.536 Redes domésticas y pequeñas oficinas

Plan de direccionamiento de Contoso Airlines, decidido por Marta Ríos con la vista puesta en la VPN con las oficinas (lección 02-06):

Red Espacio Uso
vnet-contoso-hub-pro 10.10.0.0/16 Concentrador: puerta de enlace VPN, Bastion, servicios compartidos
vnet-contoso-pro 10.20.0.0/16 Radio de producción: web, aplicación, datos, gestión
vnet-contoso-dev 10.30.0.0/16 Radio de desarrollo
Oficina de Barcelona 10.100.0.0/16 Red local existente
Oficina de Palma 10.101.0.0/16 Red local existente

Observa la disciplina: bloques /16 separados y nada solapado, con hueco reservado entre ellos para crecer. Esto no cuesta nada ahora y evita una migración dolorosa dentro de tres años.

GRUPO_RED="rg-contoso-red-pro"   # el grupo de red de larga duración del módulo 1
REGION="westeurope"
ETIQUETAS=(entorno=produccion proyecto=contoso-reservas centro-coste=CC-1042
           [email protected] criticidad=alta)

az network vnet create \
  --resource-group "${GRUPO_RED}" \
  --name vnet-contoso-pro \
  --location "${REGION}" \
  --address-prefixes 10.20.0.0/16 \
  --tags "${ETIQUETAS[@]}" \
  --output table

Recuerda por qué la red vive en rg-contoso-red-pro y no junto a las aplicaciones: el criterio de agrupación de la lección 01-05 era ciclo de vida + entorno, y la red sobrevive a muchas generaciones de aplicaciones.

  1. Aritmética CIDR sin dolor

Si CIDR ya te resulta natural, salta al apartado siguiente. Si no, este es el mínimo imprescindible y basta con entender tres ideas.

Idea 1: el número tras la barra son los bits fijos. Una dirección IPv4 tiene 32 bits. En 10.20.1.0/24, los 24 primeros bits son la red (fijos) y los 8 restantes identifican al equipo (variables).

Idea 2: cuantos más bits fijos, más pequeña es la red. Un /24 es más pequeño que un /16. La cuenta es directa: 2^(32 - prefijo) direcciones.

Prefijo Direcciones totales Utilizables en Azure (−5) Equivalente
/16 65.536 65.531 Una red virtual completa
/20 4.096 4.091 Un bloque grande de subredes
/24 256 251 Una subred típica
/26 64 59 Subred pequeña (mínimo para Bastion)
/27 32 27 Mínimo para GatewaySubnet
/29 8 3 La subred más pequeña permitida en Azure

Idea 3: para trocear, se avanza de bloque en bloque. Un /24 cubre 256 direcciones, así que dentro de 10.20.0.0/16 las subredes /24 van saltando de uno en uno en el tercer octeto:

10.20.0.0/16  →  de 10.20.0.0 a 10.20.255.255 (65.536 direcciones)
  ├── 10.20.1.0/24   →  10.20.1.0   a  10.20.1.255
  ├── 10.20.2.0/24   →  10.20.2.0   a  10.20.2.255
  ├── 10.20.3.0/24   →  10.20.3.0   a  10.20.3.255
  └── 10.20.4.0/24   →  10.20.4.0   a  10.20.4.255

Y si una subred necesita menos, se trocea con prefijos mayores. Dentro de 10.20.250.0/24:

10.20.250.0/26   →  10.20.250.0   a  10.20.250.63   (64 direcciones)
10.20.250.64/26  →  10.20.250.64  a  10.20.250.127
10.20.250.128/26 →  10.20.250.128 a  10.20.250.191
10.20.250.192/26 →  10.20.250.192 a  10.20.250.255

Regla mental que resuelve el 90 % de los casos del día a día: /24 es "un bloque de 256 con el mismo tercer octeto". Planifica con /24 salvo que sepas que necesitas otra cosa, y deja huecos entre subredes para crecer.

  1. Diseño de subredes de vnet-contoso-pro

Una subred es una porción del espacio de direcciones de la red virtual donde se colocan realmente los recursos. Se segmenta por función, porque la segmentación es lo que permite aplicar reglas distintas a cada capa.

Subred Rango Qué contiene Quién le habla
snet-web 10.20.1.0/24 Front-end público, Application Gateway Internet (solo 443)
snet-app 10.20.2.0/24 API de Disponibilidad, integración de App Service Solo snet-web
snet-datos 10.20.3.0/24 Puntos de conexión privados de SQL y Storage Solo snet-app
snet-gestion 10.20.4.0/24 VM del motor heredado, servidores de administración Solo snet-gestion y Bastion
AzureBastionSubnet 10.20.250.0/26 Azure Bastion (nombre obligatorio) Servicio gestionado
GatewaySubnet 10.20.255.0/27 Puerta de enlace VPN (nombre obligatorio, lección 02-06) Servicio gestionado
GRUPO_RED="rg-contoso-red-pro"
VNET="vnet-contoso-pro"

# Subredes funcionales.
for PAR in "snet-web:10.20.1.0/24" "snet-app:10.20.2.0/24" \
           "snet-datos:10.20.3.0/24" "snet-gestion:10.20.4.0/24"; do
  NOMBRE="${PAR%%:*}"
  RANGO="${PAR##*:}"
  az network vnet subnet create \
    --resource-group "${GRUPO_RED}" \
    --vnet-name "${VNET}" \
    --name "${NOMBRE}" \
    --address-prefixes "${RANGO}" \
    --output none
  echo "Subred ${NOMBRE} creada con ${RANGO}"
done

# Subredes de servicios gestionados: el nombre es obligatorio y literal.
az network vnet subnet create -g "${GRUPO_RED}" --vnet-name "${VNET}" \
  --name AzureBastionSubnet --address-prefixes 10.20.250.0/26 --output none

az network vnet subnet create -g "${GRUPO_RED}" --vnet-name "${VNET}" \
  --name GatewaySubnet --address-prefixes 10.20.255.0/27 --output none

# Comprobación.
az network vnet subnet list -g "${GRUPO_RED}" --vnet-name "${VNET}" \
  --query "[].{Subred:name, Rango:addressPrefix}" --output table

Nombres reservados que hay que respetar al pie de la letra, porque Azure los busca literalmente:

Nombre obligatorio Servicio Tamaño mínimo recomendado
GatewaySubnet Puerta de enlace de VPN o ExpressRoute /27 (mejor /26)
AzureBastionSubnet Azure Bastion /26
AzureFirewallSubnet Azure Firewall /26

Y una restricción con consecuencias: una subred se puede ampliar, pero no si hay recursos que lo impidan, y no se puede reducir con recursos dentro. Dimensiona con margen.

  1. Direcciones reservadas por Azure en cada subred

En una subred /24 no dispones de 256 direcciones ni de 254, sino de 251. Azure reserva cinco en cada subred:

Dirección (en 10.20.1.0/24) Reservada para
10.20.1.0 Identificador de red (estándar)
10.20.1.1 Puerta de enlace predeterminada de Azure
10.20.1.2 Asignada a Azure DNS (mapeo del servidor virtual)
10.20.1.3 Reservada para uso futuro de Azure
10.20.1.255 Difusión (broadcast, estándar)

Por tanto, la primera dirección asignable de snet-web es 10.20.1.4. Esto importa cuando dimensionas al límite: una subred /29 tiene 8 direcciones y solo 3 utilizables. Si has planificado «ocho servidores en un /29», no caben.

  1. Grupos de seguridad de red (NSG)

Un grupo de seguridad de red es una lista de reglas de filtrado con estado que se aplica a una subred o a una NIC. Con estado significa que si permites una conexión de entrada, la respuesta de salida se permite automáticamente; no hay que escribir la regla inversa.

Cada regla tiene:

Campo Qué es
Prioridad De 100 a 4096. Se evalúa de menor a mayor y la primera coincidencia gana
Origen / Destino IP, CIDR, etiqueta de servicio o grupo de seguridad de aplicación
Puertos De origen (casi siempre *) y de destino
Protocolo Tcp, Udp, Icmp o *
Dirección Entrada (Inbound) o Salida (Outbound)
Acción Allow o Deny

Reglas por defecto

Todo NSG trae reglas invisibles que no se pueden borrar, solo sobrescribir con prioridades más bajas:

Prioridad Nombre Efecto
65000 AllowVnetInBound Permite todo el tráfico dentro de la red virtual
65001 AllowAzureLoadBalancerInBound Permite las sondas del balanceador
65500 DenyAllInBound Deniega todo lo demás que entre
65000 AllowVnetOutBound Permite la salida dentro de la red virtual
65001 AllowInternetOutBound Permite la salida a internet
65500 DenyAllOutBound Deniega el resto de la salida

Dos consecuencias que hay que interiorizar:

  1. Por defecto, todo el tráfico dentro de la VNet está permitido, aunque sean subredes distintas. La segmentación no es automática: hay que escribirla.
  2. Por defecto, todo puede salir a internet. Si quieres impedirlo, hay que denegarlo explícitamente.

Segmentar las capas de Contoso

GRUPO_RED="rg-contoso-red-pro"
REGION="westeurope"

# --- NSG de la capa web ---
az network nsg create -g "${GRUPO_RED}" -n nsg-snet-web -l "${REGION}" --output none

# Permitir HTTPS desde internet.
az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-web \
  --name permitir-https-internet --priority 100 \
  --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes Internet --source-port-ranges '*' \
  --destination-address-prefixes '*' --destination-port-ranges 443 \
  --description "Trafico publico de Contoso Reservas" --output none

# Denegar HTTP en claro: la aplicación redirige, pero la red no lo acepta.
az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-web \
  --name denegar-http-plano --priority 110 \
  --direction Inbound --access Deny --protocol Tcp \
  --source-address-prefixes Internet --destination-port-ranges 80 \
  --output none

az network vnet subnet update -g "${GRUPO_RED}" --vnet-name vnet-contoso-pro \
  --name snet-web --network-security-group nsg-snet-web --output none

# --- NSG de la capa de aplicación: solo acepta tráfico desde la web ---
az network nsg create -g "${GRUPO_RED}" -n nsg-snet-app -l "${REGION}" --output none

az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-app \
  --name permitir-api-desde-web --priority 100 \
  --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.20.1.0/24 --destination-port-ranges 8080 \
  --description "API de Disponibilidad solo desde snet-web" --output none

# Denegar explícitamente el resto del tráfico interno (anula AllowVnetInBound).
az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-app \
  --name denegar-resto-vnet --priority 4000 \
  --direction Inbound --access Deny --protocol '*' \
  --source-address-prefixes VirtualNetwork --destination-port-ranges '*' \
  --output none

az network vnet subnet update -g "${GRUPO_RED}" --vnet-name vnet-contoso-pro \
  --name snet-app --network-security-group nsg-snet-app --output none

La regla denegar-resto-vnet con prioridad 4000 es la pieza clave de la segmentación: se evalúa antes que la regla por defecto 65000 que permitía todo el tráfico interno, pero después que la regla 100 que autoriza a la capa web. El resultado es exactamente lo buscado: snet-app solo escucha a snet-web.

Comprobación de las reglas efectivas, incluidas las invisibles:

az network nsg rule list -g "${GRUPO_RED}" --nsg-name nsg-snet-app \
  --include-default \
  --query "sort_by([].{Prioridad:priority, Nombre:name, Dir:direction, Accion:access, Origen:sourceAddressPrefix, Puerto:destinationPortRange}, &Prioridad)" \
  --output table

  1. Etiquetas de servicio y grupos de seguridad de aplicación

Escribir rangos de IP a mano envejece mal: las IP de los servicios de Azure cambian y las de tus máquinas también. Azure ofrece dos abstracciones para no depender de ellas.

Etiquetas de servicio

Una etiqueta de servicio representa un conjunto de prefijos de IP que Microsoft mantiene actualizado por ti.

Etiqueta Qué representa
Internet Todo lo que está fuera de tu red
VirtualNetwork Tu red virtual, redes emparejadas y redes locales conectadas
AzureLoadBalancer El balanceador de Azure (necesario para las sondas de estado)
Storage / Storage.WestEurope Azure Storage, global o de una región
Sql / Sql.WestEurope Azure SQL Database
AzureCloud Todos los servicios públicos de Azure
AzureMonitor Los puntos de conexión de supervisión (módulo 7)
# Permitir salida SOLO hacia Azure SQL de West Europe, sin conocer ninguna IP.
az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-app \
  --name permitir-salida-sql --priority 200 \
  --direction Outbound --access Allow --protocol Tcp \
  --source-address-prefixes VirtualNetwork \
  --destination-address-prefixes Sql.WestEurope \
  --destination-port-ranges 1433 --output none

Grupos de seguridad de aplicación (ASG)

Un ASG es una etiqueta lógica que agrupa NIC. En lugar de escribir reglas por rango de IP, escribes reglas entre grupos: «lo que esté en asg-web puede hablar con lo que esté en asg-api». Cuando añades una máquina al grupo, hereda las reglas sin tocar el NSG.

# 1. Crear los grupos.
az network asg create -g "${GRUPO_RED}" -n asg-web -l "${REGION}" --output none
az network asg create -g "${GRUPO_RED}" -n asg-api -l "${REGION}" --output none

# 2. Regla entre grupos, sin una sola IP escrita.
az network nsg rule create -g "${GRUPO_RED}" --nsg-name nsg-snet-app \
  --name permitir-web-a-api --priority 90 \
  --direction Inbound --access Allow --protocol Tcp \
  --source-asgs asg-web --destination-asgs asg-api \
  --destination-port-ranges 8080 --output none

# 3. Asociar una NIC a su grupo.
az network nic ip-config update \
  -g rg-contoso-reservas-pro --nic-name nic-api-01 --name ipconfig1 \
  --application-security-groups asg-api --output none

Es la forma de mantener reglas legibles cuando la red crece: se leen como frases del negocio, no como listas de octetos.

  1. IP públicas y privadas, estáticas y dinámicas

Tipo Asignación Comportamiento Cuándo usarla
Privada dinámica Azure elige de la subred Se conserva mientras la VM exista; puede cambiar al desasignar y reasignar Predeterminada para VM normales
Privada estática La eliges tú Fija siempre Controladores de dominio, servidores DNS, appliances
Pública dinámica Azure asigna al arrancar Cambia al desasignar la VM Solo pruebas
Pública estática Reservada para ti Fija; se factura aunque la VM esté apagada Balanceadores, puertas de enlace, cualquier cosa en un registro DNS
# IP privada estática para la VM del motor heredado.
az network nic ip-config update \
  --resource-group rg-contoso-reservas-pro \
  --nic-name nic-motor-disponibilidad-01 \
  --name ipconfig1 \
  --private-ip-address 10.20.4.10 \
  --output none

Sobre las SKU de IP pública: Standard es la actual (estática siempre, cerrada por defecto —necesita un NSG que permita el tráfico explícitamente— y compatible con zonas). La SKU Basic está retirada. Usa siempre Standard.

Un matiz de salida a internet que confunde a mucha gente: una VM sin IP pública puede seguir saliendo a internet mediante el acceso saliente predeterminado de Azure, con una IP que no controlas y que Microsoft está retirando para las redes nuevas. Para una salida predecible y auditable se usa un NAT Gateway, que da a toda la subred una IP de salida fija y evita el agotamiento de puertos SNAT.

  1. DNS en Azure y zonas DNS privadas

Dentro de una VNet, Azure ofrece resolución DNS automática: las máquinas de la misma red se resuelven por su nombre de host sin que configures nada, a través del servidor virtual 168.63.129.16 (una dirección que aparece en todos los diagnósticos de Azure y conviene reconocer).

Esa resolución automática tiene límites: no funciona entre redes emparejadas ni resuelve nombres de servicios privados. Para eso están las zonas DNS privadas.

# 1. Zona privada propia de Contoso.
az network private-dns zone create \
  --resource-group rg-contoso-red-pro \
  --name interno.contosoairlines.example \
  --output none

# 2. Vincular la zona a la red virtual, con registro automático de las VM.
az network private-dns link vnet create \
  --resource-group rg-contoso-red-pro \
  --zone-name interno.contosoairlines.example \
  --name enlace-vnet-contoso-pro \
  --virtual-network vnet-contoso-pro \
  --registration-enabled true \
  --output none

# 3. Registro manual para el motor heredado.
az network private-dns record-set a add-record \
  --resource-group rg-contoso-red-pro \
  --zone-name interno.contosoairlines.example \
  --record-set-name motor \
  --ipv4-address 10.20.4.10 \
  --output none

Ahora cualquier recurso de la red resuelve motor.interno.contosoairlines.example a 10.20.4.10. Con --registration-enabled true, además, las VM se registran solas al crearse.

Las zonas privadas son imprescindibles para Private Link: son el mecanismo por el que sql-contoso-reservas-pro.database.windows.net deja de resolver a una IP pública y pasa a resolver a una IP de tu subred. Lo vemos ahora.

El DNS público (registrar contosoairlines.example y publicar sus registros al mundo) es Azure DNS, y se trata en la lección 02-06.

  1. Emparejamiento de redes virtuales y hub-and-spoke

El emparejamiento (peering) conecta dos redes virtuales para que se vean como si fueran una sola: tráfico privado por la red troncal de Microsoft, baja latencia, sin puertas de enlace ni internet de por medio.

Características que hay que conocer:

  • Funciona dentro de una región y entre regiones (emparejamiento global).
  • No es transitivo: si A empareja con B y B con C, A no ve a C. Este es el punto que más sorprende y el que da forma a la topología hub-and-spoke.
  • Los espacios de direcciones no pueden solaparse.
  • Se factura por datos transferidos en ambas direcciones.
  • Hay que crearlo en los dos sentidos: dos comandos, uno por red.
GRUPO_RED="rg-contoso-red-pro"

# Del concentrador al radio de producción.
az network vnet peering create \
  --resource-group "${GRUPO_RED}" \
  --name peer-hub-a-pro \
  --vnet-name vnet-contoso-hub-pro \
  --remote-vnet vnet-contoso-pro \
  --allow-vnet-access \
  --allow-gateway-transit \
  --output none

# Del radio al concentrador (obligatorio: el emparejamiento es bidireccional por definición).
az network vnet peering create \
  --resource-group "${GRUPO_RED}" \
  --name peer-pro-a-hub \
  --vnet-name vnet-contoso-pro \
  --remote-vnet vnet-contoso-hub-pro \
  --allow-vnet-access \
  --use-remote-gateways \
  --output none

Las dos opciones importantes: --allow-gateway-transit en el concentrador significa «puedes usar mi puerta de enlace VPN», y --use-remote-gateways en el radio significa «la usaré». Gracias a esa pareja, una sola puerta de enlace VPN en el concentrador da conectividad a todos los radios, en lugar de pagar una por red. Es el argumento económico principal del patrón.

El patrón hub-and-spoke

graph TD
    OFI["Oficinas Barcelona y Palma<br/>10.100.0.0/16 y 10.101.0.0/16"] -->|VPN sitio a sitio| GW["Puerta de enlace VPN<br/>(lección 02-06)"]
    GW --> HUB["vnet-contoso-hub-pro<br/>10.10.0.0/16<br/>Bastion, servicios compartidos"]
    HUB -->|peering| PRO["vnet-contoso-pro<br/>10.20.0.0/16<br/>producción"]
    HUB -->|peering| DEV["vnet-contoso-dev<br/>10.30.0.0/16<br/>desarrollo"]
    PRO -.->|"sin peering directo:<br/>producción y desarrollo<br/>NO se ven"| DEV

Como el emparejamiento no es transitivo, producción y desarrollo no se ven entre sí aunque ambos vean el concentrador. Eso no es una limitación: es exactamente la propiedad de aislamiento que queremos, y sale gratis.

  1. Puntos de conexión de servicio frente a Azure Private Link

Aquí está la decisión más importante de la lección, y la que resuelve el problema con el que abríamos: la base de datos y la cuenta de almacenamiento de Contoso son accesibles desde internet.

Aspecto Punto de conexión de servicio Punto de conexión privado (Private Link)
Qué hace Extiende la identidad de tu subred hacia el servicio, que sigue teniendo su IP pública Crea una NIC con IP privada de tu subred para ese servicio
Dirección de destino La IP pública del servicio (aunque el tráfico no salga a internet) Una IP privada de snet-datos
¿El servicio sigue expuesto a internet? Sí, solo restringido por el cortafuegos del servicio No, puedes cerrar el acceso público del todo
Acceso desde la red local por VPN No funciona Sí
Alcance Toda la subred hacia todo el servicio Un recurso concreto (esta cuenta, esta base de datos)
DNS No cambia Requiere zona DNS privada para resolver al privado
Coste Gratis Por hora y por datos procesados

La diferencia práctica que decide: con un punto de conexión de servicio, alguien con la clave de la cuenta de almacenamiento puede seguir accediendo desde cualquier sitio autorizado por el cortafuegos; y las oficinas conectadas por VPN no pueden usarlo. Con un punto de conexión privado, el recurso tiene una IP dentro de tu red, se puede cerrar por completo al mundo y las oficinas llegan por la VPN.

Contoso elige puntos de conexión privados para la base de datos sql-contoso-reservas-pro y para la cuenta sttarjetascontosopro. El coste añadido es pequeño frente a exponer los datos de los pasajeros.

GRUPO_RED="rg-contoso-red-pro"
VNET="vnet-contoso-pro"

# 1. Desactivar las políticas de red en la subred de datos (requisito de Private Link).
az network vnet subnet update -g "${GRUPO_RED}" --vnet-name "${VNET}" \
  --name snet-datos --disable-private-endpoint-network-policies true --output none

# 2. Punto de conexión privado hacia la cuenta de almacenamiento de tarjetas.
ID_CUENTA=$(az storage account show -g rg-contoso-reservas-pro \
  -n sttarjetascontosopro --query id -o tsv)

az network private-endpoint create \
  --resource-group "${GRUPO_RED}" \
  --name pe-storage-tarjetas \
  --vnet-name "${VNET}" --subnet snet-datos \
  --private-connection-resource-id "${ID_CUENTA}" \
  --group-id blob \
  --connection-name conexion-blob-tarjetas \
  --output none

# 3. Zona DNS privada del servicio: sin esto, el nombre sigue resolviendo a la IP pública.
az network private-dns zone create -g "${GRUPO_RED}" \
  --name "privatelink.blob.core.windows.net" --output none

az network private-dns link vnet create -g "${GRUPO_RED}" \
  --zone-name "privatelink.blob.core.windows.net" \
  --name enlace-blob-vnet-pro --virtual-network "${VNET}" \
  --registration-enabled false --output none

# 4. Registrar automáticamente el punto de conexión en la zona.
az network private-endpoint dns-zone-group create \
  --resource-group "${GRUPO_RED}" \
  --endpoint-name pe-storage-tarjetas \
  --name grupo-zonas-blob \
  --private-dns-zone "privatelink.blob.core.windows.net" \
  --zone-name blob --output none

# 5. Cerrar el acceso público de la cuenta: ahora solo se llega por la red.
az storage account update -g rg-contoso-reservas-pro -n sttarjetascontosopro \
  --public-network-access Disabled --output none

El paso 3 es el que más gente olvida y el que provoca el fallo clásico: creas el punto de conexión privado, cierras el acceso público y la aplicación deja de funcionar, porque sigue resolviendo el nombre a la IP pública que ya está cerrada. Sin la zona DNS privada vinculada, Private Link no sirve de nada.

Comprobación desde una VM de la red:

nslookup sttarjetascontosopro.blob.core.windows.net
# Esperado: un CNAME a sttarjetascontosopro.privatelink.blob.core.windows.net
# y una dirección 10.20.3.x (privada), no una IP pública.

Las zonas privadas de los servicios que Contoso usará: privatelink.blob.core.windows.net (Storage), privatelink.database.windows.net (SQL, módulo 3), privatelink.vaultcore.azure.net (Key Vault, 04-03) y privatelink.azurewebsites.net (App Service).

  1. Integración de App Service con la red virtual

Con App Service hay que distinguir dos direcciones, y confundirlas es fuente de horas perdidas.

Necesidad Mecanismo Qué hace
Salida: que la aplicación llegue a recursos privados Integración con red virtual Enruta el tráfico de salida por una subred delegada
Entrada: que solo se pueda llegar a la aplicación desde la red Punto de conexión privado o restricciones de acceso Quita la aplicación de internet
# 1. Subred dedicada y delegada a App Service (la delegación es obligatoria
#    y la subred no puede compartirse con otros recursos).
az network vnet subnet create \
  -g rg-contoso-red-pro --vnet-name vnet-contoso-pro \
  --name snet-integracion-app --address-prefixes 10.20.5.0/24 \
  --delegations Microsoft.Web/serverFarms --output none

# 2. Integración de salida de la web de reservas.
az webapp vnet-integration add \
  -g rg-contoso-reservas-pro -n app-contoso-reservas-pro \
  --vnet vnet-contoso-pro --subnet snet-integracion-app --output none

# 3. Entrada restringida para la API interna: solo desde snet-web.
az webapp config access-restriction add \
  -g rg-contoso-reservas-pro -n app-contoso-api-disponibilidad-pro \
  --rule-name permitir-solo-web --priority 100 \
  --action Allow --vnet-name vnet-contoso-pro --subnet snet-web --output none

Detalles prácticos: la integración de salida requiere nivel Basic o superior, la subred delegada es de uso exclusivo de ese plan, y por defecto solo se enruta hacia direcciones privadas (para forzar todo el tráfico de salida por la red se activa WEBSITE_VNET_ROUTE_ALL=1, que es lo que Contoso hace en producción para que la salida sea auditable).

  1. Azure Bastion frente a exponer SSH y RDP

En la lección 02-01 abrimos el puerto 22 a internet con --nsg-rule SSH y avisamos de que era temporal. Ha llegado el momento de hacerlo bien.

Aspecto SSH/RDP con IP pública Azure Bastion
Puertos expuestos a internet 22 o 3389, atacados en minutos Ninguno
IP pública en cada VM Necesaria (y facturada) No hace falta ninguna
Acceso Cliente SSH o RDP Navegador (HTTPS) o cliente nativo por túnel
Auditoría La del sistema operativo Sesiones registradas en la plataforma
Coste Bajo Por hora, desde que existe
# Bastion necesita AzureBastionSubnet (/26) y una IP pública Standard.
az network public-ip create -g rg-contoso-red-pro -n ip-bastion-contoso-pro \
  --sku Standard --allocation-method Static --output none

az network bastion create \
  --resource-group rg-contoso-red-pro \
  --name bastion-contoso-pro \
  --vnet-name vnet-contoso-pro \
  --public-ip-address ip-bastion-contoso-pro \
  --location westeurope \
  --sku Standard \
  --output none

# Conexión SSH sin IP pública en la VM ni puerto 22 abierto.
az network bastion ssh \
  --name bastion-contoso-pro \
  --resource-group rg-contoso-red-pro \
  --target-resource-id "$(az vm show -g rg-contoso-reservas-pro -n vm-motor-disponibilidad-01 --query id -o tsv)" \
  --auth-type ssh-key --username azureuser --ssh-key ~/.ssh/contoso_motor

Aviso de coste importante: Bastion se factura por hora mientras exista, más el tráfico de salida. En un laboratorio, créalo, úsalo y bórralo el mismo día. En producción, su coste se compara favorablemente con el de gestionar IP públicas y sobrevivir a un incidente por SSH expuesto.

Alternativa más barata para administración puntual: az ssh vm con Microsoft Entra ID y la extensión correspondiente, o un simple túnel a través de una VPN de punto a sitio, que es justamente lo que Marta Ríos usará desde casa (lección 02-06).

  1. Verificación con Network Watcher

Cuando algo no conecta, adivinar es caro. Network Watcher te dice exactamente qué regla está bloqueando qué.

# 1. Comprobación de flujo IP: ¿esta conexión concreta se permite o se deniega?
az network watcher test-ip-flow \
  --resource-group rg-contoso-reservas-pro \
  --vm vm-motor-disponibilidad-01 \
  --direction Inbound --protocol TCP \
  --local 10.20.4.10:22 --remote 10.20.1.5:60000 \
  --output json
# La respuesta incluye "access": "Allow"/"Deny" y la regla exacta responsable.

# 2. Reglas de seguridad efectivas sobre una NIC (suma de NSG de subred y de NIC).
az network nic list-effective-nsg \
  --resource-group rg-contoso-reservas-pro \
  --name nic-motor-disponibilidad-01 \
  --output json

# 3. Solución de problemas de conexión de extremo a extremo.
az network watcher test-connectivity \
  --resource-group rg-contoso-reservas-pro \
  --source-resource vm-motor-disponibilidad-01 \
  --dest-address sttarjetascontosopro.privatelink.blob.core.windows.net \
  --dest-port 443 \
  --output table

test-ip-flow es la herramienta que hay que usar antes de tocar ninguna regla: te dice el nombre de la regla que decide, con lo que dejas de cambiar cosas al azar. Y los registros de flujo de NSG, que envían a Log Analytics todo lo permitido y denegado, son la base del análisis que verás en la lección 07-02.

  1. Topología completa y limpieza

graph TB
    NET["Internet"] -->|443| WEB
    subgraph VNET["vnet-contoso-pro  ·  10.20.0.0/16"]
        WEB["snet-web · 10.20.1.0/24<br/>nsg-snet-web: solo 443 de entrada"]
        APP["snet-app · 10.20.2.0/24<br/>nsg-snet-app: solo desde snet-web"]
        DAT["snet-datos · 10.20.3.0/24<br/>puntos de conexión privados"]
        GES["snet-gestion · 10.20.4.0/24<br/>motor heredado, sin IP pública"]
        INT["snet-integracion-app · 10.20.5.0/24<br/>delegada a App Service"]
        BAS["AzureBastionSubnet · 10.20.250.0/26"]
        GWS["GatewaySubnet · 10.20.255.0/27<br/>(lección 02-06)"]
    end
    WEB --> APP
    APP --> DAT
    INT --> DAT
    DAT -.->|Private Link| SQL["sql-contoso-reservas-pro"]
    DAT -.->|Private Link| ST["sttarjetascontosopro"]
    BAS --> GES
    HUB["vnet-contoso-hub-pro · 10.10.0.0/16"] <-->|peering| VNET

Limpieza de lo que factura:

# 1. Bastion: lo más caro de esta lección. Bórralo en cuanto termines.
az network bastion delete -g rg-contoso-red-pro -n bastion-contoso-pro
az network public-ip delete -g rg-contoso-red-pro -n ip-bastion-contoso-pro

# 2. Puntos de conexión privados (se facturan por hora).
az network private-endpoint delete -g rg-contoso-red-pro -n pe-storage-tarjetas

# 3. Las VNet, subredes y NSG no cuestan nada: pueden quedarse.
#    Si aun así quieres borrarlo todo en un laboratorio:
# az group delete --name rg-contoso-red-pro --yes --no-wait

Comprobación de gasto residual: az network public-ip list --query "[?ipConfiguration==null]" -o table y az network private-endpoint list -o table.

Errores Comunes y Consejos

  • Usar 10.0.0.0/16 porque es el ejemplo del tutorial. Es el rango que usa media internet corporativa; el día que montes la VPN con la oficina, se solapará. Planifica el direccionamiento antes de crear nada.
  • Dimensionar las subredes al límite. Azure reserva 5 direcciones por subred y ampliar con recursos dentro es problemático. Deja margen.
  • Olvidar los nombres obligatorios. GatewaySubnet y AzureBastionSubnet se escriben exactamente así; con cualquier otro nombre, el servicio no se despliega.
  • Suponer que las subredes están aisladas por defecto. La regla AllowVnetInBound permite todo el tráfico interno. La segmentación hay que escribirla.
  • Confundir el orden de prioridades. Se evalúa de menor a mayor y la primera coincidencia gana. Una regla Deny con prioridad 100 anula un Allow con prioridad 200.
  • Escribir rangos de IP donde cabe una etiqueta de servicio. Las IP de los servicios de Azure cambian; las etiquetas se actualizan solas.
  • Esperar que el emparejamiento sea transitivo. No lo es. En hub-and-spoke, los radios no se ven entre sí (y normalmente eso es lo que quieres).
  • Crear el emparejamiento en un solo sentido. Queda en estado Initiated y no funciona hasta que existe el enlace inverso.
  • Crear un punto de conexión privado sin su zona DNS privada. El nombre sigue resolviendo a la IP pública y, al cerrar el acceso público, la aplicación deja de funcionar. Es el fallo número uno de Private Link.
  • Dejar Azure Bastion encendido en un laboratorio. Se factura por hora aunque no lo uses.
  • Depurar conectividad a base de probar reglas. az network watcher test-ip-flow te da la regla culpable en un comando.
  • Consejo: documenta el plan de direccionamiento en un fichero del repositorio junto a los scripts. La red es la parte de la arquitectura que más gente necesita consultar y menos gente recuerda.
  • Consejo: aplica los NSG a subredes, no a NIC individuales, salvo excepciones justificadas. Las reglas por NIC se olvidan y crean agujeros invisibles.

Ejercicios

Ejercicio 1: planificar el direccionamiento

Contoso abre una tercera oficina en Sevilla y quiere además una red virtual para pruebas de carga, aislada de producción.

  1. Asigna espacios de direcciones a la oficina de Sevilla y a la nueva red vnet-contoso-pruebas, coherentes con el plan existente y sin solapamientos.
  2. Divide vnet-contoso-pruebas en tres subredes /24 con nombres coherentes con la nomenclatura del curso.
  3. ¿Cuántas direcciones utilizables tiene cada subred /24? ¿Y una /27?
  4. Explica por qué no puedes usar 10.20.0.0/16 para la red de pruebas.

Ejercicio 2: segmentar con NSG

Escribe las reglas de NSG (con prioridades) que cumplan exactamente esta política para vnet-contoso-pro:

  1. snet-web acepta 443 desde internet y nada más.
  2. snet-app acepta 8080 solo desde snet-web; ningún otro tráfico interno.
  3. snet-datos acepta 1433 solo desde snet-app.
  4. snet-gestion no acepta nada desde internet; solo administración desde Bastion.
  5. snet-app puede salir hacia Azure SQL de West Europe, pero no hacia el resto de internet.

Ejercicio 3: hacer privada la base de datos

Describe, con los comandos correspondientes, los pasos para que sql-contoso-reservas-pro deje de ser accesible desde internet y solo se llegue desde snet-app:

  1. Preparar la subred.
  2. Crear el punto de conexión privado.
  3. Configurar la resolución DNS.
  4. Cerrar el acceso público.
  5. Verificar que la resolución devuelve una IP privada.

Explica además qué pasaría si te saltases el paso 3.

Soluciones

Solución 1:

  1. Direccionamiento coherente con el plan existente:
Red Espacio Motivo
Oficina de Sevilla 10.102.0.0/16 Sigue la serie de oficinas (Barcelona 10.100, Palma 10.101)
vnet-contoso-pruebas 10.40.0.0/16 Sigue la serie de redes de Azure (hub 10.10, pro 10.20, dev 10.30)
  1. Subredes:
az network vnet create -g rg-contoso-red-pro -n vnet-contoso-pruebas \
  --address-prefixes 10.40.0.0/16 --location westeurope --output none

az network vnet subnet create -g rg-contoso-red-pro --vnet-name vnet-contoso-pruebas \
  -n snet-web --address-prefixes 10.40.1.0/24 --output none
az network vnet subnet create -g rg-contoso-red-pro --vnet-name vnet-contoso-pruebas \
  -n snet-app --address-prefixes 10.40.2.0/24 --output none
az network vnet subnet create -g rg-contoso-red-pro --vnet-name vnet-contoso-pruebas \
  -n snet-datos --address-prefixes 10.40.3.0/24 --output none
  1. Una /24 tiene 256 direcciones, menos las 5 que reserva Azure: 251 utilizables. Una /27 tiene 32, menos 5: 27 utilizables.

  2. Porque 10.20.0.0/16 ya es el espacio de vnet-contoso-pro. Dos redes con rangos solapados no se pueden emparejar ni conectar por VPN, y el enrutamiento sería ambiguo. Aunque hoy no fueras a emparejarlas, reutilizar el rango cierra esa puerta para siempre.

Solución 2:

G="rg-contoso-red-pro"

# 1. snet-web: 443 desde internet, nada más (la denegación la da la regla por defecto 65500).
az network nsg rule create -g $G --nsg-name nsg-snet-web -n permitir-https \
  --priority 100 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes Internet --destination-port-ranges 443 --output none

# 2. snet-app: 8080 solo desde snet-web; el resto del tráfico interno, denegado.
az network nsg rule create -g $G --nsg-name nsg-snet-app -n permitir-web \
  --priority 100 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.20.1.0/24 --destination-port-ranges 8080 --output none
az network nsg rule create -g $G --nsg-name nsg-snet-app -n denegar-resto-vnet \
  --priority 4000 --direction Inbound --access Deny --protocol '*' \
  --source-address-prefixes VirtualNetwork --destination-port-ranges '*' --output none

# 3. snet-datos: 1433 solo desde snet-app.
az network nsg rule create -g $G --nsg-name nsg-snet-datos -n permitir-app-sql \
  --priority 100 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.20.2.0/24 --destination-port-ranges 1433 --output none
az network nsg rule create -g $G --nsg-name nsg-snet-datos -n denegar-resto-vnet \
  --priority 4000 --direction Inbound --access Deny --protocol '*' \
  --source-address-prefixes VirtualNetwork --destination-port-ranges '*' --output none

# 4. snet-gestion: nada de internet; SSH y RDP solo desde la subred de Bastion.
az network nsg rule create -g $G --nsg-name nsg-snet-gestion -n permitir-bastion \
  --priority 100 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.20.250.0/26 --destination-port-ranges 22 3389 --output none
az network nsg rule create -g $G --nsg-name nsg-snet-gestion -n denegar-internet \
  --priority 200 --direction Inbound --access Deny --protocol '*' \
  --source-address-prefixes Internet --destination-port-ranges '*' --output none

# 5. Salida de snet-app: solo Azure SQL de la región; el resto de internet, denegado.
az network nsg rule create -g $G --nsg-name nsg-snet-app -n permitir-salida-sql \
  --priority 200 --direction Outbound --access Allow --protocol Tcp \
  --destination-address-prefixes Sql.WestEurope --destination-port-ranges 1433 --output none
az network nsg rule create -g $G --nsg-name nsg-snet-app -n denegar-salida-internet \
  --priority 4000 --direction Outbound --access Deny --protocol '*' \
  --destination-address-prefixes Internet --destination-port-ranges '*' --output none

Detalle del punto 5: la regla de salida a SQL debe tener prioridad menor (200) que la denegación general (4000), o el tráfico legítimo quedaría bloqueado.

Solución 3:

G="rg-contoso-red-pro"; V="vnet-contoso-pro"

# 1. Preparar la subred que alojará el punto de conexión.
az network vnet subnet update -g $G --vnet-name $V -n snet-datos \
  --disable-private-endpoint-network-policies true --output none

# 2. Punto de conexión privado hacia el servidor SQL (group-id sqlServer).
ID_SQL=$(az sql server show -g rg-contoso-reservas-pro -n sql-contoso-reservas-pro --query id -o tsv)
az network private-endpoint create -g $G -n pe-sql-reservas \
  --vnet-name $V --subnet snet-datos \
  --private-connection-resource-id "${ID_SQL}" --group-id sqlServer \
  --connection-name conexion-sql-reservas --output none

# 3. Zona DNS privada del servicio, vinculada a la red y enlazada al punto de conexión.
az network private-dns zone create -g $G -n "privatelink.database.windows.net" --output none
az network private-dns link vnet create -g $G \
  --zone-name "privatelink.database.windows.net" -n enlace-sql-vnet-pro \
  --virtual-network $V --registration-enabled false --output none
az network private-endpoint dns-zone-group create -g $G \
  --endpoint-name pe-sql-reservas -n grupo-zonas-sql \
  --private-dns-zone "privatelink.database.windows.net" --zone-name sql --output none

# 4. Cerrar el acceso público del servidor.
az sql server update -g rg-contoso-reservas-pro -n sql-contoso-reservas-pro \
  --enable-public-network false --output none

# 5. Verificar desde una VM de la red.
nslookup sql-contoso-reservas-pro.database.windows.net
# Esperado: CNAME a ...privatelink.database.windows.net y una IP 10.20.3.x

Si te saltas el paso 3, el punto de conexión privado existe y tiene su IP, pero el nombre sql-contoso-reservas-pro.database.windows.net sigue resolviendo a la IP pública. En cuanto ejecutes el paso 4, la aplicación intentará conectarse a esa IP pública ya cerrada y fallará con un error de conexión agotada, sin ninguna pista que apunte al DNS. Es la avería más frecuente y más desconcertante de Private Link.

Conclusión

Ya tienes la tercera pata de la plataforma. Sabes por qué la red va primero y qué decisiones quedan congeladas durante años. Manejas los espacios de direcciones privados, la aritmética CIDR suficiente para trocear una /16 en subredes sin solapamientos, y conoces las cinco direcciones que Azure reserva en cada subred. Has diseñado y desplegado vnet-contoso-pro con snet-web, snet-app, snet-datos, snet-gestion y las subredes de nombre obligatorio AzureBastionSubnet y GatewaySubnet. Escribes reglas de NSG entendiendo las prioridades y las reglas por defecto —incluida la más peligrosa, AllowVnetInBound, que hace que la segmentación no sea automática—, y usas etiquetas de servicio y grupos de seguridad de aplicación para que las reglas no dependan de listas de IP. Distingues IP públicas y privadas, estáticas y dinámicas, con su efecto en la factura. Sabes cómo funciona la resolución DNS de Azure y para qué sirven las zonas DNS privadas. Entiendes el emparejamiento y su falta de transitividad, que es justo lo que da forma al patrón hub-and-spoke y permite pagar una sola puerta de enlace VPN. Y has tomado la decisión que más protege los datos de los pasajeros: puntos de conexión privados con su zona DNS para la base de datos y la cuenta de almacenamiento, en lugar de puntos de conexión de servicio. Además, has conectado App Service a la red, has sustituido el SSH expuesto por Azure Bastion y sabes diagnosticar con Network Watcher en vez de adivinar.

Queda una pieza para cerrar el módulo, y es la que conecta Azure con el mundo real de Contoso Airlines. Las oficinas de Barcelona y Palma siguen fuera de esta red: su personal no llega a los recursos privados que acabas de blindar, el sistema de facturación heredado sigue viviendo en local, y Marta Ríos no puede administrar nada desde casa sin exponer algo. Al mismo tiempo, un cliente que compra un billete desde Sudamérica sufre la latencia de cruzar el Atlántico en cada petición hasta West Europe.

En la última lección del módulo, Conectividad híbrida y entrega global, resolvemos ambos extremos: VPN de punto a sitio para Marta y de sitio a sitio para las oficinas, con sus puertas de enlace y su despliegue por CLI; ExpressRoute y cuándo justifica su precio; Azure Virtual WAN como evolución del hub-and-spoke híbrido; y la entrega global del sitio con Azure Front Door, Azure CDN y Traffic Manager, incluido el coste de la salida de datos que sorprende a todo el mundo la primera vez que lee una factura.

Curso de Azure

Módulo 1: Introducción a Azure

Módulo 2: Servicios principales de Azure

Módulo 3: Bases de datos de Azure

Módulo 4: Seguridad en Azure

Módulo 5: Azure DevOps

Módulo 6: Servicios avanzados de Azure

Módulo 7: Monitoreo y gestión

Módulo 8: Gestión y optimización de costos

Módulo 9: Estudios de caso y mejores prácticas

© Copyright 2026. Todos los derechos reservados