Pasar al contenido principal

Let's Encrypt

Let's Encrypt es una entidad certificadora automatizable y abierta que ofrece certificados para sitios web de forma gratuita. Es una iniciativa impulsada por entidades como la Electronic Frontier Foundation, la Fundación Mozilla, Akamai Technologies, Cisco Systems, Facebook, OVH o Google Chrome, entre otras. La idea es facilitar la obtención, configuración y uso de certificados web de forma que se extienda el uso de conexiones cifradas por toda la World Wide Web.

Lo cierto es que todo lo relacionado con los certificados web para cifrar el tráfico de una web es un asunto bastante farragoso: por un lado se debe obtener el certificado, que exige pasar un proceso manual que varía según la entidad certificadora, pagar por el certificado, obtenerlo en un formato adecuado para el uso que queramos darle y por último instalarlo en el servidor web del dominio. Esto hace que muchas webs de menor tamaño y pocos recursos no hagan uso de tráfico cifrado.

Let's Encrypt aspira a terminar con esta situación facilitando este proceso. Para ello hace uso de Certbot, un software de la Electronic Frontier Foundation que permite obtener un certificado, programar su renovación automática e incluso configurarlo en diferentes softwares (Apache, Nginx, HAProxy, Plesk).

Los certificados de Let's Encrypt tienen un período de validez menor que otros certificados que típicamente tienen una duración de al menos un año. Los de Let's Encrypt solo duran tres meses, pero esto no debería ser un problema dado que su renovación es automática. Además, desde hace un par de meses ya permiten certificados wildcard.

En Metadrop hemos decidido hacer uso de Let's Encrypt en aquellos clientes que lo necesiten, así como en nuestros entornos de desarrollo y otros servicios propios. Esto nos permite realizar todo el desarrollo y los tests usando HTTPS con certificados válidos. Antes debíamos usar certificados autofirmados que los navegadores y otros programas no aceptaban, debiendo modificar algunas configuraciones para que aceptasen conexiones inseguras. Ahora todo se realiza de la misma forma que se hace en producción, con certificados válidos y sin tener que hacer ningún apaño en la configuración de los programas. De esta forma reducimos enormemente la posibilidad de que un error relacionado con el tráfico HTTPS pase desapercibido en la fase de desarrollo y solo sea detectado en producción.

En la Red ya hay mucha información sobre cómo usar Let's Encrypt y creo que aportaría poco el añadir un artículo explicando cómo hacer uso de estos certificados cuando ya existen artículos muy buenos de este tipo. Sin embargo, creo que sí puede ser interesante comentar algunas situaciones menos habituales.

Sitios en desarrollo protegidos por Apache

Normalmente los proyectos en desarrollo cuentan con al menos un entorno de staging en un servidor accesible a cualquier persona que tenga su URL. Podría usarse algún tipo de VPN de forma que solo fuese accesible desde la red de la empresa, pero esto se convierte en algo terriblemente inconveniente cuando los clientes quieren acceder al sitio para comprobar los progresos del proyecto. Por ello la solución es proteger el sitio con Apache, de forma que mediante Basic Auth basta un usuario y contraseña para acceder al sitio.

El problema llega cuando se quiere usar Let's Encrypt para el certificado de este sitio. Let's Encrypt debe confirmar que el dominio del que estás pidiendo el certificado te pertenece. La forma más cómoda y rápida que además no detiene el servidor web es usar la autentificación weboroot. Básicamente la idea es que si estás pidiendo el certificado desde el servidor web que sirve el dominio y puedes modificar los ficheros servidos por el servidor web bastará con Certbot coloque en algún sitio del docroot uno o más ficheros para que Let's Encrypt se conecte al dominio y trate de acceder a esos ficheros. Si los ficheros están es que tienes control del dominio.

¿El problema? Que tenemos el sitio protegido por Basic Auth y además de que no estaría bonito revelar nuestras claves de acceso a Let's Encrypt, por muy buena gente que parezcan, Let's Encrypt no admite la autentificación del dominio usando usuario y contraseña. ¿La solución? Basta con añadir una excepción para las peticiones que acceden a la ruta /.well-known/acme-challenge/, que es donde Certbot deja los ficheros a comprobar.

La configuración del Virtual Host de Apache tendría algo así:

<Directory /var/vhosts/projects/miproyecto>
    # Configurar autentificación.
    AuthType Basic
    AuthName "Authorization required"
    AuthBasicProvider file
    AuthUserFile /etc/apache2/htpasswd/miproyecto_passwords

    # Autorizar peticiones hacia .well-known/acme-challenge/
    Require expr %{REQUEST_URI} =~ m#^/.well-known/acme-challenge/#
    # Autorizar peticiones del usuario miusuario autenticado
    Require user miusuario
</Directory>

La línea importante es:

  Require expr %{REQUEST_URI} =~ m#^/.well-known/acme-challenge/#

Esta excepción deja pasar cualquier petición dirigida al subdirectorio /.well-known/acme-challenge/. Dado que ahí no debería haber ninguna información relevante no revelamos ningún dato del proyecto que estemos desarrollando.

Dominios redirigidos

Supongamos que hay un proyecto en el dominio example.com, pero también tenemos el dominio example.es, que queremos que redirija a example.com. Aunque podemos colocar un HTML en example.es con un código que redirija al otro dominio, es más elegante y adecuado hacerlo directamente en el Virtual Host del servidor web. Por ejemplo:

ServerName example.es RedirectMatch 301 ^(?!/\.well-known/acme-challenge/).* http://example.com

Pero tendríamos un problema al intentar obtener el certificado mediante Let's Encrypt: el servidor no tiene un docroot donde Certbot pueda dejar los ficheros de autentificación de dominio.

Para solucionarlo necesitamos un directorio donde apuntar las peticiones que Let's Encrypt hace al dominio. Se puede usar un directorio creado al efecto, o podemos usar el directorio del dominio principal (al que estamos redirigiendo) si tenemos su docroot en el mismo servidor. La idea es crear un Alias de Apache a ese directorio y solo redireccionar las peticiones que no vayan a /.well-known/acme-challenge/:

  # Vhost que redirige al dominio principal
  ServerName example.es

  # Crear un alias apuntando a la carpeta local del proyecto.
  Alias "/.well-known/acme-challenge" "/var/vhosts/projects/miproyecto/.well-known/acme-challenge"
  # Redirigir todas las peticiones que no sean a /.well-known/acme-challenge/.
  RedirectMatch 301 ^(?!/\.well-known/acme-challenge/).* http://example.com

Aplicaciones con servidor web propio

Ciertas aplicaciones, como Solr, incluyen su propio servidor web y usan puertos no estándar de HTTP. Eso hace que Let's Encrypt no pueda validar el dominio, ya sea porque el servidor web incluido no sirve los ficheros que crea Certbot para la validación o porque el servidor no está en el puerto web al que accede Let's Encrypt.

Habitualmente estas aplicaciones permiten mediante configuración solucionar estos problemas, pero deberemos conocer cada aplicación para saber cómo modificar esta configuración. Además, también deberemos configurar el certificado obtenido de Let's Encrypt, cosa a veces nada trivial según cada software. Por ello, una opción es crear un servidor virtual Apache que haga de proxy hacia la aplicación pero permitiendo que las peticiones de validación de dominio sean servidas desde un directorio del sistema de ficheros. Basta con indicarle a Certbot dicho directorio para que escriba ahí los ficheros de validación del dominio para que podamos obtener nuestro certificado sin problema. Al usar Apache como proxy configurar el certificado es directo, sin tener que lidiar con la configuración específica de cada aplicación. Como ventaja añadida podemos añadir una autentificación en Apache para proteger el recurso o cualquier otra actuación estándar que permita Apache.

  ServerName solr.example.com

  # Configurar la funcionalidad de proxy, ignorando las peticiones a /.well-known/acme-challenge/.
  ProxyPass /.well-known/acme-challenge !
  ProxyPass / http://localhost:8983/
  ProxyPassReverse / http://localhost:8983/

  # Crear un alias apuntando a la carpeta local del proyecto.
  Alias "/.well-known/acme-challenge" "/var/www/well-known/solr/.well-known/acme-challenge"

En este último caso está un poco forzado. Lo normal sería dejar la configuración del proxy en el puerto 443, cuando la conexión es SSL. En el puerto 80 se usaría una variante del caso anterior de redirección, redireccionando todas las peticiones que no sean a .well-known/acme-challenge/ al mismo dominio pero con HTTPS. Se deja así para mostrar una posible configuración de proxy.

 

Directorio .well-known

En los ejemplos previos se ha permitido el acceso a .well-known/acme-challenge, pero vale la pena mencionar que realmente se debería permitir el acceso al directorio .well-known, y sus subdirectorios. Este directorio viene del RFC 5785, y viene a ser una forma de ofrecer metadatos del servidor de forma sencilla. Pero esto en realidad ya es otra historia…

RIcardo Sanz Ante

Ricardo Sanz

CTO