Aislamiento Avanzado con Network Namespaces en Linux

Los network namespaces de Linux son la tecnología fundamental detrás del aislamiento de red en contenedores Docker, Kubernetes y otros sistemas de virtualización, proporcionando pilas de red completamente independientes por proceso. Esta guía cubre la creación de namespaces, los pares veth, el enrutamiento entre namespaces, la conexión via bridges y los fundamentos del networking de contenedores.

Requisitos Previos

  • Linux con kernel 3.0+ (los namespaces de red están disponibles desde el kernel 2.6.24)
  • Acceso root
  • Paquetes iproute2 e iptables instalados
# Verificar que iproute2 está instalado
ip link help

# Instalar si es necesario
apt install -y iproute2 iptables

Conceptos de Network Namespaces

Cada network namespace tiene su propio:

  • Interfaces de red (con sus propias MACs e IPs)
  • Tabla de enrutamiento independiente
  • Reglas iptables propias
  • Socket loopback propio
  • Tabla ARP separada

El namespace por defecto es el del host (default o 1). Los namespaces adicionales están aislados completamente a menos que los conectes explícitamente.

Creación y Gestión de Namespaces

# Crear un nuevo network namespace
ip netns add ns-web

# Listar todos los namespaces
ip netns list

# Ejecutar un comando dentro de un namespace
ip netns exec ns-web ip link list

# Verificar que el namespace tiene su propio loopback (inicialmente DOWN)
ip netns exec ns-web ip link show lo

# Levantar el loopback dentro del namespace
ip netns exec ns-web ip link set lo up

# Abrir una shell completamente dentro del namespace
ip netns exec ns-web bash
# (dentro de esta shell, todos los comandos de red son en el namespace ns-web)
exit

# Crear múltiples namespaces para un ejemplo completo
ip netns add ns-web
ip netns add ns-db
ip netns add ns-cache

# Eliminar un namespace
ip netns del ns-cache

# Ver el namespace de un proceso en ejecución
ls -la /proc/1/ns/net  # El proceso 1 (init)
ls -la /proc/$(pgrep nginx)/ns/net  # El proceso de nginx

Pares Veth

Los pares veth (virtual ethernet) son el mecanismo para conectar namespaces:

# Crear un par veth - dos interfaces virtuales conectadas entre sí
# Todo lo que entra por veth-host sale por veth-ns y viceversa
ip link add veth-host type veth peer name veth-ns

# Mover uno de los extremos al namespace
ip link set veth-ns netns ns-web

# Verificar: veth-host está en el host, veth-ns en el namespace
ip link show veth-host
ip netns exec ns-web ip link show veth-ns

# Asignar IPs a ambos extremos
ip addr add 192.168.100.1/24 dev veth-host
ip link set veth-host up

ip netns exec ns-web ip addr add 192.168.100.2/24 dev veth-ns
ip netns exec ns-web ip link set veth-ns up
ip netns exec ns-web ip link set lo up

# Probar la conectividad entre el host y el namespace
ping -c 3 192.168.100.2

# Desde el namespace hacia el host
ip netns exec ns-web ping -c 3 192.168.100.1

Enrutamiento entre Namespaces

Conectar dos namespaces mediante un tercer namespace como router:

# Topología: ns-web --- ns-router --- ns-db
# ns-web: 10.0.1.0/24, ns-db: 10.0.2.0/24

# Crear los namespaces
ip netns add ns-web
ip netns add ns-router
ip netns add ns-db

# Enlace ns-web <-> ns-router
ip link add veth-web type veth peer name veth-router-web
ip link set veth-web netns ns-web
ip link set veth-router-web netns ns-router

# Enlace ns-router <-> ns-db
ip link add veth-db type veth peer name veth-router-db
ip link set veth-db netns ns-db
ip link set veth-router-db netns ns-router

# Configurar IPs - lado ns-web
ip netns exec ns-web ip addr add 10.0.1.10/24 dev veth-web
ip netns exec ns-web ip link set veth-web up
ip netns exec ns-web ip link set lo up

# Configurar IPs - lado ns-router (hacia ns-web)
ip netns exec ns-router ip addr add 10.0.1.1/24 dev veth-router-web
ip netns exec ns-router ip link set veth-router-web up

# Configurar IPs - lado ns-router (hacia ns-db)
ip netns exec ns-router ip addr add 10.0.2.1/24 dev veth-router-db
ip netns exec ns-router ip link set veth-router-db up
ip netns exec ns-router ip link set lo up

# Habilitar el reenvío IP en el namespace router
ip netns exec ns-router sysctl -w net.ipv4.ip_forward=1

# Configurar IPs - lado ns-db
ip netns exec ns-db ip addr add 10.0.2.10/24 dev veth-db
ip netns exec ns-db ip link set veth-db up
ip netns exec ns-db ip link set lo up

# Añadir rutas por defecto en ns-web y ns-db apuntando al router
ip netns exec ns-web ip route add default via 10.0.1.1
ip netns exec ns-db ip route add default via 10.0.2.1

# Verificar la conectividad: ns-web debe poder llegar a ns-db
ip netns exec ns-web ping -c 3 10.0.2.10
ip netns exec ns-db ping -c 3 10.0.1.10

Conexión mediante Linux Bridge

Un bridge permite conectar múltiples namespaces como si estuvieran en el mismo switch:

# Crear un bridge en el host
ip link add br-containers type bridge
ip link set br-containers up
ip addr add 172.20.0.1/24 dev br-containers

# Crear y conectar el namespace ns1
ip netns add ns1
ip link add veth-ns1 type veth peer name veth-br-ns1
ip link set veth-ns1 netns ns1
ip link set veth-br-ns1 master br-containers  # Conectar al bridge
ip link set veth-br-ns1 up

ip netns exec ns1 ip addr add 172.20.0.10/24 dev veth-ns1
ip netns exec ns1 ip link set veth-ns1 up
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip route add default via 172.20.0.1

# Crear y conectar el namespace ns2
ip netns add ns2
ip link add veth-ns2 type veth peer name veth-br-ns2
ip link set veth-ns2 netns ns2
ip link set veth-br-ns2 master br-containers
ip link set veth-br-ns2 up

ip netns exec ns2 ip addr add 172.20.0.20/24 dev veth-ns2
ip netns exec ns2 ip link set veth-ns2 up
ip netns exec ns2 ip link set lo up
ip netns exec ns2 ip route add default via 172.20.0.1

# Verificar comunicación entre los dos namespaces a través del bridge
ip netns exec ns1 ping -c 3 172.20.0.20
ip netns exec ns2 ping -c 3 172.20.0.10

# Ver los dispositivos conectados al bridge
bridge link show br-containers

Reglas de Firewall por Namespace

# Las reglas iptables son independientes por namespace

# En el namespace ns-web, bloquear todo excepto HTTP y HTTPS
ip netns exec ns-web iptables -P INPUT DROP
ip netns exec ns-web iptables -P FORWARD DROP
ip netns exec ns-web iptables -P OUTPUT ACCEPT

# Permitir conexiones establecidas
ip netns exec ns-web iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Permitir HTTP y HTTPS desde la red interna
ip netns exec ns-web iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 80 -j ACCEPT
ip netns exec ns-web iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 443 -j ACCEPT

# Permitir ping (ICMP)
ip netns exec ns-web iptables -A INPUT -p icmp -j ACCEPT

# Verificar las reglas del namespace
ip netns exec ns-web iptables -L -v -n

# NAT: compartir la IP del host con los namespaces (salida a internet)
# Habilitar IP forwarding en el host
sysctl -w net.ipv4.ip_forward=1

# Añadir la regla MASQUERADE en el host (no en el namespace)
iptables -t nat -A POSTROUTING -s 172.20.0.0/24 -o eth0 -j MASQUERADE

Networking de Contenedores en la Práctica

Este es exactamente el mecanismo que usa Docker internamente:

# Ver cómo Docker gestiona los namespaces de red
# Docker crea un namespace por cada contenedor
docker run -d --name mi-contenedor nginx

# Obtener el PID del contenedor
DOCKER_PID=$(docker inspect mi-contenedor --format '{{.State.Pid}}')

# Acceder al namespace de red del contenedor desde el host
nsenter --target $DOCKER_PID --net -- ip addr show

# Ver las interfaces del contenedor desde el host
ls /proc/$DOCKER_PID/ns/

# Ver los pares veth creados por Docker
ip link show | grep veth

# Simular lo que hace Docker internamente:
# 1. Docker crea un bridge (docker0)
ip link show docker0

# 2. Para cada contenedor, crea un par veth
# 3. Un extremo va al namespace del contenedor (eth0 dentro)
# 4. El otro extremo se conecta al bridge docker0

# Crear manualmente un "contenedor" sin Docker
unshare --net bash  # Crear un nuevo namespace y ejecutar bash en él
# (dentro del nuevo namespace)
ip link show  # Solo verás lo (loopback), sin interfaces del host
ip link set lo up
exit

Solución de Problemas

# Listar todos los network namespaces del sistema
ip netns list

# Ver los procesos en cada namespace
for ns in $(ip netns list | awk '{print $1}'); do
    echo "=== Namespace: $ns ==="
    ip netns exec $ns ip addr show
    echo ""
done

# Ver namespaces de procesos específicos
ls /proc/*/ns/net | xargs -I{} sh -c 'echo {} && readlink {}'

# Verificar la conectividad entre dos namespaces
ip netns exec ns1 ping -c 3 -W 1 172.20.0.20

# Ver la tabla ARP dentro de un namespace
ip netns exec ns1 arp -n

# Capturar tráfico en una interfaz dentro de un namespace
ip netns exec ns1 tcpdump -i veth-ns1 -v

# Verificar las rutas dentro de un namespace
ip netns exec ns1 ip route show

# Error "RTNETLINK answers: File exists" al añadir IP
# La IP ya está asignada, eliminarla primero
ip netns exec ns1 ip addr del 172.20.0.10/24 dev veth-ns1
ip netns exec ns1 ip addr add 172.20.0.10/24 dev veth-ns1

# Limpiar todos los namespaces de prueba
ip netns del ns1
ip netns del ns2
ip netns del ns-web
ip netns del ns-router
ip netns del ns-db
ip link del br-containers

Conclusión

Los network namespaces de Linux son la base sobre la que se construye todo el networking de contenedores moderno, desde Docker hasta Kubernetes. Dominar su funcionamiento te permite entender y depurar problemas de red en cualquier plataforma de contenedores, diseñar topologías de red personalizadas y construir entornos de prueba de red complejos sin hardware físico. La combinación de namespaces, pares veth y bridges Linux proporciona toda la flexibilidad necesaria para implementar cualquier arquitectura de red virtualizada.