Plantilla de validación DNS de LetsEncrypt usando Cloudflare

Hola chicos

Necesitaba usar el método DNS para autenticar la propiedad de mi certificado SSL con Let’s Encrypt.

Tomé una copia del archivo web.letsencrypt.ssl.template.yml existente que se encuentra en /var/discourse/templates/ y lo modifiqué para usar el método de Integración Automática de API DNS. A continuación, presento mi plantilla de ejemplo, agradecería cualquier sugerencia sobre cómo mejorarla.

Llamé a este archivo web.letsencrypt.ssl.dns.template.yml

env:
  LETSENCRYPT_DIR: "/shared/letsencrypt"
  DISCOURSE_FORCE_HTTPS: true

hooks:
  after_ssl:
    - exec:
       cmd:
         - if [ -z "$LETSENCRYPT_ACCOUNT_EMAIL" ]; then echo "La variable de entorno LETSENCRYPT_ACCOUNT_EMAIL es requerida y no ha sido establecida."; exit 1; fi
         - /bin/bash -c "if [[ ! \"$LETSENCRYPT_ACCOUNT_EMAIL\" =~ ([^@]+)@([^\\.]+) ]]; then echo \"LETSENCRYPT_ACCOUNT_EMAIL no es una dirección de correo electrónico válida\"; exit 1; fi"

    - exec:
       cmd:
         - cd /root && git clone --branch 3.0.7 --depth 1 https://github.com/acmesh-official/acme.sh.git && cd /root/acme.sh
         - touch /var/spool/cron/crontabs/root
         - install -d -m 0755 -g root -o root $LETSENCRYPT_DIR
         - cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --install --log "${LETSENCRYPT_DIR}/acme.sh.log"
         - cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --upgrade --auto-upgrade
         - cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --set-default-ca  --server  letsencrypt 

    - file:
       path: /etc/runit/1.d/letsencrypt
       chmod: "+x"
       contents: |
        #!/bin/bash
        
        issue_cert() {
          export CF_Token="$ENV_LETSENCRYPT_CF_TOKEN"
          export CF_Account_ID="$ENV_LETSENCRYPT_CF_ACCOUNT_ID"
          export CF_Zone_ID="$ENV_LETSENCRYPT_CF_ZONE_ID"
          LE_WORKING_DIR="${LETSENCRYPT_DIR}" $ENV_LETSENCRYPT_DIR/acme.sh --issue --dns $ENV_LETSENCRYPT_DNS_PROVIDER $2 -d $ENV_DISCOURSE_HOSTNAME --keylength $1 -w /var/www/discourse/public
        }

        cert_exists() {
          [[ "$(cd ${ENV_LETSENCRYPT_DIR}/${ENV_DISCOURSE_HOSTNAME}$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")"]]
        }

        ########################################################
        # Certificado RSA
        ########################################################
        issue_cert "4096"

        if ! cert_exists ""; then
          # Intenta emitir el certificado de nuevo si algo sale mal
          issue_cert "4096" "--force"
        fi

        LE_WORKING_DIR="${LETSENCRYPT_DIR}" $ENV_LETSENCRYPT_DIR/acme.sh \
          --installcert \
          -d $ENV_DISCOURSE_HOSTNAME \
          --fullchainpath /shared/ssl/$ENV_DISCOURSE_HOSTNAME.cer \
          --keypath /shared/ssl/$ENV_DISCOURSE_HOSTNAME.key \
          --reloadcmd "sv reload nginx"

        ########################################################
        # Certificado ECDSA
        ########################################################
        issue_cert "ec-256"

        if ! cert_exists "_ecc"; then
          # Intenta emitir el certificado de nuevo si algo sale mal
          issue_cert "ec-256" "--force"
        fi

        LE_WORKING_DIR="${LETSENCRYPT_DIR}" $ENV_LETSENCRYPT_DIR/acme.sh \
          --installcert --ecc \
          -d $ENV_DISCOURSE_HOSTNAME \
          --fullchainpath /shared/ssl/$ENV_DISCOURSE_HOSTNAME_ecc.cer \
          --keypath /shared/ssl/$ENV_DISCOURSE_HOSTNAME_ecc.key \
          --reloadcmd "sv reload nginx"

        if cert_exists "" || cert_exists "_ecc"; then
          grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
        fi

    - replace:
       filename: "/etc/nginx/conf.d/discourse.conf"
       from: /ssl_certificate.+/
       to: |
         ssl_certificate /shared/ssl/$ENV_DISCOURSE_HOSTNAME.cer;
         ssl_certificate /shared/ssl/$ENV_DISCOURSE_HOSTNAME_ecc.cer;

    - replace:
       filename: /shared/letsencrypt/account.conf
       from: /#?ACCOUNT_EMAIL=.+/
       to: |
         ACCOUNT_EMAIL=$ENV_LETSENCRYPT_ACCOUNT_EMAIL

    - replace:
       filename: "/etc/nginx/conf.d/discourse.conf"
       from: /ssl_certificate_key.+/
       to: |
         ssl_certificate_key /shared/ssl/$ENV_DISCOURSE_HOSTNAME.key;
         ssl_certificate_key /shared/ssl/$ENV_DISCOURSE_HOSTNAME_ecc.key;

    - replace:
       filename: "/etc/nginx/conf.d/discourse.conf"
       from: /add_header.+/
       to: |
         add_header Strict-Transport-Security 'max-age=63072000';

Hay algunas variables de entorno adicionales que necesita agregar a app.yml y posiblemente modificar si no está utilizando Cloudflare como su proveedor de DNS. Todas las configuraciones de API de los diferentes proveedores están aquí

Esto es lo que agregué a mi app.yml en la sección templates

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  ## Descomenta la siguiente línea para habilitar el oyente IPv6
  #- "templates/web.ipv6.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## Descomenta estas dos líneas si deseas agregar Let's Encrypt (https)
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.dns.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

Y más abajo, en la sección env.

## Si agregaste la plantilla de Let's Encrypt, descomenta a continuación para obtener un certificado SSL gratuito
  LETSENCRYPT_ACCOUNT_EMAIL: me@mydomain.com
  LETSENCRYPT_CF_TOKEN: "TU_TOKEN"
  LETSENCRYPT_CF_ACCOUNT_ID: "TU_ACCOUNT_ID"
  LETSENCRYPT_CF_ZONE_ID: "TU_ZONE_ID"
  LETSENCRYPT_DNS_PROVIDER: "TU_PROVEEDOR_DNS" ## por ejemplo, dns_cf

Después de actualizar esos archivos, simplemente ejecuté el comando para reconstruir la aplicación docker

cd /var/discourse
./launcher rebuild app 

Una vez reconstruido, deberías tener tu aplicación ejecutándose en https:// y debería haber un trabajo cron que verifique diariamente si tu certificado necesita ser actualizado. Si necesita ser actualizado, obtendrá un nuevo certificado y lo instalará automáticamente.

Espero que esto ayude a alguien.

2 Me gusta

EDITAR: Acabo de alcanzar el límite de 5 certificados de Let’s Encrypt (por dominio exacto) por semana.

¿Tuviste algún problema al generar el certificado _ecc?

Usando tu publicación, el archivo principal website.com.cer se genera con éxito, sin embargo, el archivo website.com_ecc.cer muestra 0 bytes (la clave _ecc.key está bien).

Pero ambos certificados son emitidos por el mismo método issue_cert, por lo que por alguna razón el principal funciona y el _ecc falla.