Securizar Apache con mod_md y Let’s Encrypt

Apache incluye un módulo llamado mod_md. Podemos usarlo para el aprovisionamiento de certificados a través del protocolo ACME. Este artículo explica cómo instalar, configurar y poner en marcha Apache con un módulo mod_md para asegurar el tráfico con el certificado gratuito Let’s Encrypt TLS/SSL en un servidor Debian 10 Buster.

Let’s Encrypt es una Autoridad de Certificación (CA) que emplea el protocolo ACME. Uno puede usar Let’s Encrypt para emitir certificados TLS/SSL gratuitos para Apache, Nginx y otros servidores. En este tutorial, usarás mod_md para obtener un certificado TLS/SSL gratuito para Apache 2 en Debian 10 Buster y configurarás tu certificado para que se renueve automáticamente también. Nuestro ejemplo de configuración es el siguiente:

  • Dominio – www.dominio.com
  • Puerto HTTPS – 443
  • Archivo de configuración del host virtual – /etc/apache2/sites-available/www.dominio.com.conf

Paso 1 – Instalar mod_md para Let’s Encrypt

En primer lugar resulta necesario aclarar que Debian 10 Buster incluye Apache 2.4.38 y el mod_md que contiene sólo sirve para el protocolo ACME v1. Let’s Encrypt dejó de dar soporte a esta versión.

Entonces, es imprescindible actualizar Apache y para hacerlo debemos habilitar los repositorios backports.

# apt edit-sources

Agregamos la siguiente linea al final del archivo:

deb http://deb.debian.org/debian buster-backports main contrib non-free

Actualizamos la caché de APT para incluir backports en la lista de paquetes disponibles:

apt update

Instalamos Apache desde allí

apt -t buster-backports install apache2

Luego, instalamos mod_md:

apt install libapache2-mod-md

Habilitamos el módulo:
a2enmod md

Enabling module md.
To activate the new configuration, you need to run:
  systemctl restart apache2

Asegurate de activar tambien mod_ssl too:
a2enmod ssl

Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  systemctl restart apache2

Apache 2 debe ser recargado con la ayuda del comando systemctl

systemctl reload apache2.service

Paso 2 – Configurar el certificado SSL

Verificamos que Apache está escuchando en el puerto 80. Para eso usamos el comando ss o netstat:
netstat -tulpn | grep ':80'
## o ##
ss -tulpn | grep ':80'

tcp    LISTEN  0       128                        *:80                  *:*      users:(("apache2",pid=2550,fd=4),("apache2",pid=2549,fd=4),("apache2",pid=2548,fd=4))

Todos los clientes deben conectarse al servidor a través del puerto 80. De lo contrario, no será validado para el certificado Let’s Encrypt. Desde tu escritorio, ejecuta:
curl -I http://www.dominio.com
La salida del comando curl valida que podemos conectarnos al puerto 80 TCP:

HTTP/1.1 200 OK
Date: Sat, 19 Dic 2020 12:45:43 GMT
Server: Apache/2.4.46 (Debian)
Last-Modified: Wed, 06 May 2020 19:15:29 GMT
ETag: "15e-5a4ff965902a3"
Accept-Ranges: bytes
Content-Length: 350
Vary: Accept-Encoding
Connection: close
Content-Type: text/html

Editemos /etc/apache2/sites-available/www.dominio.com.conf:
nano /etc/apache2/sites-available/www.dominio.com.conf
Al comienzo del archivo agregamos tres directivas mod_md:

## Aseguramos Apache con directivas mod_md para Let's Encrypt ##
ServerAdmin administrador@dominio.com
MDCertificateAgreement accepted
MDomain www.dominio.com
MDPrivateKeys RSA 4096

Donde,

  • ServerAdmin administrador@dominio.com : mod_md usará esta dirección al registrar tu dominio en Let’s Encrypt.
  • MDCertificateAgreement accepted : Es necesario aceptar las condiciones del Acuerdo de suscripción según lo establecido por Let’s Encrypt.
  • MDomain www.dominio.com : Declarar un nombre de dominio que debe ser administrado por mod_md para emitir y renovar certificados. Se puede usar un nombre de dominio completo como www.dominio.com o dominio.com. Asegúrate de que coincide con ServerAlias.
  • MDPrivateKeys RSA 4096 : Establece el tipo y el tamaño de las claves privadas generadas.

Esta es mi configuración completa :

## Apache with mod_md Let's Encrypt ##
## mod_md config for Let's Encrypt ##
ServerAdmin administrador@dominio.com
MDCertificateAgreement accepted
MDomain www.dominio.com
MDPrivateKeys RSA 4096
 
## Config HTTP puerto 80 ##
<VirtualHost *:80>
    ServerAdmin administrador@dominio.com
    ServerName www.dominio.com
    DocumentRoot /var/www/dominio.com
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/www.dominio.com-error.log
    CustomLog ${APACHE_LOG_DIR}/www.dominio.com-access.log combined
    # Redirigir todas las solicitudes HTTP a HTTPS (descomentar las dos líneas siguientes al habilitar HTTPS) 
    # RewriteEngine On
    # RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
 
## Config HTTPS puerto 443 ##
<VirtualHost *:443>
    SSLEngine on
    ServerAdmin administrador@dominio.com
    ServerName www.dominio.com
    DocumentRoot /var/www/dominio.com
## Permisos para DocumentRoot  ##
<Directory /var/www/dominio.com/html>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/www.dominio.com-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/www.dominio.com-ssl-access.log combined
    # Activar HTTP/2 
    Protocols h2 http/1.1
    # Establecer la seguridad de transporte HTTP como estricta
    Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>

Luego editamos /etc/apache2/conf-enabled/security.conf:

nano /etc/apache2/conf-enabled/security.conf

Al final agregamos directivas para incrementar el nivel de seguridad:

## Habilitar sólo TLS v1.3 y evitar protocolos más antiguos ##
SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
SSLHonorCipherOrder     off
SSLSessionTickets       off
 
## Activar OCSP Stapling ##
SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"

Activar mod_rewrite y mod_headers de Apache

Ya hemos declarado una regla de reescritura en nuestra configuración, así que necesitamos mod_rewrite. Por lo tanto:
a2enmod rewrite
Enabling module rewrite.
To activate the new configuration, you need to run:
systemctl restart apache2

Activamos también mod_headers:
a2enmod headers
Enabling module headers.
To activate the new configuration, you need to run:
systemctl restart apache2

Comprobamos si hay errores de configuración

apache2ctl configtest
Syntax OK

Paso 3 – Obtener un certificado SSL usando mod_md

Hasta ahora, instalamos el mod_md para Apache, habilitamos todos los módulos esenciales. Es hora de reiniciar nuestro servidor Apache para obtener el certificado TLS/SSL gratuito usando Let’s Encrypt.
systemctl restart apache2.service
Tan pronto como Apache 2 se reinicie, mod_md solicitará un certificado para tu dominio a Let’s Encrypt. Normalmente tarda hasta un minuto. Puedes comprobar el registro de errores del servidor o la página de mod_status de Apache para ver si la petición ha sido satisfactoria o no. Esto lo que verás en el archivo error.log:
tail -f /var/log/apache2/error.log
También puedes usar el comando grep:
grep 'The Managed Domain' /var/log/apache2/error.log
Las salidas de ejemplo indican que LE nos ha expedido un certificado gratuito de TLS/SSL:

[Wed Dic 19 10:17:38.112849 2020] [md:notice] [pid 21777:tid 139807872861952] AH10059: The Managed Domain www.dominio.com has been setup and changes will be activated on next (graceful) server restart.

Por supuesto que también podemos visitar la url estado del servidor. Por ejemplo::
http://www.dominio.com/server-status
http://tu-ip-publica-aqui/server-status

Se recomienda reiniciar el servidor Apache 2 para activar el certificado:
systemctl reload apache2.service

Paso 4 – Probar la conexión segura de Apache

Todo lo que tienes que hacer es escribir el siguiente comando o usar un navegador web como Firefox/Chromium para asegurarte de que estás recibiendo una conexión HTTPS:
curl -I https://www.dominio.com

Otra alternativa es utilizar el servicio de prueba de servidores SSL de SSL Labs.

Paso 5 – Renovar automáticamente un certificado SSL usando mod_md y watchdog_module

mod_md emplea el modulo watchdog, que proporciona conexiones programáticas para que otros módulos ejecuten tareas como la renovación de certificados TLS/SSL y más periódicamente. En otras palabras, el modo de auto-renovación requiere que mod_watchdog esté activo en tu servidor. Por lo tanto, verifica que mod_watchdog esté activado usando:
apache2ctl -M
apache2ctl -M | grep -i watchdog

Loaded Modules:

 core_module (static)
 so_module (static)
 watchdog_module (static)
 http_module (static)
 unixd_module (static)
 access_compat_module (shared)
 alias_module (shared)
 auth_basic_module (shared)
 authn_core_module (shared)
 ....
 ..
 ...
 ssl_module (shared)
 status_module (shared)

Paso 6 – Monitoreo de estado de certificados

Ahora que configuramos Apache con mod_md y conseguimos un certificado TLS/SSL de Let’s Encrypt, es hora de monitorear el estado de nuestro certificado. Hay dos maneras. Primero abrir /server-status URL:
https://www.dominio.com/server-status
https://tu-ip-publica-aqui/server-status

Edita la configuración del servidor:
nano /etc/apache2/sites-available/www.dominio.com.conf
Agrega lo siguiente:

<Location "/md-status">
  SetHandler md-status
</Location>

Guarda el archivo, recarga el Apache y ejecuta:
systemctl restart apache2.service
curl https://www.dominio.com/md-status

{
  "version": "2.0.10",
  "managed-domains": [
    {
      "name": "www.dominio.com",
      "domains": [
        "www.dominio.com",
        "web.dominio.com"
      ],
      "contacts": [
        "mailto:administrador@dominio.com"
      ],
      "transitive": 1,
      "ca": {
        "proto": "ACME",
        "url": "https://acme-v02.api.letsencrypt.org/directory",
        "agreement": "accepted"
      },
      "state": 2,
      "renew-mode": 1,
      "renew-window": "33%",
      "warn-window": "10%",
      "must-staple": false,
      "cert": {
        "valid-from": "Wed, 19 Dec 2020 12:17:37 GMT",
        "valid-until": "Tue, 19 Mar 2021 12:17:37 GMT",
        "serial": "040E339A0A7D2224819A550BBB4596279F67",
        "sha256-fingerprint": "d78933fa946cb71810111876049defa4feb6820c319c69918ba925b463bbd11c"
      },
      "renew": false
    }
  ]
}

¿Dónde están mis archivos de certificados TLS/SSL?

Es necesario ubicarse en el directorio /etc/apache2/md:
# cd /etc/apache2/md/
# ls -l

Veremos los archivos de la siguiente manera:

total 28
drwxr-xr-x 3 root     root 4096 Nov 13 13:02 accounts
drwx------ 3 root     root 4096 Nov 13 13:02 archive
drwxr-xr-x 2 www-data root 4096 Nov 13 13:02 challenges
drwx------ 3 root     root 4096 Nov 13 13:02 domains
-rw------- 1 root     root  116 Nov 13 12:52 md_store.json
drwxr-xr-x 2 www-data root 4096 Nov 13 13:02 staging
drwx------ 2 root     root 4096 Nov 13 13:02 tmp

Miramos en el directorio de dominios:

# cd domains
# ls -l
# cd www.dominio.com
# ls -l

Aquí están los archivos TLS/SSL para tu dominio:

total 16
-rw------- 1 root root 3997 Nov 13 13:02 job.json
-rw------- 1 root root  492 Nov 13 13:04 md.json
-rw------- 1 root root 3272 Nov 13 13:02 privkey.pem
-rw------- 1 root root 3916 Nov 13 13:02 pubcert.pem

Dominios www y no www

Se puede gestionar certificados TLS/SSL para dominio.com y www.dominio.com de la siguiente manera (las directivas MDomain y ServerAlias añadidas/actualizadas):

ServerAdmin administrador@dominio.com
MDCertificateAgreement accepted
# www and non-www TLS certicate #
MDomain dominio.com www.dominio.com
MDPrivateKeys RSA 4096
 
## Config HTTP puerto 80 ##
<VirtualHost *:80>
    ServerAdmin administrador@dominio.com
    ServerName www.dominio.com
    ServerAlias dominio.com
    DocumentRoot /var/www/dominio.com
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/dominio.com-error.log
    CustomLog ${APACHE_LOG_DIR}/dominio.com-access.log combined
    # Redirigir todas las solicitudes HTTP a HTTPS (descomentar las dos líneas siguientes al habilitar HTTPS) 
    # RewriteEngine On
    # RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
 
## Config HTTPS puerto 443 ##
<VirtualHost *:443>
    SSLEngine on
    ServerAdmin administrador@dominio.com
    ServerName www.dominio.com
    ServerAlias dominio.com
    DocumentRoot /var/www/dominio.com
## Permisos para DocumentRoot  ##
<Directory /var/www/dominio.com>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/dominio.com-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/dominio.com-ssl-access.log combined
    # Habilitar HTTP/2 
    Protocols h2 http/1.1
    # Establecer la seguridad de transporte HTTP como estricta
    Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>

Una nota sobre la directiva ‘auto’

El enfoque anterior funciona para uno o dos subdominios. ¿Pero qué pasa si tenemos 4 o 5 dominios, como dominio.com, www.dominio.com, forum.dominio.com, correo.dominio.com? Podemos usar la palabra clave auto de la siguiente manera:

MDomain dominio.com auto
 
<VirtualHost *:443>
    ServerName dominio.com
    ServerAlias www.dominio.com
    ServerAlias forum.dominio.com
    ServerAlias correo.dominio.com
    ...
</VirtualHost>

Cada vez que añadas más nombres de ServerAlias a este host virtual con la palabra clave ‘auto’, se añadirán también al dominio administrado. Si prefieres declarar explícitamente todos los nombres de dominio, usa el modo ‘manual’.

Multiples dominios

Aquí está cómo configurar dominio2.com y dominio.com:

 
MDomain dominio.com auto
MDomain dominio2.com auto
 
# dominio.com #
<VirtualHost *:80>
    ServerName dominio.com
    ServerAlias www.dominio.com
    ...
    .....
</VirtualHost>
<VirtualHost *:443>
    ServerName dominio.com
    ServerAlias www.dominio.com
    ...
</VirtualHost>
 
# dominio2.com #
<VirtualHost *:80>
    ServerName dominio2.com
    ServerAlias www.dominio2.com
    ...
</VirtualHost>
<VirtualHost *:443>
    ServerName dominio2.com
    ServerAlias www.dominio2.com
    ...
</VirtualHost>

Acerca de OCSP

OCSP (Online Certificate Status Protocol) es un protocolo para comprobar si un certificado SSL ha sido revocado. Fue creado como una alternativa al CRL para reducir el tiempo de negociación del SSL. Con la CRL (Certificate Revocation List) el navegador descarga una lista de números de serie de certificados revocados y verifica el certificado actual, lo que aumenta el tiempo de negociación del SSL. Con OCSP el navegador envía una solicitud a una URL del OCSP y recibe una respuesta que contiene el estado de validez del certificado.

OCSP stapling

OCSP tiene dos problemas importantes: la privacidad y la carga en los servidores de CA.

Como OCSP requiere que el navegador contacte con la CA para confirmar la validez del certificado, compromete la privacidad. La CA sabe a qué sitio web se está accediendo y quién lo ha hecho.

Si un sitio web HTTPS recibe muchos visitantes, el servidor OCSP de la CA tiene que gestionar todas las peticiones OCSP realizadas por los visitantes.

Cuando se implementa el OCSP stapling, el titular del certificado (servidor web de lectura) consulta al propio servidor OCSP y almacena en caché la respuesta. Esta respuesta se «adjunta» con el TLS/SSL Handshake a través de la respuesta a la solicitud de estado de certificado. Como resultado, los servidores de la CA no se cargan con solicitudes y los navegadores ya no tienen que revelar los hábitos de navegación de los usuarios a ningún tercero.

Generador de configuración SSL de moz://a

En este enlace podrás obtener los detalles de configuración necesarios para tu sistema. Solo deberás escoger el tipo de servidor web, su versión y la del certificado OpenSSL.

Conclusión

En este tutorial, aseguramos Apache con el módulo mod_md para Let’s Encrypt para emitir y auto-renovar el certificado TLS/SSL gratuito en un servidor Debian 10 Buster. Para obtener más información, consultar documentación de mod_md.

 

https://www.cyberciti.biz/faq/how-to-secure-apache-with-mod_md-lets-encrypt-on-ubuntu-20-04-lts/#Installing_mod_md