--- title: "Aislamiento de red con network namespaces en Ubuntu 24.04" description: "Aísla procesos con network namespaces en Ubuntu 24.04: pares veth, bridge Linux, salida a Internet con NAT, DNS por namespace y firewall propio en cada uno." category: "Redes Avanzadas" language: es source: https://cubepath.com/es/docs/redes-avanzadas/aislamiento-avanzado-con-network-namespaces updated: 2026-09-25 --- # Aislamiento de red con network namespaces en Ubuntu 24.04 Un network namespace es una copia independiente de la pila de red de Linux: tiene sus propias interfaces, direcciones, tabla de rutas, reglas de firewall y tabla ARP. Es el mecanismo que Docker, Podman y Kubernetes usan para dar a cada contenedor su propia red. En este tutorial construirás a mano, en Ubuntu 24.04, lo mismo que hace un motor de contenedores: dos namespaces conectados a un bridge, con salida a Internet mediante NAT, resolución DNS y un firewall propio dentro de cada uno. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Sirve cualquier servidor de pruebas: todo lo que crees aquí se elimina con los comandos del paso 7. - Un usuario no root con privilegios `sudo`. - Los paquetes `iproute2` e `iptables`, que vienen instalados por defecto en Ubuntu 24.04. Si el servidor ya ejecuta Docker, evita la subred `172.17.0.0/16`. Este tutorial usa `172.20.0.0/24`. ## Paso 1: Crear un namespace y explorar su aislamiento Crea un namespace llamado `ns1`: ```bash sudo ip netns add ns1 ``` Lista los namespaces con nombre: ```bash ip netns list ``` ```output ns1 ``` `ip netns exec` ejecuta un comando dentro del namespace. Mira qué interfaces tiene: ```bash sudo ip netns exec ns1 ip -br link ``` ```output lo DOWN 00:00:00:00:00:00 ``` Solo existe un loopback, y además está apagado. No ve ninguna interfaz del host ni tiene rutas. Levanta el loopback, porque muchos programas lo necesitan aunque solo hablen consigo mismos: ```bash sudo ip netns exec ns1 ip link set lo up ``` Crea también el segundo namespace, que usarás en el paso 3: ```bash sudo ip netns add ns2 sudo ip netns exec ns2 ip link set lo up ``` ## Paso 2: Conectar el host y un namespace con un par veth Un par veth son dos interfaces virtuales unidas como por un cable: lo que entra por una sale por la otra. Crea un par y mueve un extremo dentro de `ns1`: ```bash sudo ip link add veth-test type veth peer name veth-test-ns sudo ip link set veth-test-ns netns ns1 ``` Asigna una dirección a cada extremo y levántalos: ```bash sudo ip addr add 10.99.0.1/30 dev veth-test sudo ip link set veth-test up sudo ip netns exec ns1 ip addr add 10.99.0.2/30 dev veth-test-ns sudo ip netns exec ns1 ip link set veth-test-ns up ``` Comprueba la conectividad desde el host: ```bash ping -c 2 10.99.0.2 ``` ```output 64 bytes from 10.99.0.2: icmp_seq=1 ttl=64 time=0.051 ms 64 bytes from 10.99.0.2: icmp_seq=2 ttl=64 time=0.039 ms ``` Esto funciona para un namespace, pero con muchos necesitarías una subred por par. Borra este enlace de prueba antes de continuar; al borrar un extremo, el otro desaparece también: ```bash sudo ip link del veth-test ``` ## Paso 3: Conectar varios namespaces con un bridge Un bridge Linux actúa como un switch virtual. Cada namespace se conecta a él con su propio par veth, y todos comparten la misma subred. Es exactamente lo que hace Docker con `docker0`. Crea el bridge y dale la IP que servirá de puerta de enlace a los namespaces: ```bash sudo ip link add br-ns type bridge sudo ip addr add 172.20.0.1/24 dev br-ns sudo ip link set br-ns up ``` Conecta `ns1`. El extremo `veth-ns1` se queda en el host y se enchufa al bridge; `eth0` va dentro del namespace (dentro puede llamarse igual que una interfaz del host, porque es otra pila de red): ```bash sudo ip link add veth-ns1 type veth peer name eth0 netns ns1 sudo ip link set veth-ns1 master br-ns up sudo ip netns exec ns1 ip addr add 172.20.0.10/24 dev eth0 sudo ip netns exec ns1 ip link set eth0 up sudo ip netns exec ns1 ip route add default via 172.20.0.1 ``` Conecta `ns2` de la misma forma: ```bash sudo ip link add veth-ns2 type veth peer name eth0 netns ns2 sudo ip link set veth-ns2 master br-ns up sudo ip netns exec ns2 ip addr add 172.20.0.20/24 dev eth0 sudo ip netns exec ns2 ip link set eth0 up sudo ip netns exec ns2 ip route add default via 172.20.0.1 ``` Comprueba que los dos namespaces se ven entre sí y alcanzan el host: ```bash sudo ip netns exec ns1 ping -c 2 172.20.0.20 sudo ip netns exec ns2 ping -c 2 172.20.0.1 ``` Consulta los puertos conectados al bridge: ```bash bridge link show master br-ns ``` ```output 8: veth-ns1@if2: mtu 1500 master br-ns state forwarding priority 32 cost 2 10: veth-ns2@if2: mtu 1500 master br-ns state forwarding priority 32 cost 2 ``` ## Paso 4: Dar salida a Internet con NAT Los namespaces tienen ruta por defecto hacia el host, pero el host no reenvía paquetes y, aunque lo hiciera, las IP `172.20.0.x` no son enrutables en Internet. Necesitas activar el reenvío IP y enmascarar (NAT) el tráfico que sale hacia fuera. Identifica la interfaz pública del host: ```bash ip route show default ``` ```output default via 203.0.113.1 dev eth0 proto static ``` Activa el reenvío IP de forma persistente: ```bash echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/60-ip-forward.conf sudo sysctl --system ``` Añade la regla de NAT para la subred de los namespaces cuando sale por `eth0` (sustituye el nombre por el de tu interfaz): ```bash sudo iptables -t nat -A POSTROUTING -s 172.20.0.0/24 -o eth0 -j MASQUERADE ``` Si UFW está activo, su política por defecto descarta el tráfico reenviado. Permite el reenvío del bridge hacia la interfaz pública: ```bash sudo ufw route allow in on br-ns out on eth0 ``` > Nota: si Docker está instalado, también fija la política de la cadena `FORWARD` en `DROP`. En ese caso añade la regla en la cadena que Docker reserva para el usuario: `sudo iptables -I DOCKER-USER -i br-ns -o eth0 -j ACCEPT` y `sudo iptables -I DOCKER-USER -i eth0 -o br-ns -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`. Comprueba la salida desde `ns1`: ```bash sudo ip netns exec ns1 ping -c 2 1.1.1.1 ``` ```output 64 bytes from 1.1.1.1: icmp_seq=1 ttl=57 time=1.42 ms ``` ## Paso 5: Configurar el DNS de cada namespace La conectividad ya funciona, pero la resolución de nombres falla. En Ubuntu 24.04, `/etc/resolv.conf` apunta a `127.0.0.53`, el resolvedor local de systemd-resolved, que escucha en el loopback del host y no es accesible desde otro namespace: ```bash sudo ip netns exec ns1 getent hosts ubuntu.com ``` El comando no devuelve nada. `ip netns exec` monta automáticamente los archivos de `/etc/netns//` sobre los de `/etc` para el comando que ejecuta, así que puedes dar a cada namespace su propio `resolv.conf`: ```bash sudo mkdir -p /etc/netns/ns1 /etc/netns/ns2 echo 'nameserver 1.1.1.1' | sudo tee /etc/netns/ns1/resolv.conf /etc/netns/ns2/resolv.conf ``` Vuelve a probar: ```bash sudo ip netns exec ns1 getent hosts ubuntu.com ``` ```output 185.125.190.20 ubuntu.com ``` ## Paso 6: Aplicar un firewall propio dentro de un namespace Las reglas de iptables también son independientes por namespace. Las que añadas dentro de `ns1` no afectan al host ni a `ns2`. Como ejemplo, arranca un servidor web de prueba dentro de `ns1` en segundo plano: ```bash sudo ip netns exec ns1 python3 -m http.server 8080 --bind 172.20.0.10 & ``` Desde `ns2` y desde el host responde: ```bash curl -sI http://172.20.0.10:8080 | head -n 1 ``` ```output HTTP/1.0 200 OK ``` Ahora aplica en `ns1` una política restrictiva: se acepta el tráfico de loopback y las respuestas a conexiones propias, y el puerto 8080 solo desde el host (`172.20.0.1`). Todo lo demás se descarta. ```bash sudo ip netns exec ns1 iptables -A INPUT -i lo -j ACCEPT sudo ip netns exec ns1 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo ip netns exec ns1 iptables -A INPUT -p tcp -s 172.20.0.1 --dport 8080 -j ACCEPT sudo ip netns exec ns1 iptables -P INPUT DROP ``` Desde el host sigue funcionando: ```bash curl -sI http://172.20.0.10:8080 | head -n 1 ``` Desde `ns2` ahora se agota el tiempo de espera: ```bash sudo ip netns exec ns2 curl -sI -m 3 http://172.20.0.10:8080 echo $? ``` ```output 28 ``` El código de salida `28` de curl indica tiempo de espera agotado. Revisa las reglas y sus contadores dentro de `ns1`: ```bash sudo ip netns exec ns1 iptables -L INPUT -v -n ``` Comprueba que el host no tiene ninguna de esas reglas: ```bash sudo iptables -L INPUT -n | grep 8080 ``` No debe devolver nada. Detén el servidor de prueba cuando termines: ```bash kill %1 ``` ## Paso 7: Inspeccionar y limpiar Para saber a qué namespace pertenece un proceso, compara el enlace de `/proc//ns/net` con el del host. `ip netns identify` hace esa comparación por ti con los namespaces con nombre: ```bash sudo ip netns exec ns1 sleep 300 & sudo ip netns identify "$(pgrep -n -x sleep)" ``` ```output ns1 ``` Los namespaces que crea Docker no aparecen en `ip netns list` porque no se registran en `/run/netns`. Para entrar en la red de un contenedor usa `nsenter` con el PID de su proceso principal: ```bash sudo nsenter --target "$(docker inspect -f '{{.State.Pid}}' nombre_contenedor)" --net ip -br addr ``` Nada de lo creado en este tutorial sobrevive a un reinicio salvo el reenvío IP del paso 4. Para eliminarlo antes, borra los namespaces (sus extremos veth desaparecen con ellos), el bridge, la regla de NAT y los archivos DNS: ```bash sudo ip netns del ns1 sudo ip netns del ns2 sudo ip link del br-ns sudo iptables -t nat -D POSTROUTING -s 172.20.0.0/24 -o eth0 -j MASQUERADE sudo rm -r /etc/netns/ns1 /etc/netns/ns2 ``` Si añadiste la regla de UFW, bórrala con `sudo ufw route delete allow in on br-ns out on eth0`. ## Solución de problemas **`RTNETLINK answers: File exists`.** La interfaz, la dirección o la ruta ya existe. Consulta el estado actual con `sudo ip netns exec ns1 ip addr` o `ip route` antes de volver a crearla. **El namespace llega al host pero no a Internet.** Comprueba en este orden: `sysctl net.ipv4.ip_forward` debe devolver `1`, la regla MASQUERADE debe usar el nombre correcto de la interfaz de salida (`sudo iptables -t nat -L POSTROUTING -v -n` muestra si sus contadores suben) y la cadena `FORWARD` no debe descartar el tráfico (`sudo iptables -L FORWARD -v -n`). **Ping funciona pero los nombres no se resuelven.** Falta `/etc/netns//resolv.conf` o el namespace no se creó con `ip netns`: el montaje automático solo lo hace `ip netns exec`. ## Conclusión Has construido a mano la red de un motor de contenedores: namespaces aislados, pares veth, un bridge como switch, NAT para salir a Internet, DNS por namespace y un firewall independiente dentro de cada uno. Con esta base puedes depurar la red de Docker o Kubernetes entrando en sus namespaces con `nsenter`, ejecutar servicios con `systemd` dentro de un namespace mediante la opción `NetworkNamespacePath=` o conectar namespaces de distintos servidores llevando el bridge a una red overlay VXLAN.