Aplicando certificados Let’s Encrypt en el sistema

Ya hemos usado un cliente para el proyecto Let’s Encrypt y hemos habilitado su renovación automática así que ahora lo que toca es emplearlo en los diferentes servicios del sistema.

Los que voy a comentar en esta entrada son:

  • Servidor web
  • Servidor SMTP
  • Servidor IMAP/POP3
  • Servidor XMPP

Servidor web Apache

Para declarar los certificados en el servidor Apache necesitamos añadir varias directivas a su configuración. Tal y como lo he organizado dispongo de tres juegos de certificados, uno por cada dominio principal, por lo que voy a crear tres archivos de configuración de manera que me sea más sencillo cargarlos en cada servidor virtual.

Sólo anoto aquí el ejemplo de uno de ellos

SSLEngine on
SSLCipherSuite  HIGH
SSLProtocol all -SSLv2
SSLHonorCipherOrder on
SSLCertificateFile /etc/letsencrypt.sh/certs/taquiones.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt.sh/certs/taquiones.net/privkey.pem

Guardado como

/etc/apache2/conf.d/taquiones-ssl.conf

y cargado empleando la directiva 

Include /etc/apache2/conf.d/taquiones-ssl.conf

. Las referencias sobre las otras opciones de SSL las he sacado, entre otras fuentes, de StackOverflow. Ahora, tras recargar la configuración podemos probar la nueva configuración gracias a la ayuda de SSL Labs.

Recepción de correo (servidor XMPP)

Para la recepción del correo estoy empleando qpsmtpd como frontal de exim4 y dado que es el encargado de identificar a los usuarios precisa de acceso a los certificados para las conexiones seguras.

El complemento TLS del programa no está escrito con mucho cariño, menos aún documentado, y me ha costado encontrar la forma de que funcione. Ya que qpsmtpd funciona con un usuario sin privilegios administrativos no tiene acceso a los archivos de los certificados; me he visto obligado a proporcionarle una copia de los mismos en su directorio de configuración

/etc/qpsmtpd/ssl
root@spin:/etc/qpsmtpd/ssl# ls -ltra
total 20
-rw------- 1 qpsmtpd qpsmtpd 3875 abr 11 07:55 server.crt
-rw------- 1 qpsmtpd qpsmtpd 3243 abr 11 07:55 private.key
-rw------- 1 qpsmtpd qpsmtpd 3875 abr 11 08:01 ca.crt
drwxr-xr-x 2 root    root    4096 abr 11 08:21 .
drwxr-xr-x 3 root    root    4096 abr 11 08:56 ..

Para después indicar dónde están en la configuración (

/etc/qpsmtpd/plugins

):

#       Habilitar conexiones seguras
tls /etc/qpsmtpd/ssl/server.crt /etc/qpsmtpd/ssl/private.key /etc/qpsmtpd/ssl/ca.crt

Ahora sólo resta solucionar el detalle de que cada vez que se renueve un certificado se vuelvan a copiar los contenidos en su directorio particular. Para eso he modificado la función deploy_cert() en el script

/etc/letsencrypt.sh/hook.sh:
        # y luego según el caso afinamos más
        case $DOMAIN in
        taquiones.net)
                # Detenemos el servidor smtp
                systemctl stop qpsmtpd

                # Copiamos los certificados para él
                QPSMTPD=/etc/qpsmtpd/ssl
                cp $KEYFILE $QPSMTPD/privkey.pem
                cp $CERTFILE $QPSMTPD/server.crt
                cp $FULLCHAINFILE $QPSMTPD/ca.crt

                # Reiniciar servidores de correo, mensajería ...
                echo "Reiniciando servidores de correo y mensajería ..." >&2
                systemctl start qpsmtpd
                systemctl restart dovecot
                systemctl restart prosody
                ;;
        esac

 

Servidor IMAP/POP3 (dovecot)

Este ha sido el más sencillo de configurar. Para habilitar las conexiones seguras de los protocolos de acceso a los buzones de correo basta con añadir unas estrofas a su archivo de configuración en

/etc/dovecot/dovecot.conf

:

ssl_ca = </etc/letsencrypt.sh/certs/taquiones.net/fullchain.pem
ssl_cert = </etc/letsencrypt.sh/certs/taquiones.net/fullchain.pem
ssl_key = </etc/letsencrypt.sh/certs/taquiones.net/privkey.pem

Servidor XMPP (prosody)

Con este programa nos encontramos con el mismo problema que con qpsmtpd: funciona con una cuenta de usuario normal y no tiene acceso a los certificados. He tenido que implementar la misma técnica y copiar los certificados a un directorio privado

/etc/prosody/certs/

e indicarle que los tomase de allí

-- These are the SSL/TLS-related settings. If you don't want
-- to use SSL/TLS, you may comment or remove this
ssl = { 
        key = "/etc/prosody/certs/taquiones.net.key";
        certificate = "/etc/prosody/certs/taquiones.net.cert";
}

Resumiendo

El programa letsencrypt.sh conserva los certificados bajo permisos muy restrictivos y a menos que el servicio funcione como apache (arranque como root, lea los certificados y luego cambie al usuario normal) será necesario efectuar una copia tras la renovación (o la creación inicial) para que los servidores funcionen. En el resto no he encontrado más problemas.

Usando letsencrypt.sh para crear y renovar certificados

La naturaleza abierta del proyecto Let’s Encrypt permite que existan  clientes alternativos al oficial. Yo me he decidido por uno escrito en Bash por Lukas Schauer, muy ligero y fácilmente trazable. Bueno, lo de fácilmente es un decir porque cuando se llega a la parte de openssl las cosas se complican un poco con tanto parámetro y tanto condicionante; el resto se comprende de un vistazo rápido.

El caso es que funciona muy bien y los resultados son fácilmente aplicables a los servicios del sistema como detallaré más abajo. De momento éstos son los pasos que he seguido:

  1. Descargar el programa
  2. Crear la configuración
  3. Activar (y verificar) el protocolo ACME challenge.
  4. Acomodar el programa en el sistema.

Descarga del programa

Tan simple como clonar el repositorio en algún lugar que no estorbe. En mi caso he empleado el directorio de trabajo de la cuenta que uso para configurar el servidor y luego lo he lanzado con privilegios de administración cuando lo he necesitado (que es más bien siempre).

Crear la configuración

El programa emplea como valor predeterminado para la configuración y los certificados la ruta

/etc/letsencrypt.sh

y me ha parecido muy bien, aunque se puede cambiar utilizando el parámetro

--config

. He creado el directorio y he situado allí dos archivos: uno para definir los dominios para los que quiero un certificado digital y otro para algunos ajustes en la configuración que me faciliten la automatización de la renovación.

El archivo

/etc/letsencrypt.sh/domains.txt

contiene en líneas aparte los dominios para los que queremos certificados separados por espacios en blanco. El primero es el dominio principal y los restantes son los nombres alternativos para el mismo.

taquiones.net mail.taquiones.net db.taquiones.net
astillas.net git.astillas.net 
vm69.net

Respecto a la configuración he añadido lo siguiente en

/etc/letsencrypt.sh/config.sh

(es un archivo shell):

# Archivo de configuración de openssl
OPENSSL_CNF=/usr/lib/ssl/openssl.cnf

# Ruta al directorio del protocolo ACME
WELLKNOWN=/var/www/letsencrypt

# Dirección de contacto
CONTACT_EMAIL=victor@example.net

Para crear los archivos CSR (Certificate Signing Request) con openssl es imprescindible que exista su archivo de configuración. Al parecer el mío había desaparecido del sistema y me he limitado a copiar una versión ejemplo que he encontrado por ahí y la he situado en

/etc/ssl/openssl.cnf

ya que Debian mantiene un enlace simbólico desde

/usr/lib/ssl/openssl.cnf

hacía allí; supongo que porque se trata de un archivo de configuración y la normativa Debian indica que deben estar bajo

/etc

.

Acomodar el programa en el sistema

Fase que incluye el probarlo por vez primera. Una vez que nos hemos asegurado de que respondemos correctamente al reto del protocolo ACME ejecutamos el programa con el parámetro

--cron

para obtener nuestros certificados.

Si todo ha ido bien los habrá creado bajo su directorio de configuración concretamente en bajo el subdirectorio certs:

.
├── certs
│   ├── astillas.net
|   .
|   .
│   ├── taquiones.net
|   .
|   .
|   └── vm69.net

En cada uno de ellos tendremos enlaces simbólicos apuntando a la última versión de cada componente que necesitamos:

  • cert.pem: es el certificado del servidor.
  • chain.perm: son los certificados intermedios.
  • fullchain.pem: el certificado del servidor y los intermedios.
  • privkey.pem: es la clave privada de lo anterior.

Después sólo resta instalar el programa y crear una tarea de renovación en el sistema:

$ sudo install -o root -g root -m 0555 letsencrypt.sh /usr/local/bin
$ cat <<EOF > renew.cron
# Renovación semanal en domingo
0 23 * * 0 root /usr/local/bin/letsencrypt.sh --cron
EOF
$ sudo install renew.cron /etc/cron.d/letsencrypt

Renovando certificados

El programa letsencrypt.sh, al igual que los demás que he visto, comprueban que la validez del certificado sea superior a los treinta días y si no es así solicitan renovarlo. También ocurre cuando la lista de dominios ha sufrido alguna alteración como el añadido o el borrado de algún nombre.

Luego está la cuestión de que tras la renovación los certificados han cambiado y nos encontramos con el problema de reiniciar aquellos servicios que hacen uso de ellos.

El programa letsencrypt.sh permite llamar a una función con el nombre de

deploy_cert()

que debe incluirse dentro del fuente principal en el archivo

hook.sh

del directorio de configuración.

Un ejemplo:

function deploy_cert
{
        local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}"

        # En cualquier caso reiniciar el servidor web
        echo "Reiniciando servidor web ..." >&2
        systemctl restart apache2

        # y luego según el caso afinamos más
        case $DOMAIN in
        taquiones.net) 
                # Reiniciar servidores de correo, mensajería 
                echo "Reiniciando servidores de correo y mensajería ..." >&2
                systemctl restart qpsmtpd
                systemctl restart dovecot
                systemctl restart prosody
                ;;
        esac
}