¿Por qué Certbot no puede ejecutar scripts de post-hook?

¿Por qué Certbot no puede ejecutar scripts de post-hook?

Este es mi primer intento de renovar los certificados Let's Encrypt a través de Certbot. Después de leer detenidamente la guía del usuario de Certbot, creé dos scripts de enlace de publicación como este:

root@pelargir:~# ls -l /etc/letsencrypt/renewal-hooks/post
total 8
-rwxr-xr-x 1 root root 697 Aug 29 16:35 10-setup-courier.sh
-rwxr-xr-x 1 root root 377 Aug 29 16:32 20-restart-services.sh

Luego ejecuté el proceso de renovación manualmente en la línea de comando (es decir, no mediante cron). Esto logró renovar los certificados, pero no pudo ejecutar los scripts de enlace de publicación anteriores. Aquí está el resultado relevante:

[...]
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh" returned error code 127
Error output from 10-setup-courier.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh: not found

Running post-hook command: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/20-restart-services.sh" returned error code 127
Error output from 20-restart-services.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh: not found
[...]

No tengo idea de por qué sucede esto. Verifiqué dos veces:

  • Los archivos de script existen
  • Los archivos de script son ejecutables.
  • Puedo ejecutar los scripts manualmente (con las variables de entorno configuradas RENEWED_DOMAINSy RENEWED_LINEAGEexportadas) y hacen su trabajo como se esperaba.

Otra cosa que probablemente debería mencionar es que ejecuto Certbot dentro de una imagen de Docker porque estoy trabajando con certificados comodín. Mi proveedor de DNS es Cloudflare. Aquí está la línea de comando que estoy usando para iniciar el proceso de renovación:

docker run -it --rm --name certbot \
           -v "/etc/letsencrypt:/etc/letsencrypt" \
           -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
           certbot/dns-cloudflare
           renew

La imagen de Docker ejecuta Certbot versión 0.25.0. El sistema es Debian 9 (stretch), recientemente actualizado desde Debian 8 (jessie).

¿Alguna pista de cuál podría ser el problema?


EDITAR: Según lo solicitado, aquí está el contenido de los dos archivos, ligeramente editado para reemplazar mi dominio con "ejemplo.com":

root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh 
#!/bin/bash

# Exit immediately if a command exits with non-zero status
set -e

case $RENEWED_DOMAINS in
  # Courier runs only under a example.com subdomain
  example.com)

    # We don't care about file permissions because we know that the
    # filesystem folder where we generate the file is not generally
    # accessible
    cat "$RENEWED_LINEAGE/fullchain.pem" "$RENEWED_LINEAGE/privkey.pem" >"$RENEWED_LINEAGE/courier.cert-and-key.unsecure"
    ;;
esac

root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
#!/bin/bash

# Exit immediately if a command exits with non-zero status
set -e

case $RENEWED_DOMAINS in
  # Courier and Exim run only under a example.com subdomain
  *example.com*)
    systemctl restart courier-imap.service
    systemctl restart exim4.service
    systemctl restart apache2.service
    ;;

  # Apache has vhosts for all domains. Unfortunately the daemon is
  # restarted several times if several certificates are renewed.
  *)
    systemctl restart apache2.service
    ;;
esac

Respuesta1

Sus scripts de shell usan un shebang #!/bin/bash, lo que significa que deben ejecutarse con ese programa, pero el contenedor Docker en el que se ejecutan no incluye bash. Es por eso que /bin/shinforma el not founderror confuso al llamar a estos scripts obviamente presentes. No son los scripts los que no se encuentran, sino el intérprete de bash con el que solicitó ejecutarlos.

Puede resolver el problema cambiando el intérprete de scripts /bin/shy eliminando cualquier bash-ismo de los scripts (probablemente rápido y fácil), o instalando bash en el contenedor (probablemente desordenado).

información relacionada