systemli.letsencrypt
Rol de Ansible para obtener certificados SSL de Let's Encrypt
Este rol está diseñado para solicitar certificados SSL de Let's Encrypt, utilizando el desafío HTTP o el desafío DNS para su API ACME.
Características:
- Instala y configura certbot y el script ayudante para el desafío DNS
 - Soporta tanto el desafío HTTP como el desafío DNS
- Para el desafío HTTP, se soportan los plugins de autenticación 
apache,nginx,standaloneywebroot 
 - Para el desafío HTTP, se soportan los plugins de autenticación 
 - El desafío DNS utiliza una zona dedicada solo para los token de desafío AMCE, reduciendo los riesgos de seguridad de las actualizaciones dinámicas. El concepto se explica aquí
 - Reinicia los servicios al renovar el certificado usando post-hooks o un comando post-hook personalizado
 - Control de permisos a los certificados usando un grupo de sistema dedicado
 
Distribuciones soportadas:
- Debian 11 (Bullseye)
 - Debian 12 (Bookworm)
 
Probado en:
- Debian 11 (Bullseye)
 - Debian 12 (Bookworm)
 - CentOS7
 - Ubuntu 2204 (Jammy Jellyfish)
 
Realiza lo siguiente:
Cuando
letsencrypt_setupes True (el valor predeterminado), este rol:- Instala certbot
 - Registra una cuenta en Let's Encrypt
 - Instala los archivos/claves necesarios para el desafío DNS
 - Crea el grupo de sistema 'letsencrypt'
 
Cuando se invoca con la variable
letsencrypt_certllena:- Solicita un certificado SSL a través de la API ACME de Let's Encrypt, usando el desafío HTTP o el desafío DNS
 - Opcionalmente establece el post-hook para renovaciones del certificado (para reiniciar los servicios necesarios después)
 - Opcionalmente añade usuarios del sistema al grupo 'letsencrypt' para otorgarles acceso de lectura a los certificados SSL y sus claves privadas
 
Cómo funciona (ejemplos)
- Instalación de certbot
ansible-playbook site.yml -l localhost -t letsencrypt - Creación de un certificado mediante desafío HTTP y con autenticador 
webroot(reiniciando el servicio 'apache2' al renovar):ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub.example.org","domains":["sub.example.org"],"challenge":"http","http_auth":"webroot","webroot_path":"/var/www/sub.example.org","services":["apache2"]}}' - Creación de un certificado mediante desafío DNS (otorgando acceso de lectura a los certificados al usuario 'Debian-exim', reiniciando los servicios 'exim4' y 'dovecot' al renovar):
ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub2","domains":["sub2.example.org","sub2.another.example.org"],"challenge":"dns","services":["dovecot","exim4"],"users":["Debian-exim"]}}' - Creación de un certificado mediante desafío HTTP y con autenticador 
standalone(reutilizando la misma clave privada al renovar y ejecutando un script post-hook personalizado al renovar):ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub3","domains":["sub3.example.org"],"challenge":"http","http_auth":"standalone","reuse_key":True,"post_hook":"/usr/local/bin/cert-post-hook.sh"}}' 
Estructura esperada de la variable letsencrypt_cert
La variable letsencrypt_cert se espera que sea un diccionario:
letsencrypt_opts_extra: "--register-unsafely-without-email"
letsencrypt_cert:
  name: sub.example.org
  domains:
    - sub.example.org
  challenge: http
  http_auth: webroot
  webroot_path: /var/www/sub.example.org
  services:
    - apache2
o:
letsencrypt_cert:
  name: sub2
  domains:
    - sub2.example.org
    - sub2.another.example.org
  challenge: dns
  services:
    - dovecot
    - exim4
  users:
    - Debian-exim
o:
letsencrypt_cert:
  name: sub3
  domains:
    - sub3.example.org
  challenge: http
  http_auth: standalone
  reuse_key: True
  post_hook: "/usr/local/bin/cert-post-hook.sh"
letsencrypt_cert:
  name: sub3
  domains:
    - sub3.example.org
  challenge: http
  http_auth: standalone
  reuse_key: True
  deploy_hook: "/usr/local/bin/cert-post-hook.sh"
El diccionario soporta las siguientes claves:
name: nombre del certificado [opcional]domains: lista de dominios para el certificado [requerido]challenge: 'http' o 'dns' [requerido]- para el desafío 'http': 
http_auth: 'webroot', 'apache' o 'nginx' [opcional, por defecto 'webroot']- para 
http_auth'webroot':webroot_path[opcional, por defecto '/var/www'] 
 - para 
 
- para el desafío 'http': 
 services: lista de servicios a reiniciar en el post-hook [opcional]reuse_key: Reutilizar la misma clave privada al renovar el certificado. 'True' o 'False' (por defecto 'False')post_hook: Post-hook personalizado a ejecutar después de intentar obtener/renovar un certificado [opcional]deploy_hook: Deploy-hook personalizado a ejecutar después de un intento exitoso de obtener/renovar un certificado [opcional]renew_hook: Renew-hook personalizado a ejecutar una vez por cada certificado renovado después de la renovación del certificado [opcional]users: lista de usuarios a añadir al grupo de sistema 'letsencrypt' [opcional]
Preliminares generales
El rol se encarga de instalar certbot y solicitar certificados SSL usando ya sea el desafío HTTP o el desafío DNS. No instala o configura la infraestructura requerida (es decir, el servidor web Apache o un servidor DNS).
El rol se ha probado solo con Ansible 2.2. No se garantiza que funcione con versiones anteriores de Ansible.
El desafío HTTP
Requisitos:
- El nombre del dominio del certificado solicitado debe apuntar a el sistema
 - Para 
http_auth'apache', Apache2 debe estar instalado (y configurado) en el sistema - Para 
http_auth'nginx', NGINX debe estar instalado (y configurado) en el sistema 
El desafío DNS
Requisitos:
- Un servidor DNS con una zona dedicada, utilizada solo para el desafío DNS de ACME. Esta zona debe permitir actualizaciones dinámicas de DNS (NSUPDATE) para registros TXT (ver más abajo).
 - Los registros CNAME para 
_acme-challenge.sub.example.orgpara todos los nombres de dominio del certificado solicitado deben apuntar asub.example.org._le.example.org(dentro de la zona dedicada para el desafío DNS de ACME). - El contenido de la clave de actualización de DNS y las claves privadas de actualización de DNS deben estar disponibles en las variables de Ansible 
letsencrypt_ddns_keyyletsencrypt_ddns_privkey(preferiblemente dentro de un vault). 
Este rol instala un script ayudante para el desafío DNS en
/usr/local/bin/certbot-dns-hook.sh. Este script añadirá el token de validación al registro TXT en sub.example.org._le.example.org durante el desafío DNS y lo eliminará después.
Soporte para comodines con el desafío DNS
La obtención de certificados comodín debería funcionar sin problemas a través del desafío DNS.
Configurando bind9 para el desafío DNS
(Otra opción sería usar el servidor acme-dns para esto)
Genera una clave para actualizaciones dinámicas:
cd /etc/bind/keys
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER _le.example.org_ddns_update
chown -R bind:bind /etc/bind/keys
Añade la clave a tu configuración de bind (por ejemplo, en /etc/bind/named.conf.options):
key "_le.example.org_ddns_update" {
    algorithm hmac-sha512;
    secret "...";
};
Crea la zona para actualizaciones dinámicas:
$ORIGIN .
$TTL 86400	; 1 día
_le.example.org		IN SOA	ns1.example.org. postmaster.example.org. (
                2017061501 ; serial
                86400      ; refresco (1 día)
                3600       ; reintento (1 hora)
                2419200    ; caducidad (4 semanas)
                86400      ; mínimo (1 día)
                )
            NS	ns1.example.org.
            NS	ns2.example.org.
            TXT	"v=spf1 -all"
y configúralo en tu configuración de bind (por ejemplo, en /etc/bind/named.conf.local):
zone "_le.example.org" {
    type master;
    file "/etc/bind/zones/db._le.example.org";
    update-policy { grant _le.example.org_ddns_update wildcard *._le.example.org. TXT; };
};
Formato para /etc/letsencrypt/keys/ddns_update.key (de bind)
key "<clave>" {
    algorithm HMAC-SHA512;
    secret "<clave>";
};
Formato para /etc/letsencrypt/keys/ddns_update.private
Private-key-format: v1.3
Algorithm: 165 (HMAC_SHA512)
Key: <clave>
Bits: AAA=
Created: 20181017144534
Publish: 20181017144534
Activate: 20181017144534
Valores predeterminados de las variables de Ansible
# Realizar paso de configuración; establecer falso para desactivar
letsencrypt_setup: True
# Proporcionar datos de cuenta existentes para copiar
letsencrypt_account: ""
# letsencrypt_account:
#   hash: 1234567890abcdef1234567890abcdef
#   id: 123456789
#   creation_host: localhost
#   creation_dt: 2020-12-13T13:12:00Z
#   private_key:
#     n: 1234
#     e: 5678
#     d: 90ab
#     p: cdef
#     q: 1234
#     dp: 5678
#     dq: 90ab
#     qi: cdef
#     kty: RSA
# Establecer la dirección de correo electrónico asociada con la cuenta de Let's Encrypt
letsencrypt_account_email: ""
# Autenticador predeterminado para el desafío HTTP ('webroot' o 'apache')
letsencrypt_http_auth: webroot
# Ruta predeterminada del webroot para el autenticador 'webroot'
letsencrypt_webroot_path: /var/www
# Instalar el script ayudante del desafío DNS y la clave de actualización DNS
letsencrypt_dns_challenge: yes
# Configuración para las actualizaciones dinámicas de la zona DNS
# letsencrypt_ddns_server: ""
# letsencrypt_ddns_zone: ""
# letsencrypt_ddns_key: ""
# letsencrypt_ddns_privkey: ""
# Crear grupo de sistema 'letsencrypt' para el acceso a los certificados
letsencrypt_group: yes
# Reutilizar clave privada en la renovación del certificado?
letsencrypt_reuse_key: False
# ¿Permitir subconjunto de nombres?
letsencrypt_subset_names: True
# Establecer opciones adicionales globales de línea de comando para certbot
letsencrypt_opts_extra: ""
# Establecer la ruta para el directorio letsencrypt (¡sin "/" al final!)
letsencrypt_directory: /etc/letsencrypt
Pruebas
Para fines de prueba, la variable letsencrypt_test puede ser establecida. Si se establece en True, el rol utilizará servidores de prueba de Let's Encrypt para la creación de la cuenta y la obtención del certificado.
Para desarrollar y probar el rol utilizamos Molecule y Vagrant/Github Actions. En el entorno local, puedes probar fácilmente el rol con
molecule test
Licencia
Este rol de Ansible está licenciado bajo la GNU GPLv3.
Autor
Copyright 2017-2019 systemli.org (https://www.systemli.org/)
ansible-galaxy install systemli.letsencrypt