sábado, 24 de octubre de 2020

Servidor de correo: Correo entrante

La máquina no va a existir porque sí. Vamos a ver que todo tiene un porqué. En este caso, va a ser un servidor de correo.

En principio basta con instalar Postfix. Lo configuramos como Sitio de Internet y configuramos correctamente el nombre de la máquina. Lo interesante vendrá después.

Ya que tenemos un cortafuegos, vamos a tener que autorizar las conexiones que correspondan al correo electrónico:

iptables -A INPUT -p tcp -m tcp --dport smtp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp --dport smtp -j ACCEPT
ip6tables -A INPUT -p tcp -m tcp --dport smtp -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p tcp -m tcp --dport smtp -j ACCEPT

Y activar la regla de Postfix correspondiente en fail2ban: en la sección [postfix] del fichero /etc/fail2ban/jail.local añado la línea

enabled = true

De momento no voy a poner modos más agresivos ni jaulas extra. En vez de cargar la jaula a mano, como en la entrada anterior, también basta con

/etc/init.d/fail2ban reload

Bendito sysvinit.

El Postfix en realidad se configura solo, con lo anterior ya recibiría correo. Pero no lo queremos "simplemente" para eso. En mi caso, este servidor va a encargarse de todo el correo de un dominio, y evidentemente no voy a crear todos los usuarios que tiene ese dominio como usuarios UNIX (sería de locos). Así que tienen que ser usuarios virtuales. Lo más cómodo es que el propio dominio sea un dominio virtual.

Para ello, en /etc/postfix/main.cf añadimos estas líneas (donde, evidentemente, he cambiado el dominio) al final:

#Dominios virtuales
virtual_mailbox_domains = example.com
virtual_mailbox_base = /var/mail/v
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 1000
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_alias_maps = hash:/etc/postfix/virtual

Los usuarios que tienen que tener cuenta se definen en el fichero /etc/postfix/vmailbox que tenemos que crear y que queda así:

# /etc/postfix/vmailbox:
# Recuerda ejecutar postmap /etc/postfix/vmailbox
# despues de modificar este fichero
compras@example.com	    example.com/compras/
ventas@example.com	    example.com/ventas/
legal@example.com	    example.com/legal/
# Descomenta la línea de demajo para tener un buzon catch-all.
# @example.com	        example.com/catchall/
#...Se pueden añadir otros dominios...

Los otros usuarios a tener en cuenta son esos usuarios que todo dominio debe tener, que redirigimos en el fichero /etc/postfix/virtual que también tenemos que crear:

#/etc/postfix/virtual
# Recuerda ejecutar postmap /etc/postfix/virtual
# despues de modificar este fichero
postmaster@example.com          postmaster
root@example.com                root

A Postfix no se le da nada bien crear los directorios Maildir que hemos indicado, y además es quisquilloso con los permisos. Hay que crear el directorio padre (que al crearse en /var/mail aparecerá como root:mail con permisos 2750) y para cada usuario crear el suyo con unos permisos específicos:

mkdir /var/mail/v
chmod g+w /var/mail/v
mkdir /var/mail/v/example.com
chmod g+w /var/mail/v/example.com
mkdir /var/mail/v/example.com/compras
chown 5000:5000 /var/mail/v/example.com/compras
mkdir /var/mail/v/example.com/ventas
chown 5000:5000 /var/mail/v/example.com/ventas
mkdir /var/mail/v/example.com/legal
chown 5000:5000 /var/mail/v/example.com/legal

...y así sucesivamente. Ya solo necesitamos activarlo todo, primero los mapas y después el propio Postfix:

postmap /etc/postfix/vmailbox
postmap /etc/postfix/virtual
/etc/init.d/postfix/restart

Y ya podemos empezar a recibir correo, para los usuarios definidos, en el nuevo servidor.

miércoles, 21 de octubre de 2020

Aumentando la seguridad

En la entrada anterior apliqué unas reglas de cortafuegos muy monas, y activé fail2ban.

Pero dichas reglas son solamente para IPv4, y hay que repetirlas en IPv6. Pero ojo, que en IPv6 el ICMP no es simplemente un protocolo de apoyo, es parte fundamental de la infraestructura, y si los paqutes no pasan, no hay comunicación (véase RCF 4890):

ip6tables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p tcp -m tcp --dport ssh -m state --state NEW,ESTABLISHED -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-replay -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type ttl-exceeded -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type router-solicitation -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type router-advertisement -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-solicitation -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-advertisement -j ACCEPT
ip6tables -J INPUT DROP
ip6tables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p tcp -m tcp --dport http -j ACCEPT
ip6tables -A OUTPUT -p tcp -m tcp --dport https -j ACCEPT
ip6tables -A OUTPUT -p tcp -m tcp --dport domain -j ACCEPT
ip6tables -A OUTPUT -p udp -m udp --dport domain -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-reply -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type packet-too-big -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type ttl-exceeded -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type parameter-problem -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type router-solicitation -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type router-advertisement -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-solicitation -j ACCEPT
ip6tables -A OUTPUT -p ipv6-icmp -m icmp6 --icmpv6-type neighbour-advertisement -j ACCEPT
ip6tables -J OUTPUT DROP
ip6tables -J FORWARD DROP

Para conseguir que las reglas se mantengan al reiniciar, basta con instalar el paquete iptables-persistent.

Por fail2ban para IPv6 no tenemos que preocuparnos, ya que funciona automáticamente.

La otra cosa pendiente es que no vale de mucho parar a un atacante por unos minutos si después vuelve a las andadas. La configuración por defecto de fail2ban prohíbe la entrada de paquetes durante 10 minutos. Esto para los ataques casuales, pero a los atacantes serios no. Pero subir el tiempo puede dejarle fuera a uno mismo si tiene problemas con la configuración del teclado, por ejemplo.

La solución a este tipo de problemas es prohibir el acceso de nuevo, por más tiempo, a los reincidentes. Siguiendo (un poco) los pasos de The art of web, creamos dos jaulas nuevas, cada una de ellas más dura que la anterior.

En /etc/fail2ban/jail.local añadimos estas líneas:

[sshd-fail2ban-L1]
# 3 veces en 6 horas, 24 horas
enabled = true
port = ssh
filter = sshd-fail2ban-L1
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 21600
bantime = 86400

[sshd-fail2ban-L2]
# 3 veces en 7 días, 30 días
enabled = true
port = ssh
filter = sshd-fail2ban-L2
logpath = /var/log/fail2ban.log
maxretry = 3
findtime = 604800
bantime = 2592000

A continuación, creamos el fichero /etc/fail2ban/filter.d/sshd-fail2ban-L1.conf con este contenido (ojo al espacio final en ignoreregex) como filtro:

[DEFAULT]
[Definition]
failregex = \[sshd\] Ban <HOST>
ignoreregex =

Y este otro contenido (la misma advertencia) como el fichero /etc/fail2ban/filter.d/sshd-fail2ban-L2.conf como el otro filtro:

[DEFAULT]
[Definition]
failregex = \[sshd-fail2ban-L1\] Ban <HOST>
ignoreregex =

Ahora basta con un par de órdenes y ya tenemos un sistema un poco más robusto:

fail2ban-client add sshd-fail2ban-L1
fail2ban-client start sshd-fail2ban-L1
fail2ban-client add sshd-fail2ban-L2
fail2ban-client start sshd-fail2ban-L2

lunes, 12 de octubre de 2020

Asegurando el servidor

El servidor que migré ayer a Devuan va a estar abierto a Internet, ese lugar tan grande. Así que no puede ser fácilmente accesible.

Lo primero será que no se pueda entrar como root mediante ssh (el acceso por consola debe seguir siendo posible, para un posible rescate). Así que eliminamos esa opción:

PasswordAuthentication no
PermitRootLogin without-password

Claro que antes nos hemos asegurado el acceso mediante clave pública ssh, metiéndola en /root/.ssh/authorized_keys.

El siguiente paso es poner un sistema que nos asegure que los niñatillos que se dedican a probar accesos se queden fuera. Para esto, yo suelo elegir fail2ban. Basta con instalarlo y, muy importante, copiar el fichero /etc/fail2ban/jail.conf como /etc/fail2ban/jail.local.

Inicialmente activaré solo la regla relativa a SSH, ya que es el único servicio que estará activo en la máquina. Para ello, en /etc/fail2ban/jail.local añadiremos

enabled=true

en la sección [sshd] de/etc/fail2ban/jail.local.

Tras ello, las reglas de cortafuegos.

Realmente, ¿qué tráfico necesita tu máquina? Es algo que tienes que pensar dos veces, y luego prohibe todo lo demás.

Los paquetes que correspondan a conexiones de salida ya establecidas, conexiones abiertas por nosotros, hay que permitirlos, o no habrá comunicación:

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

El tráfico de entrada SSH evidentemente hay que permitirlo:

-A INPUT -p tcp --dport ssh -m state --state NEW,ESTABLISHED -j ACCEPT

Y queremos que funcione el ping:

-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

¿Algo más? De momento no. todo lo demás, prohibido.

-P INPUT DROP

El tráfico de salida también hay que permitirlo, pero solo para lo que lo necesitemos. En primer lugar, el tráfico de salida correspondiente a conexiones de entrada ya establecidas:

-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

En nuestro caso, queremos las actualizaciones de paquetes y otras consultas de ese estilo a sitios web:

-A OUTPUT -p tcp --dport http -j ACCEPT
-A OUTPUT -p tcp --dport https -j ACCEPT

Evidentemente tiene que funcionar el DNS, o no hacemos nada:

-A OUTPUT -p tcp --dport domain -j ACCEPT
-A OUTPUT -p udp --dport domain -j ACCEPT

Y también queremos que funcione el ping:

-A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
-A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

Todo lo demás, incluso de salida, prohibido.

-P OUTPUT DROP

La tabla FORWARD no la utilizaremos, ya que este sistema no es un enrutador:

-P FORWARD DROP

Con esto nos aseguramos un cortafuegos bastante restrictivo, y sin embargo utilizable.

domingo, 11 de octubre de 2020

Vamo' a migra' un server

Quiero poner un servicio de correo electrónico donde no está. Y eso es una migración. Y lo voy a hacer de on-premises a eso que llaman "la nube". Aunque lo local sea mi servidor casero y la nube sea un servidor contratado con un servicio de hosting.

Así que lo primero es pagar por, e instalar el servidor remoto. De entre las opciones disponible, he elegido Debian 9 (Stretch), porque me será sencillo migrarlo a Devuan.

Así que una vez creado el servidor, de nombre mercurio, el mensajero de los dioses, le instalo lo mínimo que requiero siempre (es decir, vim, htop y aptitude) y a actualizarlo a Devuan.

El primar paso desde Stretch, siguiendo las indicaciones oficiales de Devuan es instalar sysvinit-core y eliminar libpam-systemd, para sentar las bases del nuevo sistema de arranque. Con esto puede que el escritorio no arranque, pero en serio, ¿alguien tiene un escritorio en un servidor recién instalado? (Ejem, SuSE, ejem) En cambio, aseguramos que el sistema sí arranque. Particularmente, en este tipo de operaciones yo siempre las eliminaciones las hago con purge y no con delete.

El siguiente paso sería cambiar las fuentes, pero yo no lo hago directamente. En su lugar creo un fichero /etc/apt/sources.list.d/beowulf que contiene las líneas que hay que añadir. Así queda todo más claro.

Se actualizan las listas de paquetes, se instala el llavero y se actualizan otra vez. Aquí el documento peca de optimista: te la han podido colar con un MITM justo en ese momento. ¡Ah!

Vamos a evitar esto. Primero, vemos e importamos (ojo, si no la importamos será como si nada) la clave maestra de Devuan con

gpg --keyserver keys.gnupg.net --search-keys BB23C00C61FC752C

tal y como indica la página de la distribución. No me creas a mi, comprueba por ti mismo la huella que tienes que importar. Cuando ya la tienes, la puedes ver y jugar con ella, pero lo importante es que puedes usarla para autentificar paquetes:

gpg --export BB23C00C61FC752C | apt-key add -

En este momento ya se puedes realizar el aptitude update, instalar el paquete devuan-keyring, realizar el segundo aptitude update, y seguir. Para ello hay que instalar libtinfo6 y pasar a meternos en harina. Ahí viene el primer paso de la migración real: la paquetería.

aptitude upgrade

"Sí a todo".

Luego hacer el primer reinicio. Ojo, que puedes perder el acceso remoto al servidor en este paso, si no te has asegurado de que todas las tarjetas de red van a levantar, las IPs están bien asignadas, etc. El renombrado de ens* a eth* puede dar problemas.

Tras el reinicio instalamos eudev y hacemos un full-upgrade, para cambiar lo que queda de la paquetería:

aptitude full-upgrade

Con esto vemos desaparecer systemd, y dejar el sistema listo para los siguientes pasos. Finalmente, puedes sustituir libsystemd0 por libelogind0 y ya no quedará rastro.

Lo siguiente que hago es asegurarme de que todos los paquetes que hay instalados tienen una razón de ser: recorro todo aptitude marcando los paquetes como auto, y los que aparecen para borrar porque no son dependencias de otro decido si los quiero o no.

viernes, 11 de mayo de 2018

Las cintas no mueren, pero matan.

En la empresa para la que trabajo como administrador de copias de seguridad, Atos, realizamos copias de seguridad en cinta para nuestros clientes, como casi en todas partes. Tanto de clientes enormes como de pequeñas sedes remotas.

En una de estas sedes remotas utilizamos un tipo de cintas que es un estándar empresarial, las Linear Tape-Open Ultrium, si bien de cuarta generación (LTO-4, no es necesario especificar Ultrium ya que nunca se produjeron comercialmente las Accelis), introducidas en 2007, con una capacidad nativa de 800GB.

Y los 800GB son la única medida real del tamaño de la cinta. HP las publicita como cintas de 1,6TB, suponiendo que darán una compresión de 2:1 pero IBM indica realmente que son cintas de 800GB que dan 1,6TB con compresión (suponiendo otra vez 2:1).

Y la realidad es que la capacidad de las cintas depende mucho del tipo de datos que se meta en ellas. Para hacer backups de máquinas completas, con su Sistema Operativo lleno de ficheros binarios, un factor de compresión de 2:1 es excesivamente optimista. En esa sede remota de la que hablo, las cintas de 800GB están cargando entre 970GB y 1020GB (de 1,21:1 a 1,27:1, muy lejos de 2:1), con lo cual los backups completos semanales de 1140GB de esa sede que, según la publicidad, deberían caber en un cartucho, necesitan dos.

Siempre, siempre, un administrador de backup debe trabajar a partir de datos históricos de compresibilidad, y no fiarse de la versión edulcorada de los fabricantes de los cartuchos.

Los puntos de vista expresados en esta entrada son propios, y no representan necesariamente los puntos de vista de Atos SE, Atos España o ninguna de sus filiales.

miércoles, 20 de diciembre de 2017

Los backups incrementales y diferenciales

Una de las cosas con las que se enfrenta, con un poco de miedo, cualquier administrador de copias de seguridad es al backup diferencial.

¿Qué es un backup diferencial? La verdad es que ni siquiera los programas de backup lo tienen claro.

Para empezar, todos tienen claro lo que es un backup Full o completo: se copia todo lo que haya que copiar. Pero no se puede hacer backup de todo todos los días, sería un gasto enorme e inútil de recursos.

Entonces, se puede copiar cada día solamente lo que haya cambiado desde el día anterior. O solamente lo que haya cambiado desde que se hizo el backup Full.

Estas dos estrategias son interesantemente diferentes: si se copia solamente lo que haya cambiado desde el día anterior, todos esos backups serán pequeños, pero a la hora de restaurar (no perdamos de vista que los backups no son el objetivo: su propósito es poder restaurar) son necesarios tanto el backup completo inicial como todos estos backups parciales. En cambio, si se copia todo lo que haya cambiado desde el backup Full, estos backups parciales serán pequeños, sí, pero cada vez más grandes, sin embargo para restaurar solamente serán necesarios el backup completo inicial el el backup parcial en cuestión.

Estas dos estrategias, además, se pueden combinar de varias maneras. Y el problema es que reciben diferentes nombres allá donde se usen.

Uno de los grandes contendientes en la arena empresarial es EMC NetWorker. Para este programa la estrategia de copiar "lo que haya cambiado desde el día anterior" es llamada comúnmente backup incremental, y la de copiar "lo que haya cambiado desde el backup completo" es llamada normalmente backup diferencial. Aunque no es exactamente así: NetWorker tiene 9 niveles de backup diferencial. Así, un backup diferencial de nivel 1 es realmente "lo que haya cambiado desde el backup completo", uno de nivel 2 es "lo que haya cambiado desde el backup completo o desde el backup de nivel 1", etc., permitiendo un control fino de la estrategia de copia, mientras que un backup incremental es realmente "lo que haya cambiado desde el backup anterior". Nótese, por cierto, que en determinadas aplicaciones, como en el módulo de NetWorker para Microsoft SQL Server, el backup "incremental" tiene un uso especial (en MSSQL hace copia de los Transaction Logs), con lo cual no queda disponible para su uso regular. Para el control de lo que se ha copiado en cada uno de estos niveles, NetWorker maneja índices de ficheros.

Otro de los grandes programas es Veritas NetBackup. Para este programa, o su primo Veritas Backup Exec, la estrategia de copiar "lo que haya cambiado desde el día anterior" es llamada "Cumulative incremental" o más comúnmente incremental, y la de copiar "lo que haya cambiado desde el backup completo" es llamada "Differential Incremental" o más amigablemente backup diferencial, pero aquí no trabajan en base a índices de ficheros, sino que el backup incremental copia los ficheros que tengan el bit de Archivo en ON (los nuevos o que hayan sido modificados) y pone dicho bit a OFF, mientras que el backup diferencial copia los ficheros que tengan el bit de archivo a ON pero no modifica dicho bit. El comportamiento de ambos tipos de backups es el esperado, pero la interacción entre ambos es exactamente la contraria que en EMC NetWorker: los backups diferenciales de Veritas NetBackup o Veritas BackupExec "se apoyan", es decir, necesitan a la hora de una restauración, de un backup incremental previo si lo hubiera, mientras que en EMC NetWorker es exactamente al contrario.

El más importante de los programas de backup Open Source, Bacula, usa unas definiciones parecidas: un Incremental es exactamente lo que haya cambiado desde que comenzó el último backup de cualquier tipo, mientras que un Differential es exactamente lo que haya cambiado desde que comenzó (y es importante el detalle "desde que comenzó", ya que puede que no haya acabado) el último backup Full. De este modo, a la hora de la restauración se comportan igual que los de EMC NetWorker.

Para el no iniciado, pensar en términos de completo, diferencial e incremental puede suponer un esfuerzo mental extra. Es más sencillo trabajar solamente con el completo y el incremental, e introducir el diferencial a medida que se coge expericncia con el programa específico con el que se ha de trabajar.

viernes, 25 de julio de 2014

Configurando la red para máquinas virtuales

Siguiendo con la configuración de máquinas virtuales, es hora de configurar la red.

Quiero que mis máquinas virtuales atiendan servicios, así que necesito que tengan direcciones IP visibles desde la red física, a las que mi enrutador pueda dirigirse.

Ha sido muy difícil encontrar la documentación, y al final en realidad he tenido que recurrir a métodos de prueba y error, pero finalmente lo tengo.

En el servidor, hay que configurar un puente. Eso quiere decir que pasamos de esto:

#/etc/network/interfaces

# The primary network interface
allow-hotplug eth0
auto eth0
iface eth0 inet static
      address 192.168.2.25
      netmask 255.255.255.0
      network 192.168.2.0
      broadcast 192.168.2.255
      gateway 192.168.2.1
      dns-nameservers 127.0.0.1
      dns-domain rolamasao.org

a esto:

#/etc/network/interfaces

# The primary network interface
auto br0
iface br0 inet static
        bridge_ports eth0
        address 192.168.2.25
        netmask 255.255.255.0
        network 192.168.2.0
        broadcast 192.168.2.255
        gateway 192.168.2.1
        dns-nameservers 127.0.0.1
        dns-domain rolamasao.org

Es importante notar que a partir de ese momento debemos considerar que la interfaz de red de nuestro servidor físico es br0, y no eth0.

Claro que de nada sirve tener un puente si los paquetes que llegan al puente no son retransmitidos hacia Internet. Por eso hay que modificar un parámetro del kernel:

# /etc/sysctl.conf - Configuration file for setting system variables

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

Para que estos cambios tengan efecto es necesario reiniciar, pero siempre se pueden ejecutar a mano con un poquito de brctl, ifconfig, route y echo.

En las máquinas virtuales la configuración debe indicar que utilizan el puente br0, lo cual es bastante sencillo de hacer desde virt-manager. Ya dentro de la máquina virtual, tenemos una configuración bastante estándar. Simplemente hay que indicar que el enrutador por defecto es la máquina física, no el enrutador de la red:

#/etc/network/interfaces VIRTUAL

# The primary network interface
allow-hotplug eth0
iface eth0 inet static
        address 192.168.2.80
        netmask 255.255.255.0
        network 192.168.2.0
        broadcast 192.168.2.255
        gateway 192.168.2.25
        # dns-* options are implemented by the resolvconf package, if installed
        dns-nameservers 192.168.2.25