Guacamole, docker y shorewall

Y es que según voy aprendiendo más cosas sobre docker, su gestión de redes y el cortafuegos, voy retocando servicios para eliminar capas.

Y la primera que va a caer es precisamente docker-compose. No dudo de que tenga un gran valor pero toquetea la red para propocionar aislamiento a los contenedores y me está poniendo de los nervios. Está muy bien que te asegures de que están en otra red, con su puente y todo, pero es que necesito que además de estar aislados tengan acceso a la red interna. Porque si no, no serán útiles.

Y luego está que docker-compose añade una capa más con su correspondiente aprendizaje que no voy a emplear más que para este servicio por ahora. Prefiero entender mejor qué hace docker y cómo gestionarlo.

He creado un script y un archivo de configuración para gestionar la ejecución de ambos contenedores. Funciona bien y no es complicado de entender.


#!/usr/bin/env bash

#   Variables
VERSION=0.4
DOCKER=/usr/bin/docker
CONFIG=/etc/guacamole/guacamole.conf
GUACAMOLE_ENV=/etc/guacamole/guacamole.env
NAME=
IMAGE=

#   Funciones
_log() {
    echo "$* " >&2 
}

_die() {
    echo "$0 ($VERSION): ERROR " "$*" >&2 
    exit 1
}

_read_env() {
	ARCHIVO=$1
	ENV=""

	if [ ! -r "$ARCHIVO" ]; then
		_die "no puedo leer $ARCHIVO"
	fi

	for var in $(egrep -v '/#' $ARCHIVO)
	do
		ENV+="-e=$var "
	done

	echo "$ENV"
}

_read_config() {
	if [ ! -r "$CONFIG" ]; then
	    _die "necesito el archivo de configuración en $CONFIG"
	else
		_log "Cargando configuración de $CONFIG ... "
		. "$CONFIG"

	fi
}

_start_docker() {
    DOCKER_START="-d --rm=true --name=$NAME \
	    $DNS \
	    --network=bridge \
	    --publish=$PORTS"
	
    _log "Arrancando contenedor de $NAME($IMAGE) ... "
    $DOCKER run $DOCKER_START $EXTRA $IMAGE
}

_stop_docker() {
    case "$IAM" in
    guacamole)
        NAME=$GUACAMOLE_NAME
        ;;
    guacd)
        NAME=$GUACD_NAME
        ;;
    esac

    _log "Parando contenedor $NAME ..." 
    $DOCKER stop $NAME
}

#   Quién soy 
case $(basename $0) in 
guacamole-ctl)
    IAM="guacamole"
    ;;
guacd-ctl)
    IAM="guacd"
    ;;
*)
    _die "nombre de programa $0 erróneo"
esac

#   Parámetros
OP=$1

case "$OP" in 
start) 
	_read_config
    case "$IAM" in 
    guacamole)
        NAME=$GUACAMOLE_NAME
        IMAGE=$GUACAMOLE_IMAGE
        PORTS=$GUACAMOLE_PORTS
        EXTRA=$(_read_env $GUACAMOLE_ENV)
        EXTRA+="--link $GUACD_NAME -v /etc/guacamole:/etc/guacamole"
    ;;
    guacd)
        NAME=$GUACD_NAME
        IMAGE=$GUACD_IMAGE
        PORTS=$GUACD_PORTS
    esac
    _start_docker
    ;;
stop)
	_read_config
    _stop_docker
    ;;
*)
	_log "uso: $0 {start|stop}"
	exit 0
	;;	
esac




Este script se instala junto a un enlace simbólico a sí mismo con el nombre del otro contenedor –guacd– y arranca o detiene según sea invocado. Los detalles curiosos están en el archivo de configuración con los parámetros para arrancar el contenedor.


#
#   Parámetros de arranque y parada del servicio
#   guacamole empleando contenedores
#

#   Compartidos
DNS="--dns=192.168.100.1"

#   Guacamole
GUACAMOLE_IMAGE=guacamole/guacamole
GUACAMOLE_NAME=guacamole
GUACAMOLE_PORTS="127.0.0.1:8080:8080"

#   Guacd
GUACD_IMAGE=guacamole/guacd
GUACD_NAME=guacd
GUACD_PORTS="4822:4822"

Se respeta la red que crea y mantiene docker pero se les indica que el servidor de nombres es el de la red interna. Además, se fuerza a que guacamole publique los puertos en la dirección local. Esto lo mismo no es estrictamente necesario en otras configuraciones pero esta máquina hace de enrutador y tiene puentes y varias rutas que me estaban dando problemas. Hacerlo así e indicar al servidor web que va a hacer de proxy que se conecte vía http://localhost:8080 funciona perfectamente.

Luego está la parte del cortafuegos. Como he dicho en esa máquina la cosa está un poco complicada y la solución más efectiva que he encontrado empleando shorewall es:

  1. Definir una zona llamada dock de tipo ipv4 (archivo /etc/shorewall/zones).
  2. Asignar a la zona el interface docker con las opciones bridge (archivo /etc/shorewall/interfaces)
  3. En la normativa de conexión entre zonas definir lo siguiente en el archivo /etc/shorewall/policy:
    • Permitir tráfico entre la zona dock y la zona del cortafuegos $FW.
    • Permitir tráfico entre la red local loc y el cortafuegos $FW.

Y con ésto lo único que me queda es que guacamole emplee el directorio LDAP para validar usuarios. No es que sea esencial pero me gustaría tenerlo porque llevo tiempo detrás de instalar un mecanismo de acceso único (SSO) y supongo que me facilitará el trabajo.