miércoles, 19 de octubre de 2016

Linux Containers #LXC



Virtualización 

La virtualización nos permite ejecutar diferentes sistemas operativos a la vez, en una misma máquina física. De alguna manera, emulamos una máquina para cada sistema. Existen diferentes tipos de virtualización. Las habituales, del tipo VirtualBox, simulan una máquina completa y, en ella, instalamos el sistema operativo.


Otro concepto a tener en cuenta es el de hypervisor. No es más que un programa que permite que, múltiples sistemas operativos, compartan un único host hardware.

Otro tipo de virtualización, es la virtualización por Sistema Operativo. En este caso, es el sistema operativo quien se encarga de crear los contenedores, que alojarán los diferentes sistemas. Éste es el tipo de virtualización de los Linux Containers.

Es interesante la virtualización, desde el punto de vista de la seguridad, porque nos permite aislar diferentes aplicaciones y/o servicios, sin necesidad de utilizar diferentes máquinas reales, con lo que reducimos el impacto, en caso de una intrusión.

Linux Containers

Los Linux Containers no son una máquina virtual, son entornos virtuales, con su propio espacio de procesos y de nombres. Se basan en cgroups, que es una funcionalidad propia del kernel Linux. Esto se traduce en que, los Linux Containers, sólo alojarán sistemas operativos GNU/Linux.

Esta virtualización nos permite aislar los procesos y recursos de una manera mucho más simple que con máquinas virtuales ,y su objetivo, es que tengamos una instalación estándar de un sistema operativo, sin necesidad  de tener varias instancias del kernel. Esto hace que, el sistema operativo virtualizado, funcione a velocidad nativa, cosa que no ocurriría si hubiese que emular una máquina completa y tener varias instancias de kernels. En este sentido, podríamos considerarlos como una “vuelta de tuerca” a los clásicos chroot, permitiendo más aislamiento y más flexibilidad.

Arquitectura

El kernel nos proporciona la funcionalidad para separar el espacio de nombres y procesos. Libvirt, nos proporciona la interfaz encargada de gestionar los contenedores.

Disponemos de varias implementaciones para la gestión de los contenedores que, de alguna manera, utilizan libvirt para su gestión:

  • LXC: Son utilidades en el espacio de usuario para la gestión de contenedores. No utiliza libvirt directamente, pero es una dependencia a la hora de compilarlo.
  • Virt-Manager: Es una herramienta gráfica para la gestión de máquinas virtuales, soporta KVM, XEN y LXC. Utiliza, para el caso de los contenedores, libvirt directamente. Es necesario ejecutar el daemon libvirt, que actuará a modo de hypervisor.
  • Docker: Es un motor que nos permite empaquetar una aplicación y sus dependencias en un contenedor.
  • Systemd: Nos proporciona una herramienta, systemd-nspawn, con la que podemos crear contenedores, que nos vendrán bien para testear. Este método no es adecuado para separar servicios en entornos de producción, por temas de seguridad. La configuración con los anteriores, nos permite crear contenedores que sí nos vendrán bien para separar servicios o aplicaciones en ambientes de producción.
Vamos a realizar una comparación con máquinas virtuales completas:

La primera diferencia es que, en cada máquina virtual, ha de existir una instancia del kernel. Esto no es necesario con los contenedores, con lo que, la velocidad de cada contenedor, es mayor.

Una ventaja de las máquinas virtuales,  es la posibilidad disponer diferentes sistemas operativos, no sólo basados en linux. Sin embargo, el consumo de recursos por cada máquina virtual, es mucho mayor que con contenedores. Podemos crear muchos más contenedores por host, que máquinas virtuales.

En el caso de máquinas virtuales, al ser sistemas operativos independientes, implica mayor separación y seguridad. Si un kernel falla, no queda todo el sistema inhabilitado. Pero presenta el inconveniente de la comunicación de cada máquina virtual con el resto del sistema, que será más compleja. Aunque aún no existe un aislamiento total, que proporciona características similares a las máquinas virtuales, la intención es llegar a ese punto, proporcionando un sistema operativo completo por contenedor.

¿Cómo crear y manejar contenedores?

Vamos a crear un contenedor básico, con conexión a red, utilizando un “puente” (bridge), con nuestra interfaz de red. Nos servirá para enjaular aplicaciones y servicios, funcionando como una especie de chroot, pero mucho más versátil.



Instalamos los paquetes necesarios en Arch Linux:
   
$ sudo pacman -Syu lxc bridge-utils arch-install-scripts



Para configurar la interfaz de red, vamos a utilizar netctl.    

$ sudo cp /etc/netctl/examples/bridge /etc/netctl/

Editamos el archivo creado y lo adaptaremos a nuestra configuración.
Para conocer cuál es nuestra interfaz de red:

ip link show

Ahora, en el archivo /etc/netctl/bridge, generamos nuestra configuración. En el ejemplo, las IPs quedarían de las siguiente manera:

    El host -> 192.168.0.21
    El bridge -> 192.168.0.22
    La puerta de enlace -> 192.168.0.1
    El contenedor -> 192.168.0.23

Suponemos que el host ya tiene conectividad y que fue configurado con netctl. Vamos a crear la interfaz para el bridge con el siguiente contenido (el archivo /etc/netctl/bridge):

   
Description="Example Bridge connection"
Interface=br0
Connection=bridge
BindsToInterfaces=(eth0)
IP=static
Address=192.168.0.22
Gateway=192.168.0.1

## Ignore (R)STP and immediately activate the bridge
#SkipForwardingDelay=yes

Suponemos que nuestra interfaz real es eth0. Ya, tan sólo falta levantar la interfaz:

$ sudo netctl start bridge

Una vez hecho esto, vamos a crear el contenedor. Podemos utilizar las plantillas de OpenVZ. El paquete LXC, dispone de varias plantillas para crearlos, que podemos ver en /usr/share/lxc/templates/. En  nuestro caso:

   
$ sudo lxc-create -n archninfa -t archlinux -- -P vim,dhclient

Hemos creado un contenedor llamado archninfa, de tipo archlinux y, además del software base, le hemos añadido los paquetes vim y dhclient.

Las opciones que van después de --  son las específicas de la plantilla utilizada. Para que ver un listado de las opciones, bastará ejecutar:

   
$ lxc-create -t archlinux -h

El contenedor se ha creado en /var/lib/lxc/nombrecontenedor. El fichero de configuración, config, se encuentra dentro de este directorio y, en rootfs, es donde se hará el chroot, es decir, es directorio raíz.

Otra forma de crear contenedores es mediante imágenes:

$ sudo lxc-create -t downdload -n archninfa

Descarga una lista de imágenes disponibles y podemos elegir la que deseemos.
Las imágenes están disponibles en https://images.linuxcontainers.org/.

Una vez hecho esto, editamos el archivo de configuración y la adaptamos a nuestras necesidades,  y la configuración de red:
   
...
...

#networking
lxc.network.type=veth
lxc.network.link=br0
lxc.network.flags=up
lxc.network.name=eth0
lxc.network.ipv4=192.168.0.23/24
lxc.network.ipv4.gateway=192.168.0.1
...
...

Y ya, tan solo debemos arrancar el contenedor. Para comprobar que todo va bien:

   
$ sudo lxc-start -n archninfa -F

Para arrancar en modo demonio:
   
$ sudo lxc-start -n archninfa

Para acceder al contenedor creado:
   
$ sudo lxc-console -n archninfa

Para arrancarlo, en modo demonio, con systemd:

$ sudo systemctl start lxc@archninfa

Si solo quieres ejecutar un comando dentro del contenedor sin entrar en una consola:

$ sudo lxc-attach -n archninfa -- nano

Me parece que también funciona así:

$ sudo lxc-attach -n archninfa nano

Te ejecutará el nano del contenedor, sin necesidad de entrar en él con ssh o vía consola
   
$ sudo systemctl start lxc@archninfa

Si queremos que el contenedor arranque al inicio del sistema:
   
$ sudo systemctl enable lxc@archninfa

También deberá estar el bridge creado, así que:
   
$ sudo netctl enable bridge 

Nota: Para poder utilizar  una tarjeta inalámbrica debemos realizar algunas modificaciones en el bridge:

- No establecemos ninguna interfaz física en BindsToInterfaces.
- No añadimos un gateway.
- Añadimos una regla al firewall:

iptables -t nat -A POSTROUTING -o Nombre_de_la_interfaz -j MASQUERADE



¡Espero que os haya gustado!;-)

 

2 comentarios: