Seguridad

Creación manual de contenedores mediante espacios de nombres: espacios de nombres de red

Durante el último año, he estado escribiendo para Enable Sysadmin sobre algunos de los espacios de nombres de Linux más utilizados. A lo largo de la serie, observé algunas características muy útiles integradas en el kernel de Linux:

  • Con el espacio de nombres UTS, puede cambiar el nombre de host o el dominio del Servicio de información de red (NIS) informado por un proceso. Esta función es principalmente útil en el contexto de los contenedores y no es muy útil por sí misma.

  • Los espacios de nombres PID son útiles para aislar procesos entre sí. Esto es valioso si tiene un entorno complejo en el que utiliza la función de congelación del kernel de Linux, que le permite suspender un proceso y reanudarlo en un host diferente. También permite ejecutar múltiples versiones de aplicaciones que se basan en árboles de procesos aislados.
  • Montar espacios de nombres Hay una serie de espacios de nombres que se utilizan para crear espacios de nombres que no tienen acceso completo al sistema de archivos del host. Esto es útil no solo para crear y administrar procesos en el host, sino también para crear contenedores de Linux.
  • Los espacios de nombres de usuario permiten que un proceso se ejecute como un usuario específico. Entre otras cosas, esto es útil para crear espacios de nombres como usuarios sin privilegios que aún pueden ser root en el espacio de nombres. Existen limitaciones obvias en las tareas que pueden contener estos espacios de nombres, ya que no están enraizados en el host. Los espacios de nombres de usuario se usan con mayor frecuencia junto con otros espacios de nombres para proporcionar un mayor nivel de aislamiento que de otra manera.

Este artículo analiza los espacios de nombres que más me preguntan: espacio de nombres de redComo sugiere el nombre, puede usar este espacio de nombres para administrar la pila de red dentro del espacio de nombres. Vería los siguientes casos de uso para saber por qué es posible que desee hacer algo como esto:

  1. Configure un espacio de nombres de red punto a punto, mostrando que un espacio de nombres puede comunicarse con un servidor web de Python en otro espacio de nombres.
  2. Configurar DHCP dentro de un espacio de nombres para mostrar que los espacios de nombres pueden aislar el tráfico de difusión, incluso de los hosts.
  3. Combine el espacio de nombres de red y Open vSwitch para aislar dos o más procesos que se comunican mediante la red sin permitir el acceso externo (o incluso host) a estos procesos.

Ajuste inicial

Estoy usando una máquina virtual (VM) CentOS Stream para este tutorial. Necesitas instalar algunos paquetes para seguirlo. En general, recomiendo instalar todo desde el administrador de paquetes:

$ sudo dnf install centos-release-nfv-openvswitch
$ sudo dnf install openvswitch-selinux-extra-policy \
openvswitch2.15 \
dnsmasq \
dhcp-client \
net-tools

Sin embargo, estoy usando CentOS Stream 9 y, en el momento de escribir este artículo, Network Functions Virtualization (NFV) se rellena el repositorio, pero no forma parte del repositorio predeterminado. Si intenta instalar un metapaquete que normalmente proporciona estos repositorios, es posible que obtenga un error.

Si esto te sucede, descarga el paquete directamente desde el repositorio. Cuando lo use, instale el paquete DHCP para su uso posterior:

wget http://mirror.stream.centos.org/SIGs/9-stream/nfv/x86_64/openvswitch-2/Packages/o/openvswitch-selinux-extra-policy-1.0-30.el9s.noarch.rpm
wget http://mirror.stream.centos.org/SIGs/9-stream/nfv/x86_64/openvswitch-2/Packages/o/openvswitch2.15-2.15.0-51.el9s.x86_64.rpm
dnf install -y dnsmasq dhcp-client net-tools
dnf install openvswitch-selinux-extra-policy-1.0-30.el9s.noarch.rpm openvswitch2.15-2.15.0-51.el9s.x86_64.rpm

Ejemplo 1: Configuración de un espacio de nombres de red punto a punto

El primer ejemplo es crear dos espacios de nombres de red que se comuniquen entre sí. Esta configuración es similar al uso de un cable cruzado al conectar dos controladores de interfaz de red.

En la imagen de abajo, cada extremo del «cable» está etiquetado. Recomiendo usar nombres obvios, aunque su elección de convención de nomenclatura es completamente arbitraria.

(Steve Owens, CC BY-SA 4.0)

Para ello, establezca algunos Variable ambiental Haga la vida más fácil y el código más repetible. Puede crear múltiples variables a la vez colocando lo que desea en un archivo de texto sin formato y luego importándolos al shell usando el comando fuente (o un solo punto):

$ cat << EOF >> vars
namespace1=client
namespace2=server
command='python3 -m http.server'
ip_address1="10.10.10.10/24"
ip_address2='10.10.10.20/24'
interface1=veth-client
interface2=veth-server
EOF
$ . vars

Para este ejemplo, el servidor ejecuta un servidor web Python 3 básico. Solo necesita verificar que la conexión es válida.

Lo primero que debe hacer es crear el espacio de nombres.A diferencia de otros comandos, puede directamente ip Pedido. Cree el espacio de nombres:

sudo ip netns add $namespace1
sudo ip netns add $namespace2

Verifique que el espacio de nombres exista:

$ ip netns list
server
client

Genial, tienes algunos espacios de nombres. Esto no es muy útil en sí mismo.Si ejecuta el comando en uno de los nuevos espacios de nombres, verá que solo existe la dirección de bucle invertido y está marcada como Abajo:

$ sudo ip netns exec $namespace2 ip ad
1: lo:  mtu 65536 qdisc noop state 
DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

El siguiente paso es crear un «cable ethernet» virtual creando un enlace entre los dos espacios de nombres, como este:

$ sudo ip link add \
       ptp-$interface1 \
       type veth \
       peer name ptp-$interface2

si tu corres ip link Ejecute el comando en el host y verá los dos enlaces adicionales creados por este comando:

$ ip link
1: lo:  mtu 65536 [...]
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0:  [...]
    link/ether 52:54:00:57:53:77 brd ff:ff:ff:ff:ff:ff
3: [email protected]:  [...]
    link/ether d6:d9:74:95:64:6f brd ff:ff:ff:ff:ff:ff
4: [email protected]:  [...]
    link/ether f6:4a:a4:70:86:67 brd ff:ff:ff:ff:ff:ff

La salida puede parecer extraña.incluso si escribió un comando porque especificó peer En el comando de enlace, crea un enlace con la siguiente convención: @Por eso te recomiendo elegir nombres descriptivos para tus enlaces. Una vez que tenga algunos enlaces, puede ser difícil hacer un seguimiento de su propósito.

En este punto, ha creado enlaces, pero no los ha asignado a ninguna parte. Continúe y asigne las interfaces a sus respectivos espacios de nombres:

sudo ip link set ptp-$interface1 netns $namespace1
sudo ip link set ptp-$interface2 netns $namespace2

Después de ejecutar este comando, el host ya no tiene acceso a estos enlaces porque están asignados a diferentes espacios de nombres de red.si vuelves a ejecutar ip netns exec comando, puede ver que su nuevo espacio de nombres tiene dispositivos, pero todavía están marcados como Abajo y no hay dirección IP para comunicarse con:

$ sudo ip netns exec $namespace2 ip ad
1: lo:  mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: [email protected]:  mtu 1500 qdisc noop state [...]
    link/ether d6:d9:74:95:64:6f brd ff:ff:ff:ff:ff:ff link-netns client

A continuación, asigne una IP y abra la interfaz:

sudo ip netns exec $namespace1 ip addr \
     add $ip_address1 dev ptp-$interface1
sudo ip netns exec $namespace2 ip addr \
     add $ip_address2 dev ptp-$interface2
sudo ip netns exec $namespace1 ip link set \
     dev ptp-$interface1 up
sudo ip netns exec $namespace2 ip link set \
     dev ptp-$interface2 up

Finalmente, inicie el servidor web de Python 3 $namespace2 y probarlo:

sudo ip netns exec $namespace2 $command &

porque tú eres $ip_addres2, tienes opciones. Puedes hacer algunos trucos de Bash para eliminarlo:

sudo ip netns exec $namespace1 curl `echo $ip_address2 |awk -F '/' '{print $1}'`:8000

O simplemente puede ingresar la dirección IP en el comando:

sudo ip netns exec $namespace1 curl 10.10.10.20:8000

Durante la instanciación del servidor web de Python, recibe una lista de directorios de todos los directorios que están activos.Porque no hay ningún dispositivo Ethernet en el host original 10.x.x.x red, no puede llegar al nuevo espacio de nombres:

$ curl --connect-timeout 3 10.10.10.20:8000
curl: (28) Connection timed out after 3001 milliseconds

Incluso si tiene la interfaz configurada correctamente para esa subred porque está utilizando un «cable» de punto a punto, solo los espacios de nombres vinculados a esa interfaz pueden comunicarse entre sí.

[ Learn what it takes to develop cloud-native applications using modern tools such as microservices. Download the eBook Kubernetes-native microservices with Quarkus and MicroProfile. ]

Agregar servicio DHCP

Sobre la base del ejemplo anterior, cree más variables para ayudar al ejemplo de DHCP:

ip_range_start="10.10.10.100"
ip_range_end='10.10.10.150'
netmask='255.255.255.0'

Para que DHCP funcione correctamente, debe iniciar el dispositivo de bucle invertido en el espacio de nombres del servidor:

sudo ip netns exec $namespace2 ip addr add 127.0.0.1/8 dev lo
sudo ip netns exec $namespace2 ip link set lo up

A continuación, empieza dnsmasq Proceso en el nuevo espacio de nombres:

sudo ip netns exec $namespace2 \
     dnsmasq --interface=ptp-$interface2 \
     --dhcp-range=$ip_range_start,$ip_range_end,$netmask

Finalmente, elimine la dirección IP adjunta a $namespace1 entonces empezar dhclient Asegúrese de que puede establecer una conexión con el servidor DHCP:

sudo ip netns exec $namespace1 ip addr\
     del $ip_address1 dev ptp-$interface1

Ahora ve una IP diferente en la interfaz interior $namespace1:

$ sudo ip netns exec $namespace1 ip ad

1: lo:  mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: [email protected]:  mtu 1500 [...]
    link/ether 9a:61:93:29:73:d5 brd ff:ff:ff:ff:ff:ff link-netns server
    inet 10.10.10.124/24 brd 10.10.10.255 scope global dynamic ptp-veth-client
       valid_lft 3468sec preferred_lft 3468sec
    inet6 fe80::9861:93ff:fe29:73d5/64 scope link 
       valid_lft forever preferred_lft forever

¡Pero espera! Es posible que haya notado que su host se comporta de manera extraña al realizar consultas de DNS.Eso es porque no hizo nada para evitar que se sobrescribiera el espacio de nombres de la red. /etc/resolv.confHay varias formas de solucionar este problema. Puede crear un nuevo espacio de nombres de montaje usando las habilidades que aprendió en mi artículo anterior. De hecho, esta es probablemente la forma más «similar a un contenedor» para lograr el resultado correcto.

Sin embargo, si planea usar espacios de nombres de red en su computadora de escritorio o portátil, existe otro enfoque que podría ser más útil.

Esta ip-netns(8) La página del manual dice:

Para las aplicaciones que conocen el espacio de nombres de la red, la convención es buscar primero en /etc/netns/NAME/ el archivo de configuración de la red global y luego en /etc/. Por ejemplo, si desea utilizar una versión diferente de /etc/resolv.conf para el espacio de nombres de red utilizado para aislar la VPN, asígnele el nombre /etc/netns/myvpn/resolv.conf.

Debido a la anulación de DHCP /etc/resolv.confSolo necesitas touch archivos en el directorio correspondiente. Para completar, puede crear un directorio para ambos espacios de nombres, pero esto no es obligatorio.Esta servidor El espacio de nombres no recibirá DHCP, por lo que no se requiere ningún ajuste /etc/resolv.conf documento.

Cree un directorio en el sistema de archivos del host:

sudo mkdir -p /etc/netns/{$namespace1,$namespace2}

ahora puedes tocar resolv.conf por cliente Espacios de nombres:

sudo touch /etc/netns/$namespace{1,2}/resolv.conf

Con este archivo, el espacio de nombres de la red original utilizará /etc/resolv.conf mientras que el resto del espacio de nombres de la red hará referencia resolv.conf archivos en subdirectorios de cada espacio de nombres.

Ejemplo 2: Configuración de varios espacios de nombres de red mediante Open vSwitch

Si bien es bueno poder tener servicios que se ejecuten localmente y solo se comuniquen entre sí, la mayoría de las cargas de trabajo en contenedores involucran múltiples servicios que trabajan juntos para lograr sus objetivos. Al igual que una computadora física, para conectar múltiples espacios de nombres a la misma red de manera elocuente, debe implementar un conmutador.

Muchos conmutadores virtuales están disponibles para este propósito. Para esta demostración, implementaré Open vSwitch. Antes de continuar, recomiendo eliminar cualquier espacio de nombres que haya creado anteriormente, o simplemente puede reiniciar el host (ya que los espacios de nombres no sobreviven a los reinicios de manera predeterminada). Puede usar la política de DHCP discutida anteriormente, pero nuevamente configurar una IP estática es un poco más fácil.

Aquí está la declaración de la variable:

namespace1=east
namespace2=west
namespace3=central
command='python3 -m http.server'
ip_address1="10.10.10.10/24"
ip_address2='10.10.10.20/24'
ip_address3='10.10.10.30/24'
interface1=east
interface2=west
interface3=central

Cree el espacio de nombres como antes:

sudo ip netns add $namespace1
sudo ip netns add $namespace2
sudo ip netns add $namespace3

Inicie Open vSwitch y cree un puente de red:

sudo systemctl start openvswitch
sudo ovs-vsctl add-br NAMESPACE-DEMO

Como antes, crea algunos veth peer interfaz, pero esta vez especifique un lado del «cable» porque agregará el otro extremo al conmutador virtual. Cuando termine se verá así:

(Steve Owens, CC BY-SA 4.0)

Agregar la interfaz debería resultarle familiar ahora:

sudo ip link add $interface1 type veth peer name ovs-$interface1
sudo ip link set $interface1 netns $namespace1
sudo ip link add $interface2 type veth peer name ovs-$interface2
sudo ip link set $interface2 netns $namespace2
sudo ip link add $interface3 type veth peer name ovs-$interface3
sudo ip link set $interface3 netns $namespace3

Puede verificar que el comando funciona como se espera mirando uno de los espacios de nombres:

$ sudo ip netns exec $namespace1 ip link

1: lo:  mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: [email protected]:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 32:5f:80:91:34:40 brd ff:ff:ff:ff:ff:ff link-netnsid 0

A continuación, agregue el puerto al conmutador:

sudo ovs-vsctl add-port NAMESPACE-DEMO ovs-$interface1
sudo ovs-vsctl add-port NAMESPACE-DEMO ovs-$interface2
sudo ovs-vsctl add-port NAMESPACE-DEMO ovs-$interface3

También puede ver los puertos utilizados por Open vSwitch:

$ sudo ovs-vsctl list-ports NAMESPACE-DEMO
ovs-central
ovs-east
ovs-west

Como puede ver en la salida, las interfaces existen y están adjuntas a sus respectivos componentes. Sin embargo, no tienen direcciones IP ni están activas actualmente.

Inicie el dispositivo:

sudo ip link set dev ovs-$interface1 up
sudo ip link set dev ovs-$interface2 up
sudo ip link set dev ovs-$interface3 up

Luego configure:

sudo ip netns exec $namespace1 ip addr add $ip_address1 dev $interface1
sudo ip netns exec $namespace2 ip addr add $ip_address2 dev $interface2
sudo ip netns exec $namespace3 ip addr add $ip_address3 dev $interface3
sudo ip netns exec $namespace1 ip link set dev $interface1 up
sudo ip netns exec $namespace2 ip link set dev $interface2 up
sudo ip netns exec $namespace3 ip link set dev $interface3 up

A continuación, haz algo rápido ping Prueba para verificar que el espacio de nombres funciona como se esperaba:

$ sudo ip netns exec $namespace3 ping -c 2 10.10.10.20
$ sudo ip netns exec $namespace1 ping -c 2 10.10.10.20

Finalmente, mire la tabla del Protocolo de resolución de direcciones (ARP) para cada espacio de nombres:

$ sudo ip netns exec $namespace1 arp
Address                  HWtype  HWaddress           Flags Mask            Iface
10.10.10.20              ether   ce:29:53:b3:b1:bd   C                     east

$ sudo ip netns exec $namespace2 arp
Address                  HWtype  HWaddress           Flags Mask            Iface
10.10.10.10              ether   32:5f:80:91:34:40   C                     west
10.10.10.30              ether   72:4c:7b:f3:87:fe   C                     west

$ sudo ip netns exec $namespace3 arp
Address                  HWtype  HWaddress           Flags Mask            Iface
10.10.10.20              ether   ce:29:53:b3:b1:bd   C                     central

ping por espacio de nombres Oeste espacio de nombres, por lo que tiene entradas para otras dos direcciones IP en su tabla ARP, y ambas este y central tienen una entrada en su tabla ARP.

¡estupendo! Entonces, tiene un montón de espacios de nombres que pueden comunicarse entre sí a través de Open vSwitch. Si también desea habilitar la comunicación entre el host y el espacio de nombres, siga un patrón similar:

  1. crear veth peer.
  2. Agregue IP al lado del host del «cable».
  3. Configurar el anfitrión veth interfaz para UP.
  4. Conecte el otro extremo del «cable» al Open vSwitch.
  5. Establezca el puerto Open vSwitch en UP.

Los siguientes comandos realizarán estas acciones:

sudo ip link add host-if type veth peer name ovs-host-if
sudo ip addr add 10.10.10.40/24 dev ovs-host-if
sudo ip link set dev ovs-host-if up
sudo ovs-vsctl add-port NAMESPACE-DEMO ovs-host-if
sudo ip link set dev ovs-host-if up

Ahora puede comunicarse con procesos en todos los espacios de nombres conectados a Open vSwitch:

ping -c 2 10.10.10.20

Espacio de nombres manual

Este es un tema enorme, y cubro mucho en esta publicación:

  1. Deje que dos espacios de nombres de red separados se comuniquen directamente entre sí
  2. Establecer DHCP en lugar de IP estática
  3. Cree múltiples espacios de nombres de red y conéctelos todos usando Open vSwitch

He demostrado varias técnicas para crear e interactuar con el espacio de nombres net, combinándolo con el conocimiento previo del usuario y los espacios de nombres mnt para aislar aún más los procesos. Puede combinar estos espacios de nombres (pid, usuario, mnt y net) para crear una capa de aislamiento muy poderosa en cualquier sistema Linux. Si bien los contenedores de Linux brindan esta funcionalidad de una manera más fácil de usar, siempre es importante dominar los componentes básicos.

Si bien, por diseño, un contenedor debe tener solo un proceso (aunque, por supuesto, puede haber más), la creación de su propio espacio de nombres le brinda la flexibilidad de personalizar su entorno según sus necesidades específicas, todo sin descargar ni ejecutar los archivos binarios instalados intencionalmente. Los espacios de nombres proporcionan una interfaz muy personalizable para tareas como aislar el tráfico de aplicaciones.

En mi próximo artículo, usaré todo lo que aprendiste en este artículo para ejecutar la VPN en un espacio de nombres privado que creaste a mano.

LEER  Su televisor inteligente podría dar a los piratas informáticos un vistazo a su mundo

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba