Esta pagina se ve mejor con JavaScript habilitado

Gestión de jails en FreeBSD con Iocage

 ·  🎃 kr0m

Iocage es un gestor de contenedores(jails) que hace uso de las mejores funcionalidades y tecnologías que nos ofrece FreeBSD. Este nos facilitará la gestión en todo el ciclo de vida de la jail, creación, destrucción y actualización.

El artículo se componde de varias partes:


Instalación

El primer paso será instalar el software:

pkg install py37-iocage

Podemos indicarle que nos muestre colores:

export IOCAGE_COLOR=TRUE

Para que sea permanente habrá que exportar la variable en la shell que utilicemos, en mi caso se trata de bash:

vi .bashrc

export IOCAGE_COLOR=TRUE

Si se trata de un servidor que contendrá muchos jails debemos montar el sistema de ficheros de descriptores de ficheros , de este modo el acceso será mas rápido:

mount -t fdescfs null /dev/fd

Para que sea permanente:

vi /etc/fstab

fdescfs /dev/fd fdescfs rw 0 0

Si tenemos mas de un zpool debemos indicarle a Iocage cual de ellos utilizar:

zpool list

NAME      SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
storage   928G  35.8G   892G        -         -     1%     3%  1.00x  ONLINE  -
zroot     109G  16.0G  93.0G        -         -     3%    14%  1.00x  ONLINE  -

En mi caso zroot:

iocage activate zroot

Nos bajamos la versión de FreeBSD que actuará como base de las jails:

iocage fetch

Press [Enter] to fetch the default selection: (12.1)
ENTER

Para proporcionar red a las Jails se utilizan alias en la interfaz del padre, al ser alias estas son ips del padre y de la Jail simultáneamente, esto implica ciertos problemas si bindeamos en todas las direcciones disponibles los servicios del padre, por ejemplo si lo hacemos con el servicio Ssh mientras la Jail tenga el servicio arrancado se servirá en esa ip el Ssh de la Jail, si se apaga el Ssh de la Jail se servirá el Ssh del padre, esto puede llevar a confusión.

Cualquier servicio del padre se debe bindear exclusivamente a su dirección ip, en la jail no hay problema ya que solo ve la ip asignada y con un wildcard se bindea a esta única ip existente.

En el padre debemos evitar los bindeos genéricos como estos:

ListenAddress 0.0.0.0  
listen *

Creación de una Jail

Creamos nuestra jail:

iocage create -r LATEST -n test boot=on

Comprobamos que esté up:

iocage list

+-----+---------+-------+--------------+--------------+
| JID |  NAME   | STATE |   RELEASE    |     IP4      |
+=====+=========+=======+==============+==============+
+-----+---------+-------+--------------+--------------+
| 5   | test    | up    | 12.1-RELEASE | -            |
+-----+---------+-------+--------------+--------------+

Podemos acceder a la consola con el comando console:

iocage console test
root@test:~ # hostname
test
exit

Iocage viene con varias jails listas para ser utilizadas, las llaman plugins, con el comando list --plugins --remote podemos ver que jails hay disponibles:

iocage list --plugins --remote

Algunas de las mas populares son:

+-------------------+-------------------+-------------------+------------------+
|       NAME        |    DESCRIPTION    |        PKG        |       ICON       |
+===================+===================+===================+==================+
| Bacula-server     | Manage, backup,   | bacula-server     | https://www.true |
+-------------------+-------------------+-------------------+------------------+
| GitLab            | DevOps lifecycle  | gitlab            | https://www.true |
+-------------------+-------------------+-------------------+------------------+
| Jenkins           | Open source build | jenkins           | https://www.true |
+-------------------+-------------------+-------------------+------------------+
| Nextcloud         | Suite of client-  | nextcloud         | https://www.true |
+-------------------+-------------------+-------------------+------------------+
| Zoneminder        | Closed-circuit    | zoneminder        | https://www.true |
+-------------------+-------------------+-------------------+------------------+

Asignación de dirección ip

En cuanto a la asignación de direcciones ip Iocage soporta dos modos sharedIP/Vnet, pero este último es considerado inestable por lo tanto nos centraremos en sharedIP.

Las ips de las jails se configurarán en el host padre de forma automática mediante alias al arrancar la Jail en cuestión.

Primero nos aseguramos de que la jail no tenga Vnet activada:

iocage get vnet test

0

Le asignamos una dirección ip:

iocage set ip4_addr="nfe0|IP_JAIL/24" test
iocage list

+-----+---------+-------+--------------+--------------+
| JID |  NAME   | STATE |   RELEASE    |     IP4      |
+=====+=========+=======+==============+==============+
+-----+---------+-------+--------------+--------------+
| 5   | test    | up    | 12.1-RELEASE | IP_JAIL      |
+-----+---------+-------+--------------+--------------+

Comprobamos que la jail conozca su ip:

iocage exec test ifconfig

nfe0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=8210b<RXCSUM,TXCSUM,VLAN_MTU,TSO4,WOL_MAGIC,LINKSTATE>
    ether 00:00:ca:fe:00:00
    inet IP_JAIL netmask 0xffffff00 broadcast 192.168.1.255
    media: Ethernet autoselect (1000baseT <full-duplex,master>)
    status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    groups: lo
ipfw0: flags=8800<SIMPLEX,MULTICAST> metric 0 mtu 65536
    groups: ipfw

Definición de dependencias de arranque

Iocage permite definir dependencias entre jails, de este modo hasta que no arranquen las dependencias no arrancará la jail en cuestión:

iocage set depends="dep1 dep2" test


Gestión de snapshots

Una de las funcionalidades mas interesantes son los snapshots, para crearlos ejecutaremos:

iocage snapshot -n testJail00 test
iocage snapshot -n testJail01 test

Para ver los snapshots de una jail:

iocage snaplist test

+-----------------+-----------------------+-------+------+
|      NAME       |        CREATED        | RSIZE | USED |
+=================+=======================+=======+======+
| testJail00      | Sun Mar 29 14:06 2020 | 92K   | 60K  |
+-----------------+-----------------------+-------+------+
| testJail00/root | Sun Mar 29 14:06 2020 | 1.33G | 264K |
+-----------------+-----------------------+-------+------+
| testJail01      | Sun Mar 29 14:14 2020 | 92K   | 0    |
+-----------------+-----------------------+-------+------+
| testJail01/root | Sun Mar 29 14:14 2020 | 1.33G | 220K |
+-----------------+-----------------------+-------+------+

NOTA: Podemos observar que hay dos snapshots, uno del directorio donde se encuentra la configuración de la Jail(config.json/fstab) y otro de la raíz de dicha Jail.

Si queremos revertir primero paramos la jail:

iocage stop test

Acto seguido realizamos el rollback:

iocage rollback -n testJail00 test

NOTA: Si no revertimos al último snapshot los snapshots intermedios serán borrados, en mi caso tenía los snapshots testJail00 y testJail01, al revertir al testjail00, testjail01 ha sido eliminado:

iocage snaplist test
+-----------------+-----------------------+-------+------+
|      NAME       |        CREATED        | RSIZE | USED |
+=================+=======================+=======+======+
| testJail00      | Sun Mar 29 14:06 2020 | 92K   | 0    |
+-----------------+-----------------------+-------+------+
| testJail00/root | Sun Mar 29 14:06 2020 | 1.33G | 0    |
+-----------------+-----------------------+-------+------+

Para eliminar snapshots ejecutaremos:

iocage snapremove -n testJail00 test


Instalación de software automáticamente

Es posible instalar de forma automática ciertos paquetes en una jail cuando es creada tan solo debemos preparar la lista en formato json:

vi pkgs.json

{
    "pkgs": [
    "ngrep",
    "tcpdump"
    ]
}

Arrancamos la jail:

iocage create -r LATEST -p pkgs.json -n test ip4_addr="nfe0|JAIL_IP/24"


Importación/Exportación de Jails

La funcionalidad de importar en Iocage está bugeada, consume toda la RAM+SWAP del sistema, como workaround se puede exportar de forma normal, pero la importación la tendremos que hacer mediante comandos de ZFS manualmente:

iocage export test
scp /zroot/iocage/images/test_2020-03-28.zip REMOTE_SERVER:/zroot/iocage/images/test_2020-03-28.zip

En el servidor receptor:

unzip /zroot/iocage/images/test_2020-03-28.zip
zfs recv -F zroot/iocage/jails/test < zroot/iocage/images/test_2020-03-28
zfs recv -F zroot/iocage/jails/test/root < zroot/iocage/images/test_2020-03-28_root


Puntos de montaje en Jails

Si queremos montar directorios externos dentro de la jail utilizaremos el comando fstab de Iocage, en mi caso monto el directorio /storage dentro de la jail(/mnt/storage):

iocage console test
mkdir /mnt/storage

iocage fstab -a test "/storage /mnt/storage nullfs rw 0 0"

Podemos consultar los puntos de montaje con:

iocage fstab -l test

+-------+-------------------------------------------------------------------------------------------+
| INDEX |                                        FSTAB ENTRY                                        |
+=======+===========================================================================================+
| 0     | /storage        /zroot/iocage/jails/test/root/mnt/storage       nullfs  rw      0       0 |
+-------+-------------------------------------------------------------------------------------------+

Consulta de recursos Jail

Otra opción muy útil es poder ver que recursos están ocupando cada jail:

iocage df

+---------+-------+------+------+-------+-------+
|  NAME   |  CRT  | RES  | QTA  |  USE  |  AVA  |
+=========+=======+======+======+=======+=======+
| test    | 1.04x | none | none | 396K  | 84.1G |
+---------+-------+------+------+-------+-------+

Tipos de Jails

Iocage soporta varios tipos de jails.

  • Clone: iocage create -r [RELEASE]
    Es el tipo de jail por defecto, cuando se crea una jail de este tipo se realiza un clon del snapshot de la RELEASE, consume poco espacio ya que la base es compartida entre jails y solo se guardan los datos que se cambian en su interior, cada jail de este tipo debe ser actualizada de forma independiente. Como las jails de este tipo tiene la RELEASE como base, no podremos eliminar la RELEASE hasta que hayamos eliminado todas las jails que dependan de esta.

  • Base: iocage create -r [RELEASE] -b
    Se trata de una jail generada a partir de una copia completa de la RELEASE pero hay ciertos directorios de la RELEASE que son montados dentro de la jail mediante nullfs, este tipo de jail ocupa menos espacio que las thick pero mas que las clone. Es el tipo ideal para parchear de forma masiva ya que mediante iocage update sobre una de las jails estaremos actualizando todas las que compartan RELEASE con esta. También se pueden actualizar todas las jails de esa RELEASE ejecutando iocage fetch RELEASE de nuevo.

  • Thick: iocage create -r [RELEASE] -T
    Se realiza una copia entera de la RELEASE ocupando mas espacio que los demás tipos, es una jail totalmente independiente de las demás, cada jail de este tipo debe ser actualizada de forma independiente.

  • Template
    Los templates son jails retocadas para servir como plantilla de despliegue rápido. Para generar un template a partir de una jail existente seguiremos los siguientes pasos:

iocage stop test
iocage set template=yes test

Podemos consultar los templates locales:

iocage list -t

+-----+------+-------+--------------+--------------+
| JID | NAME | STATE |   RELEASE    |     IP4      |
+=====+======+=======+==============+==============+
| -   | test | down  | 12.1-RELEASE | JAIL_IP      |
+-----+------+-------+--------------+--------------+

Para crear una jail a partir de un template:

iocage create -t test -n newtest

El proceso de conversión a template se puede revertir mediante el parámetro template:

iocage set template=no test

  • Empty: iocage create -e
    Son jails pensadas para testing o funcionalidades no soportadas, ideales para experimentar con RELEASES no soportadas o Linux-jails.

Normalmente utilizaremos jails de tipo clone a no ser que utilicemos templates donde debemos tener en cuenta que estos no podrán ser actualizados sin reiniciar las jails que descienden de este, para poder realizar updates en los templates sin tener que reinicar las jails estas tendrán que ser creadas de tipo Thick.

iocage create -T -t test -n newtest

Update

Como en cualquier sistema FreeBSD la actualización del sistema operativo se divide en dos partes, el sistema base y los paquetes/ports instalados.


Update BASE

Si nos mantenemos dentro de la misma versión bastará con:

iocage update JAILNAME

Para pasar de una versión a otra consultamos la última RELEASE disponible.

Si es una minor update, ej: 12.0 -> 12.1:

iocage upgrade JAILNAME -r 12.1-RELEASE
iocage update JAILNAME

Si es una major update ej: 12.1 -> 13.0, además de los pasos de una minor update debemos reinstalar los paquetes binarios/ports y terminar la actualización:
Si estamos funcionando con paquetes binarios:

iocage console JAILNAME
pkg-static upgrade -f
exit
iocage update JAILNAME

Si estamos funcionando con ports:

iocage console JAILNAME
git -C /usr/ports pull
cd /usr/ports
make fetchindex
for PORT in $(pkg info|awk '{print$1}'); do PORT_PATH=$(pkg info $PORT|grep Origin|awk '{print$3}') && echo PORT: $PORT - $PORT_PATH && cd /usr/ports/$PORT_PATH && export BATCH="yes" && make clean reinstall clean; done
exit
iocage update JAILNAME

NOTA: Las actualizaciones mediante Iocage realizan de forma automática un snapshot en cada actualización de este modo si algo saliese mal se podría revertir sin problemas.


Update PAQUETES/PORTS

Actualizar los paquetes binarios de una jail:

iocage exec JAILNAME 'ASSUME_ALWAYS_YES=yes pkg upgrade'

iocage exec JAILNAME 'ASSUME_ALWAYS_YES=yes pkg autoremove'

Actualizar los ports de una jail:

iocage console JAILNAME
git -C /usr/ports pull
for PORT in $(pkg info|awk '{print$1}'); do PORT_PATH=$(pkg info $PORT|grep Origin|awk '{print$3}') && echo PORT: $PORT - $PORT_PATH && cd /usr/ports/$PORT_PATH && export BATCH="yes" && make clean reinstall clean; done


Script actualización

Para que la actualización de las jails sea mas cómoda podemos escribir un script como el siguiente, este deja siempre el último snapshot por si fuese necesario revertir y los snapshots llamados PRESERVER*:

#!/usr/local/bin/bash
source /root/.scripts/cecho.sh

function sendTelegram {
	message=${@:1}
	curl -s -X POST https://api.telegram.org/bot535179217:AAGXRe1df_1WNgqxOCfC8VrCNKGqouhslLw/sendMessage -d chat_id=30418601 -d text="$message"
}

clear
cecho "Cyan" "<== Iocage Jail updater by kr0m ==>"

echo ""
echo ""
cecho "Cyan" ">> Converting basic_template to regular jail"
iocage set template=no basic_template
iocage start basic_template

for JAIL in $(iocage list|grep up|awk '{print$4}'); do
	echo ""
	echo ""
	cecho "Cyan" ">> Updating Base: $JAIL"
	iocage update $JAIL
done

echo ""
cecho "Green" "----------------------------------------------------"

for JAIL in $(iocage list|grep up|awk '{print$4}'); do
	echo ""
	echo ""
	cecho "Cyan" ">> Clearing $JAIL snapshots"
	SNAPSNUMBER=$(iocage snaplist $JAIL|grep -v root|grep -v '+'|grep -v 'NAME'|wc -l|awk '{print$1}')

	# Check testJail
	echo $JAIL |grep test_ 1>/dev/null
	if [ $? -eq 0 ]; then
		TESTJAIL=1
	else
		TESTJAIL=0
	fi
		
	if [ $SNAPSNUMBER -gt 0 ]; then
		# TestJail: Delete all snapshots
		if [ $TESTJAIL -eq 1 ]; then
			for SNAPTOREMOVE in $(iocage snaplist $JAIL|grep -v root|grep -v '+'|grep -v 'NAME'|awk '{print$2}'); do
				cecho "Cyan" "-- Removing: $SNAPTOREMOVE"
				iocage snapremove -n $SNAPTOREMOVE $JAIL
			done
		else
			# If you want to preserve some snapshot from being deleted in update process, name it PRESERVE
			# Additionally we will preserve las IOC update snapshot, it always will be present because script always execute iocage update $JAIL in previous step
			LAST_IOC_UPDATE=$(iocage snaplist $JAIL|grep ioc_update|grep -v 'root'|awk '{print$2}'|tail -n 1)
			for SNAPTOREMOVE in $(iocage snaplist $JAIL|grep -v root|grep -v '+'|grep -v 'NAME'|grep -v 'PRESERVE'|grep -v "$LAST_IOC_UPDATE"|awk '{print$2}'); do
				cecho "Cyan" "-- Removing: $SNAPTOREMOVE"
				iocage snapremove -n $SNAPTOREMOVE $JAIL
			done
		fi
	else
		cecho "Cyan" "-- No snapshots to remove"
	fi
done

echo ""
cecho "Green" "----------------------------------------------------"

for JAIL in $(iocage list|grep up|awk '{print$4}'); do
        echo ""
        echo ""
        cecho "Cyan" ">> Updating PKGs: $JAIL"
	iocage exec $JAIL 'ASSUME_ALWAYS_YES=yes pkg upgrade'
	echo ""
        cecho "Cyan" ">> Executing AUTO-REMOVE: $JAIL"
	iocage exec $JAIL 'ASSUME_ALWAYS_YES=yes pkg autoremove'
done

echo ""
echo ""
cecho "Cyan" ">> Converting basic_template jail to template"
iocage stop basic_template
iocage set template=yes basic_template

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating SpamAssasin: DrWho"
iocage exec DrWho 'sa-update -v'
iocage exec DrWho 'service sa-spamd restart'

echo ""
echo ""
cecho "Cyan" ">> Restarting Mail services: DrWho"
iocage exec DrWho 'service sendmail restart'
iocage exec DrWho 'service dovecot restart'

echo ""
cecho "Cyan" ">> Visit: https://mail.alfaexploit.com/?admin#/about"

echo ""
cecho "Cyan" ">> Checking if Mail system still works: DrWho"
DATE=$(date "+%d/%m/%Y %H:%M:%S")
#echo "DrWho updated: $DATE" | mail -s "DrWho updated: $DATE" kr0m@alfaexploit.com
echo -e "Subject: DrWho updated: $DATE" | sendmail -f root@alfaexploit.com kr0m@alfaexploit.com
sleep 10
grep -r "DrWho updated: $DATE" /zroot/iocage/jails/DrWho/root/var/mail/kr0m 1>/dev/null
if [ $? -ne 0 ]; then
	cecho "Red" "++ ERROR: Mail system is not working"
	MESSAGE="ERROR: Mail system is not working"
	sendTelegram $MESSAGE
else
	cecho "Cyan" ">> Mail system is working"
fi

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating Python PIP: rxWod"
iocage exec rxWod 'su -l kr0m -c "/usr/home/kr0m/rxWod/bin/python3.7 -m pip install --upgrade pip"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating git: rxWod"
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject && git status"'|grep 'nothing to commit, working tree clean' 1>/dev/null
if [ $? -eq 1 ]; then
	iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject && git stash"'
	iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject && git stash drop"'
fi
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject && git pull"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating Python libraries: rxWod"
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod && source bin/activate && cd rxWodProject/ && pip-upgrade -p all"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Making Django migrations: rxWod"
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod && source bin/activate && cd rxWodProject && python manage.py makemigrations"'
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod && source bin/activate && cd rxWodProject && python manage.py migrate"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating Yarn libraries: rxWod"
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject/ && yarn install --force"'
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject/ && yarn upgrade"'
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod/rxWodProject/ && yarn prod-build"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Collecting Django static files: rxWod"
iocage exec rxWod 'su -l kr0m -c "cd /home/kr0m/rxWod && source bin/activate && cd rxWodProject && python manage.py collectstatic --noinput"'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Restarting Daphne service: rxWod"
iocage exec rxWod '/usr/sbin/service daphne restart'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating owasp-modsecurity: Infinity"
iocage exec Infinity 'cd /usr/local/owasp-modsecurity-crs/ && git pull'

echo ""
cecho "Cyan" ">> Updating Hugo theme: Infinity"
iocage exec Infinity 'su -l kr0m -c "cd /home/kr0m/AlfaExploit/alfaexploit_zzo/ && git submodule update --remote --merge"'

echo ""
cecho "Cyan" ">> Redeploying Alfaexploit: Infinity"
iocage exec Infinity 'su -l kr0m -c "cd /home/kr0m/AlfaExploit/alfaexploit_zzo/ && hugo && rm -rf /usr/local/www/alfaexploit/* && cp -r public/* /usr/local/www/alfaexploit/"'

NOTA: El script cecho lo dejo un poco mas abajo, si no queremos utilizarlo tan solo debemos cambiar los cechos por echos.


Script nueva jail

Para que la creación de nuevas jails sea automática primero debemos crear una jail que servirá como base:

iocage create -r 12.2-RELEASE -n basic_template
iocage set ip4_addr=“nfe0|192.168.69.9/24” basic_template

Instalamos el software base y realizamos la configuración básica:

iocage console basic_template

Convertimos la jail en template:

iocage stop basic_template
iocage set template=yes basic_template

Ahora ya podemos automatizar la creación de jails con el siguiente script:

#!/usr/local/bin/bash
source /root/.scripts/cecho.sh

clear
cecho "Cyan" "<== Iocage Jail creator by kr0m ==>"

echo ""
echo ""
cecho "Green" "-- Jail name: $1"
cecho "Green" "-- IP address: $2"
if [ -z $3 ]; then
	cecho "Green" "-- VNET: NO"
	VNET=0
else
	if [ $3 == "vnet" ]; then
		cecho "Green" "-- VNET: YES"
		cecho "Yellow" "-- VNET: Remember to check configuration for bridge interface"
		VNET=1
	else
		cecho "Green" "-- VNET: NO"
		VNET=0
	fi
fi

echo ""
echo ""
cecho "Cyan" ">> Making basic checks"
if [ $# -ne 2 ] && [ $# -ne 3 ]; then
	cecho "Red" "++ ERROR: Script needs JAIL_NAME IP_ADDRESS VNET(optional) arguments"
	exit
fi

JAIL_NAME=$1
IP_ADDRESS=$2

cecho "Cyan" ">> Checking ip in correct net/range"
first_ip_address=$(echo $IP_ADDRESS|awk -F "." '{print$1}')
second_ip_address=$(echo $IP_ADDRESS|awk -F "." '{print$2}')
third_ip_address=$(echo $IP_ADDRESS|awk -F "." '{print$3}')
fourth_ip_address=$(echo $IP_ADDRESS|awk -F "." '{print$4}')

if [ $first_ip_address -eq 192 ] && [ $second_ip_address -eq 168 ] && [ $third_ip_address -eq 69 ] && [ $fourth_ip_address -lt 200 ]; then
    cecho "Green" "-- Correct ip net/range"
else
    if [ $first_ip_address -ne 192 ] || [ $second_ip_address -ne 168 ] || [ $third_ip_address -ne 69 ]; then
        cecho "Red" "++ ERROR: Incorrect ip address NET: $IP_ADDRESS"
	exit
    fi
    if [ $fourth_ip_address -ge 200 ]; then
        cecho "Red" "++ ERROR: Ip address in DHCP range: $IP_ADDRESS"
	exit
    fi
fi

cecho "Cyan" ">> Checking jail names"
for JAIL in $(iocage list|grep up|awk '{print$4}'); do
    if [ "$JAIL_NAME" == "$JAIL" ]; then
        cecho "Red" "++ ERROR: Already running jail with name: $JAIL_NAME"
        exit
    fi
done
cecho "Green" "-- Correct jail name"

cecho "Cyan" ">> Checking duplicated jail ips"
for IP in $(iocage list|grep up|awk '{print$10}'); do
    if [ "$IP_ADDRESS" == "$IP" ]; then
        cecho "Red" "++ ERROR: Already running jail with ip: $IP_ADDRESS"
        exit
    fi
done
cecho "Green" "-- Correct jail ip"

cecho "Cyan" ">> Checking if base template exists"
BASE_TEMPLATE_EXISTS=$(iocage list -t|grep 'basic_template'|awk '{print$4}'|wc -l|awk '{print$1}')
if [ $BASE_TEMPLATE_EXISTS -eq 1 ]; then
    cecho "Green" "-- Base template found"
else
    cecho "Red" "++ ERROR: Base template not found"
    exit
fi

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Deploying: $JAIL_NAME"
iocage create -T -t basic_template -n $JAIL_NAME
if [ $VNET -eq 1 ]; then
	iocage set vnet=on $JAIL_NAME
	#iocage set allow_raw_sockets="1" $JAIL_NAME
	iocage set defaultrouter=192.168.69.200 $JAIL_NAME
	iocage set ip4_addr="vnet0|$IP_ADDRESS/24" $JAIL_NAME
else
	#iocage set ip4_addr="bridge0|$IP_ADDRESS/24" $JAIL_NAME
	iocage set ip4_addr="nfe0|$IP_ADDRESS/24" $JAIL_NAME
fi
iocage start $JAIL_NAME

echo ""
cecho "Green" "----------------------------------------------------"

if [ $VNET -eq 1 ]; then
	echo ""
	echo ""
	cecho "Cyan" ">> Disabling FW: $JAIL_NAME"
	iocage exec $JAIL_NAME "sysrc firewall_enable=YES"
	iocage exec $JAIL_NAME "sysrc firewall_type=open"
fi

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Setting FQDN: $JAIL_NAME"
iocage exec $JAIL_NAME "sysrc hostname=$JAIL_NAME.alfaexploit.com"

cecho "Cyan" ">> Patching /etc/hosts: $JAIL_NAME"
iocage exec $JAIL_NAME "sed -i '' 's/$JAIL_NAME//g' /etc/hosts"
JAIL_NAME2=$(echo $JAIL_NAME | tr '[:upper:]' '[:lower:]')
if [ "$JAIL_NAME" == "$JAIL_NAME2" ]; then
	iocage exec $JAIL_NAME "sed -i '' 's/CUSTOM_ENTRY/$IP_ADDRESS\t\t$JAIL_NAME.alfaexploit.com $JAIL_NAME/g' /etc/hosts"
else
	iocage exec $JAIL_NAME "sed -i '' 's/CUSTOM_ENTRY/$IP_ADDRESS\t\t$JAIL_NAME.alfaexploit.com $JAIL_NAME $JAIL_NAME2.alfaexploit.com $JAIL_NAME2/g' /etc/hosts"
fi

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Restarting: $JAIL_NAME"
iocage stop $JAIL_NAME
iocage start $JAIL_NAME

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating Base: $JAIL_NAME"
iocage update $JAIL_NAME

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Clearing $JAIL_NAME snapshots"

N=$(iocage snaplist $JAIL_NAME|grep 'ioc_update'|grep -v root|grep -v '+'|grep -v 'NAME'|wc -l|awk '{print$1}')

if [ $N -gt 0 ]; then
    for SNAPTOREMOVE in $(iocage snaplist $JAIL_NAME|grep 'ioc_update'|grep -v root|grep -v '+'|grep -v 'NAME'|awk '{print$2}'); do
        cecho "Cyan" "-- Removing: $SNAPTOREMOVE"
	    iocage snapremove -n $SNAPTOREMOVE $JAIL_NAME
    done
else
    cecho "Cyan" "-- No snapshots to remove"
fi

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating PKGs: $JAIL_NAME"
iocage exec $JAIL_NAME 'ASSUME_ALWAYS_YES=yes pkg upgrade'
iocage exec $JAIL_NAME 'ASSUME_ALWAYS_YES=yes pkg autoremove'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Updating pip: $JAIL_NAME"

iocage exec $JAIL_NAME 'pip install --upgrade pip'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Configuring SendMail Stats: $JAIL_NAME"

iocage exec $JAIL_NAME 'cd /etc/mail && make'
echo "define(\`STATUS_FILE',\`/var/log/sendmail.stats')dnl" >> /zroot/iocage/jails/$JAIL_NAME/root/etc/mail/$JAIL_NAME.alfaexploit.com.mc
iocage exec $JAIL_NAME 'cd /etc/mail && make'
iocage exec $JAIL_NAME "cp /etc/mail/$JAIL_NAME.alfaexploit.com.cf /etc/mail/sendmail.cf"
iocage exec $JAIL_NAME 'service sendmail restart'

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Making last restart: $JAIL_NAME"
iocage stop $JAIL_NAME
iocage start $JAIL_NAME

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Red" ">> Remember to add $JAIL_NAME to Prometheus: /etc/hosts and /usr/local/etc/prometheus.yml: sendmail_exporter"
cecho "Red" ">> Remember to add fstab entry via iocage and CRON job for backups"

echo ""
cecho "Green" "----------------------------------------------------"

echo ""
echo ""
cecho "Cyan" ">> Jail $JAIL_NAME deployed and updated"

Una primera versión del script creaba jails de tipo clone pero esto corrompía las jails ya creadas a partir del template, al ser clone no se puede tocar la base compartida mientras está en marcha, apagando la jail y volviéndola a arrancar volvían a funcionar pero para evitar ese downtime se ha decidido crearlas de tipo Thick .

A continuación el script cecho :

cecho(){
    # Reset
    Color_Off='\033[0m'       # Text Reset
    
    # Regular Colors
    Black='\033[0;30m'        # Black
    Red='\033[0;31m'          # Red
    Green='\033[0;32m'        # Green
    Yellow='\033[0;33m'       # Yellow
    Blue='\033[0;34m'         # Blue
    Purple='\033[0;35m'       # Purple
    Cyan='\033[0;36m'         # Cyan
    White='\033[0;37m'        # White
    
    # Bold
    BBlack='\033[1;30m'       # Black
    BRed='\033[1;31m'         # Red
    BGreen='\033[1;32m'       # Green
    BYellow='\033[1;33m'      # Yellow
    BBlue='\033[1;34m'        # Blue
    BPurple='\033[1;35m'      # Purple
    BCyan='\033[1;36m'        # Cyan
    BWhite='\033[1;37m'       # White
    
    # Underline
    UBlack='\033[4;30m'       # Black
    URed='\033[4;31m'         # Red
    UGreen='\033[4;32m'       # Green
    UYellow='\033[4;33m'      # Yellow
    UBlue='\033[4;34m'        # Blue
    UPurple='\033[4;35m'      # Purple
    UCyan='\033[4;36m'        # Cyan
    UWhite='\033[4;37m'       # White
    
    # Background
    On_Black='\033[40m'       # Black
    On_Red='\033[41m'         # Red
    On_Green='\033[42m'       # Green
    On_Yellow='\033[43m'      # Yellow
    On_Blue='\033[44m'        # Blue
    On_Purple='\033[45m'      # Purple
    On_Cyan='\033[46m'        # Cyan
    On_White='\033[47m'       # White
    
    # High Intensity
    IBlack='\033[0;90m'       # Black
    IRed='\033[0;91m'         # Red
    IGreen='\033[0;92m'       # Green
    IYellow='\033[0;93m'      # Yellow
    IBlue='\033[0;94m'        # Blue
    IPurple='\033[0;95m'      # Purple
    ICyan='\033[0;96m'        # Cyan
    IWhite='\033[0;97m'       # White
    
    # Bold High Intensity
    BIBlack='\033[1;90m'      # Black
    BIRed='\033[1;91m'        # Red
    BIGreen='\033[1;92m'      # Green
    BIYellow='\033[1;93m'     # Yellow
    BIBlue='\033[1;94m'       # Blue
    BIPurple='\033[1;95m'     # Purple
    BICyan='\033[1;96m'       # Cyan
    BIWhite='\033[1;97m'      # White
    
    # High Intensity backgrounds
    On_IBlack='\033[0;100m'   # Black
    On_IRed='\033[0;101m'     # Red
    On_IGreen='\033[0;102m'   # Green
    On_IYellow='\033[0;103m'  # Yellow
    On_IBlue='\033[0;104m'    # Blue
    On_IPurple='\033[0;105m'  # Purple
    On_ICyan='\033[0;106m'    # Cyan
    On_IWhite='\033[0;107m'   # White

    printf "${!1}${2} ${Color_Off}\n"
}

Firewall

Como nota final debemos tener en cuenta que todas las reglas de firewall deben definirse en el host padre, cuando se haga referencia a "me" son todas las ips de los alias, por lo tanto las reglas genéricas se configurarán utilizando "me" y las mas específicas de cada servicio indicando la ip origen y destino de la jail.


Recomendaciones

Algunas recomendaciones son:

  • Es mas eficiente reiniciar las jails mediante iocage restart -s que hacer un stop/start
  • Cada cierto tiempo realizar limpieza de los snapshots antiguos sobretodo de las jails cuyos datos cambien muy a menudo.
Si te ha gustado el artículo puedes invitarme a un RedBull aquí