systemli.letsencrypt

Rol de Ansible para obtener certificados SSL de Let's Encrypt

Integración Ansible Galaxy

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, standalone y webroot
  • 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_setup es 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_cert llena:

    • 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']
  • 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.org para todos los nombres de dominio del certificado solicitado deben apuntar a sub.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_key y letsencrypt_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/)

Acerca del proyecto

Role to obtain Let's Encrypt SSL certificates

Instalar
ansible-galaxy install systemli.letsencrypt
Licencia
gpl-3.0
Descargas
25.7k
Propietario
Your friendly tech collective