El tráfico de los contenedores Docker esquiva la VPN del host: cómo comprobarlo
Una VPN del host solo cubre el espacio de nombres del host. Use estas comprobaciones para saber si el tráfico de los contenedores en el puente entra en el túnel o sale directamente.
Su navegador en el host muestra la dirección de salida de la VPN, el contenedor informa de su conexión doméstica y alguien lo llama fuga. No se ha filtrado nada. Un túnel del host es un conjunto de interfaces, rutas y reglas que pertenecen al espacio de nombres de red del host, y un contenedor en un puente es otro espacio de nombres con su propia ruta predeterminada. He estado en un stack de Compose donde el cliente VPN llevaba semanas conectado y ni un solo paquete de contenedor había entrado nunca en él.
Compruebe el espacio de nombres antes que el icono de la bandeja
Los espacios de nombres son todo el argumento. Cuando Docker arranca un contenedor en una red de puente, crea un espacio de nombres de red, conecta un extremo de un par veth dentro de él y da a ese espacio de nombres una dirección y una ruta predeterminada. La interfaz del túnel, se llame como se llame, vive en el espacio de nombres del host. El tráfico dentro del contenedor no puede verla, y ningún ajuste del cliente cambia eso desde fuera.
Dos movimientos admitidos le sacan del aislamiento. --network host coloca el contenedor dentro del espacio de nombres del host, así que hereda las rutas del host y, por tanto, el túnel. --network container:vpn comparte el espacio de nombres de otro contenedor, y así es como la mayoría de los diseños sidecar envían una carga de trabajo por un contenedor VPN. Ambos son elecciones explícitas; normalmente solo una de ellas es lo que pretendía la persona que despliega.
El modo host no es una mejora gratuita. El contenedor deja de tener su propia dirección, la publicación de puertos deja de aplicarse y un proceso que tenga NET_ADMIN allí puede reescribir el enrutamiento del host. Aceptarlo puede ser la decisión correcta. Suponer que ya está activo es como la gente pasa una tarde depurando un túnel que nunca estaba en la ruta.
Siga el paquete fuera del puente
Un contenedor del puente envía su paquete a su puerta de enlace predeterminada, que es la interfaz del puente en el host. El host reenvía entonces el paquete y, en la configuración predeterminada, traduce la dirección de origen a la suya antes de que el paquete salga. Ese paso de traducción es el que derrota la política en silencio.
Cuando el paquete llega al extremo del túnel, lleva la dirección del host. Cualquier regla, ruta de política o decisión de túnel dividido basada en la dirección original del contenedor deja de coincidir, y dos contenedores destinados a salir por salidas distintas no se pueden distinguir solo por el origen. Si necesita enrutamiento por contenedor, la decisión tiene que ocurrir antes de la traducción o dentro de un espacio de nombres que usted controle.
Docker mantiene estas reglas por sí mismo, con el backend de firewall con el que se haya configurado el demonio. Las reglas escritas a mano fuera del gancho admitido para el tráfico reenviado, DOCKER-USER, pueden reordenarse o eliminarse cuando el demonio se reinicia o el host se actualiza. La documentación de Docker sobre filtrado de paquetes muestra el orden de las cadenas; el punto práctico es que cada regla necesita un propietario y una ruta de recarga que usted haya probado de verdad.
Pruebe los dos sistemas por separado
La evidencia de un espacio de nombres no dice nada sobre el otro. Una petición ejecutada dentro del contenedor VPN demuestra que el túnel funciona para ese contenedor. No es evidencia sobre el host, y el mismo comando ejecutado desde un contenedor --network host no es evidencia sobre el puente.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
Después repita la prueba dentro del contenedor real de la aplicación en lugar de una imagen parecida. La aplicación puede llevar una ruta extra, una variable de entorno de proxy o un resolutor distinto, y cada una de esas cosas cambia la respuesta. Compruebe la resolución de nombres y la segunda familia de direcciones cada vez: los contenedores en puentes definidos por el usuario resuelven a través del resolutor integrado de Docker en 127.0.0.11, y una ruta predeterminada IPv6 en el puente puede sacar tráfico mientras usted está ocupado probando un túnel solo IPv4.
Lea el patrón antes de tocar credenciales
Cuando el host funciona y el contenedor no, la causa es estructural casi siempre, y rotar claves o reinstalar el cliente desperdicia una tarde. Ordene primero el síntoma y la solución suele nombrarse sola.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
La fila del solapamiento merece su propia frase. Un perfil de VPN que empuja una ruta para 172.17.0.0/16, o para una 10.0.0.0/8 que casualmente contiene el prefijo de su puente, hace que el túnel reclame la subred de los contenedores, y las respuestas a las direcciones traducidas irán en la dirección equivocada o desaparecerán. Renumerar la red de Docker suele ser más limpio que acumular excepciones.
Haga explícita la cobertura y luego rómpala a propósito
Dos diseños resisten una revisión. Comparta el espacio de nombres del contenedor VPN y cada carga cubierta usa un solo túnel con una sola frontera de reinicio, lo que es simple hasta que un servicio necesita otra salida o su propia ruta DNS. O bien encamine la red de los contenedores a una puerta de enlace VPN en el host: reenvío activado, el prefijo del puente apuntado al túnel, el tráfico de retorno tratado explícitamente. Eso compra control por red y le cuesta un conjunto de reglas que mantener a través de actualizaciones del demonio y del cliente.
En cualquier caso, la prueba que importa es el caso de fallo. Detenga el túnel con una petición de contenedor en vuelo y observe adónde va el paquete. Si vuelve a la ruta directa, la cobertura nunca se aplicó, porque un kill switch del cliente gobierna el tráfico propio del cliente y no los paquetes reenviados desde un puente. Reinicie después el demonio y el host y confirme el resultado una segunda vez; ese es el momento en que las reglas escritas a mano desaparecen.
Antes de darlo por terminado, confirme cuatro cosas: la interfaz del túnel está en el mismo espacio de nombres que el tráfico, la prueba del contenedor se ejecutó dentro del contenedor real, se comprobaron la resolución de nombres y ambas familias de direcciones, y la prueba de fallo del túnel sigue fallando cerrada. Después anote el backend de firewall, la versión del cliente y el propietario de cada regla. Ese registro es lo que impide que la siguiente actualización deje una mezcla no documentada de suposiciones antiguas.