Crear certificados SSL wildcard de Let’s Encrypt con certbot

Let’s Encrypt permite generar certificados SSL de forma gratuita, que podemos renovar periódicamente, por ejemplo cada tres meses. Ya sea para un entorno de pruebas o laboratorio, un proyecto personal, o para un proyecto empresarial de mayor tamaño, Let’s Encrypt es una solución adecuada y muy utilizada, cada vez más. Si bien, es habitual su uso con aplicaciones o servidores que están disponibles en Internet, en este Post os voy a contar cómo generar un certificado de Let’s Encrypt con certbot para una máquina Ubuntu que no está expuesta a Internet, ya sea un entorno de laboratorio o de pruebas, algo que para mi, resulta muy útil.

Aunque cada vez es menos habitual trabajar con servicios que no estén expuestos a Internet, sigue habiendo casos, y en estas situaciones probablemente necesitaremos utilizar certificados SSL, para acceder de forma segura a través de un nombre DNS válido mediante HTTPS. En estos escenarios, también podemos utilizar los certificados gratuitos de Let’s Encrypt y generarlos con certbot.

En cualquier caso, lo primero que deberemos hacer es instalar certbot si no lo tenemos disponible, algo que en Ubuntu 22 podríamos hacer así, suponiendo el caso de una máquina con Apache en la que deseamos utilizarlo:

sudo apt install certbot python3-certbot-apache

Al instalar certbot en las versiones recientes de Ubuntu, se crea un servicio que se encarga de las renovaciones de los certificados, que podemos comprobar con el siguiente comando.

systemctl status certbot

Máquinas publicadas a Internet

El caso más habitual de uso de certificados gratuitos de Let’s Encrypt y certbot, es en máquinas publicadas a Internet. Por ejemplo, para generar un certificado SSL de Let’s Encrypt para un WordPress con Apache utilizando certbot, podemos utilizar un comando como el siguiente, el cual:

  • Genera un certificado SSL dentro de /etc/letsencrypt/live/, para lo cual, debemos especificar una cuenta de email, aceptar los términos de licencia, y especificar el dominio o dominios para los que deseamos generar el certificado.
  • Configura el certificado SSL en Apache, así como una redirección automática de HTTP a HTTPS.
  • Crea una tarea planificada para la renovación automática del certificado.
sudo certbot --apache

A continuación se muestra un ejemplo de su ejecución.

root@elwillie01:~# certbot --apache
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): mimail@gmail.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: n
Account registered.
Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel): midominio.com
Requesting a certificate for midominio.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/midominio.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/midominio.com/privkey.pem
This certificate expires on 2022-11-06.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for www.midominio.com to /etc/apache2/sites-available/wp-midominiocom-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://midominio.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

La verdad que certbot lo hace todo, nos genera el certificado SSL, lo configura en el Apache, y configura una tarea planificada y automática que se encargará de la renovación automática del certificado. Así que, guay, hecho esto, ya no tendremos que hacer nada más, y además, gratis.

Máquinas NO publicadas a Internet

Ahora vamos al caso que nos interesa: cuando la máquina no está publicada a Internet.

En el siguiente ejemplo, podemos ver cómo generar un certificado SSL para el nombre www.midominio.com con el comando certbot, utilizando como método de validación el DNS (deberemos crear un registro DNS de tipo TXT para validar que tenemos la propiedad del dominio, siguiendo sus instrucciones).

sudo certbot certonly --manual --preferred-challenges dns --email mimail@gmail.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d www.midominio.com

El anterior comando es interactivo (es decir, no vale para una ejecución desantendida), y sus principales parámetros son:

  • certonly indica que deseamos genear un un certificado, sin más, es decir, no lo va a instalar en un NGINX, ni en un Apache, ni nada.
  • manual indica que deseamos generar el certificado de forma interactiva, en nuestro caso necesario, al ser una máquina que no está expuesta a Internet.
  • preferred-challenges=dns indica que vamos a validar la propiedad del dominio mediante la creación de un registro TXT, con el valor que nos especificará durante la ejeución de certbot.
  • email debe incluir una dirección de correo electrónico válida, es interesante, porque nos llegarán notificaciones, como por ejemplo para avisarnos cuando está cerca de expirar.
  • server permite especificar el servidor de Let’s Encrypt contra el que se ejecutará nuestro comando.
  • agree-tos indica que aceptamos los términos del servicio de Let’s Encrypt.
  • d permite especificar el nombre de dominio para el que deseamos generar el certificado.

A continuación se muestra una salida de ejecución de ejemplo, donde nos deja claro, que no se va a auto-renovar automáticamente, por lo que deberemos ejecutar de nuevo este comando antes de la expiración del certificado, para su renovación. También vemos, las instrucciones para la creación del registro TXT en DNS.

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for www.midominio.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.www.midominio.com.

with the following value:

erareBF1C5gaMhzqE8Q-cX2gwv4_HciFrya7AAxLYRX

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.www.midominio.com.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/www.midominio.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/www.midominio.com/privkey.pem
This certificate expires on 2024-05-15.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Como vemos, los ficheros correspondientes al certificado que acabamos de generar, serán creados dentro del directorio /etc/letsencrypt/live. Eso sí, tendremos que encargarnos de:

  • La instalación y configuración del certificado (ej: utilizarlo en un NGINX que se ejecuta dockerizado, compartiendo los certificados mediante volúmenes).
  • Su futura renovación, que es una tarea periódica a tener en cuenta.

Aun así, esto mola porque hemos conseguido un certificado SSL gratis que ahora podemos utilizar con libertad, pero si tenemos varios servicios, por ejemplo, un Jenkins, un Sonar, un Nexus, un Gitea, un Keycloack, un Prometheus, un Grafana, etc., pues la verdad que es un poco rollo andarse con tanto certificado para tanto nombre y sus renovaciones periódicas posteriroes. ¿Qué podemos hacer en ese caso? Pues una opción es generar un único certificado wildcard, por ejemplo, para *.midominio.com, y utilizar ese mismo certificado en todos los servicios en que lo necesitemos. Bastaría con hacerlo con un comando como el siguiente. Fácil y sencillo.

sudo certbot certonly --manual --preferred-challenges dns --email mimail@gmail.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d *.midominio.com

Otra tarea que podemos necesitar, es generar un fichero en formato PFX con nuestro certificado SSL, para compartirlo con un tercero que nos pida ese formato, algo que podemos realizar fácilmente ejecutando un comando openssl como el siguiente.

sudo openssl pkcs12 -export -out ./midominio.com.pfx -inkey /etc/letsencrypt/live/midominio.com/privkey.pem -in /etc/letsencrypt/live/midominio.com/fullchain.pem -passout pass:P@ssw0rd

Poco más por hoy, como siempre, confío que la lectura resulte de interés.