Installation réalisée par jvoisin et nicoo le mercredi 3 Août 2016.

Installation d'acmetool

Pin depuis testing

On pin acmetool depuis stretch, vu que ce n'est pas encore disponible via les backports.

#/etc/apt/preferences
Package: *
Pin: release n=jessie
Pin-Priority: 900
#/etc/apt/preferences.d/acmetools
Package: acmetool
Pin: release n=testing
Pin-Priority: -1

On se fend ensuite d'un apt update && apt upgrade, et on vérifie qu'on n'upgrade pas le système entier vers testing.

Installation du paquet

Un bête apt install acmetool.

Configuration

On prend le parti de ne pas laisser tourner acmetool en tant que root. C'est un mode supporté et documenté.

Création d'un user dédié

adduser --system --group --home /var/lib/acme/ acme
chsh -s /usr/sbin/nologin acme
passwd -l acme
etckeeper commit

Ajustement des droits d'accès

chown -Rf acme:acme /var/lib/acme
mkdir /usr/lib/acme/hooks

Configuration d'acmetool

sudo -u acme acmetool quickstart
  • On choisi d'utiliser directement le serveur « live ».
  • On utilise la méthode « webroot » pour faire interagir acmetool et le httpd :

      location /.well-known/acme-challenge {
          alias /var/lib/acme/webroot;
      }
    
  • On choisis adminsys@nos-oignons.net comme adresse de contact.

Modification du crontab

Par défaut, acmetool installe un cronjob qui lance acmetool --batch reconcile tous les jours.

On modifie le crontab en ajoutant MAILTO=root.

Configuration de Nginx

Obtention des certificats

sudo -u acme acmetool want {www.,}nos-oignons.{org,net,fr}

Changement de certificats

  • On pointe vers /var/lib/acme/live/nos-oignons.net/ pour les certificats.
  • On ajoute un « site » https-redirect pour rediriger depuis nos-oignons.{fr,org} vers .net :

        #/etc/nginx/sites-available/https-redirect
        server {
          listen   [::]:443 ssl;
          listen   443 ssl;
    
          include snippets/headers.conf;
    
          ssl_certificate     /var/lib/acme/live/nos-oignons.net/fullchain;
          ssl_certificate_key /var/lib/acme/live/nos-oignons.net/privkey;
    
          server_name nos-oignons.org www.nos-oignons.org nos-oignons.fr www.nos-oignons.fr;
    
          location / {
              return 301 https://nos-oignons.net$request_uri;
          }
    
      }
    
  • On fait un lien symbolique dans /etc/nginx/sites-enabled/

  • On se fend d'un nginx -t pour confirmer la configuration.
  • On relance nginx

Configuration de Postfix

  • La configuration antérieure avait un certificat (« snake oil ») pour bulbe.nos-oignons.net. C'est ce qu'on garde.
  • On obtient simplement une nouvelle clef et un nouveau certificat avec sudo -u acme acmetool want bulbe.nos-oignons.net.
  • On reconfigure Postfix :

      # /etc/postfix/main.cf
      smtpd_tls_cert_file=/var/lib/acme/live/bulbe.nos-oignons.net/fullchain
      smtpd_tls_key_file=/var/lib/acme/live/bulbe.nos-oignons.net/privkey
    
  • On teste :

      # swaks --tls --tls-verify bulbe.nos-oignons.net
      To: noexist@nos-oignons.net
      === Trying bulbe.nos-oignons.net:25...
      === Connected to bulbe.nos-oignons.net.
      <-  220 bulbe.nos-oignons.net ESMTP Postfix (Debian GNU/Oignons)
       -> EHLO bulbe.nos-oignons.net
      <-  250-bulbe.nos-oignons.net
      <-  250-PIPELINING
      <-  250-SIZE 10240000
      <-  250-VRFY
      <-  250-ETRN
      <-  250-STARTTLS
      <-  250-AUTH DIGEST-MD5 NTLM CRAM-MD5 LOGIN PLAIN
      <-  250-AUTH=DIGEST-MD5 NTLM CRAM-MD5 LOGIN PLAIN
      <-  250-ENHANCEDSTATUSCODES
      <-  250-8BITMIME
      <-  250 DSN
       -> STARTTLS
      <-  220 2.0.0 Ready to start TLS
      === TLS started with cipher TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256
      === TLS no local certificate set
      === TLS peer DN="/CN=bulbe.nos-oignons.net"
       ~> EHLO bulbe.nos-oignons.net
      <~  250-bulbe.nos-oignons.net
      <~  250-PIPELINING
      <~  250-SIZE 10240000
      <~  250-VRFY
      <~  250-ETRN
      <~  250-AUTH DIGEST-MD5 NTLM CRAM-MD5 LOGIN PLAIN
      <~  250-AUTH=DIGEST-MD5 NTLM CRAM-MD5 LOGIN PLAIN
      <~  250-ENHANCEDSTATUSCODES
      <~  250-8BITMIME
      <~  250 DSN
       ~> MAIL FROM:<root@bulbe.nos-oignons.net>
      <~  250 2.1.0 Ok
       ~> RCPT TO:<noexist@nos-oignons.net>
      <~* 550 5.1.1 <noexist@nos-oignons.net>: Recipient address rejected: User unknown in local recipient table
       ~> QUIT
      <~  221 2.0.0 Bye
      === Connection closed with remote host.
    
  • On met à jour la fingerprint sur les nœuds, et la documentation.
    Note : on pin maintenant la clef publique, vu que le certificat lui-même change.

  • On teste en envoyant un mail de test depuis les nœuds.
  • On s'assure qu'acmetool ne changera pas la clef RSA pour Postfix :

      # /var/lib/acme/desired/bulbe.nos-oignons.net-syghkqm6izf3fbm2sjalo4rnnq
      satisfy:
        names:
        - bulbe.nos-oignons.net
    
      request:
        key:
          id: k2425j72hots32y36ftqpsmrtktx2pug6hcpy2mcth6hgoofqxwq
    

    C'est une option cachée dans la doc.

Hooks acmetool

sudo

On donne à acmetool le droit d'exécuter les scripts contenus dans /var/lib/acme/hooks en tant que root :

# /etc/sudoers.d/05_acmetool
acme ALL=(root) NOPASSWD: /usr/lib/acme/hooks

Note : Faire ainsi ne pose pas vraiment de problème de sécurité, car le répertoire et son contenu appartiennent à root, et ne sont écrivables que par ce-dernier.

Nginx

On crée un simple /usr/lib/acme/hook/nginx.sh:

#!/bin/sh -e
if [ "$1" = "live-update" ]; then
    systemctl reload nginx
fi

On le met bit setuid : ce n'est pas effectif, mais ça indique à acmetool qu'ielle doit utiliser sudo.

Postfix

Contrairement à Nginx, on ne recharge que si le certificat de bulbe.nos-oignons.net change.

#!/bin/sh -e
if [ "$1" = "live-update" -a "$2" = "bulbe.nos-oignons.net" ]; then
    systemctl reload postfix
fi

Test & correction

On peut tester le bon fonctionnement des hooks avec la commande suivante :

sudo -u acme acmetool test-notify <nom d'hôte d'un certificat>

En testant, nicoo a découvert que ça ne marchait pas ... parce que le paquet Debian change l'emplacement des hooks pour /etc/acme/hooks. nicoo a corrigé la configuration en conséquence.

Changement des paramètres de clefs

On change les paramètres de clef pour du RSA 4k (par défaut) et l'extension OCSP-Must-Staple pour le certificat du serveur web :

# /var/lib/acme/conf/target
request:
  provider: https://acme-v01.api.letsencrypt.org/directory
  key:
    type: rsa
    rsa-size: 4096
  challenge:
    webroot-paths:
    - /var/lib/acme/webroot
# /var/lib/acme/desired/www.nos-oignons.org-j5thsdpg7fgtvempit6g4vyv2m
satisfy:
  names:
  - nos-oignons.net
  - nos-oignons.org
  - nos-oignons.fr
  - www.nos-oignons.net
  - www.nos-oignons.org
  - www.nos-oignons.fr

request:
  ocsp-must-staple: true

Ensuite, on force acmetool à générer un nouveau certificat :

% ll live
total 28K
lrwxrwxrwx 1 acme acme 61 Aug  4 21:13 bulbe.nos-oignons.net -> ../certs/k2425j72hots32y36ftqpsmrtktx2pug6hcpy2mc
th6hgoofqxwq
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 nos-oignons.fr -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7
ijtba
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 nos-oignons.net -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc
7ijtba
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 nos-oignons.org -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc
7ijtba
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 www.nos-oignons.fr -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55
kfc7ijtba
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 www.nos-oignons.net -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo5
5kfc7ijtba
lrwxrwxrwx 1 acme acme 61 Aug  4 20:44 www.nos-oignons.org -> ../certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo5
5kfc7ijtba
% ll certs
total 8.0K
drwxr-xr-x 2 acme acme 4.0K Aug  4 23:15 k2425j72hots32y36ftqpsmrtktx2pug6hcpy2mcth6hgoofqxwq
drwxr-xr-x 2 acme acme 4.0K Aug  4 23:15 sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
% sudo mv certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba{,.bak}
[sudo] password for nicoo:
% sudo -u acme acmetool reconcile
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/nos-oignons.fr -> ../certs/sw5ph3cgjg4blf
in2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/nos-oignons.net -> ../certs/sw5ph3cgjg4bl
fin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/nos-oignons.org -> ../certs/sw5ph3cgjg4bl
fin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/www.nos-oignons.fr -> ../certs/sw5ph3cgjg
4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/www.nos-oignons.net -> ../certs/sw5ph3cgj
g4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [WARN] fdb: broken symlink, removing: /var/lib/acme/live/www.nos-oignons.org -> ../certs/sw5ph3cgj
g4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba
20160805031106 [ERROR] acme.storage: failed to load certificate sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ij
tba.bak: cert ID mismatch: "sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba.bak" != "sw5ph3cgjg4blfin2yluaku
ofeer3vx6mxw46xsbo55kfc7ijtba"
20160805031115 [ERROR] acme.storage: failed to load certificate sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ij
tba.bak: cert ID mismatch: "sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba.bak" != "sw5ph3cgjg4blfin2yluaku
ofeer3vx6mxw46xsbo55kfc7ijtba"
% ll certs
total 12K
drwxr-xr-x 2 acme acme 4.0K Aug  5 03:11 edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojqluhwz4vyffa
drwxr-xr-x 2 acme acme 4.0K Aug  5 03:11 k2425j72hots32y36ftqpsmrtktx2pug6hcpy2mcth6hgoofqxwq
drwxr-xr-x 2 acme acme 4.0K Aug  4 23:15 sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba.bak
% ll live
total 28K
lrwxrwxrwx 1 acme acme 61 Aug  4 21:13 bulbe.nos-oignons.net -> ../certs/k2425j72hots32y36ftqpsmrtktx2pug6hcpy2mc
th6hgoofqxwq
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 nos-oignons.fr -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojqluhwz4
vyffa
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 nos-oignons.net -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojqluhwz
4vyffa
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 nos-oignons.org -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojqluhwz
4vyffa
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 www.nos-oignons.fr -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojqlu
hwz4vyffa
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 www.nos-oignons.net -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojql
uhwz4vyffa
lrwxrwxrwx 1 acme acme 61 Aug  5 03:11 www.nos-oignons.org -> ../certs/edtxofe3wztlpz22n4iwxzvzyeenzcsy7urvrvojql
uhwz4vyffa
% sudo systemctl reload nginx
% sudo rm -rf certs/sw5ph3cgjg4blfin2yluakuofeer3vx6mxw46xsbo55kfc7ijtba.bak

C'est l'occasion de tester les hooks de rotation de certificat.

Malheureusement, c'est aussi l'occasion pour nicoo de découvrir un bug dans acmetool : les certificats générés ne comportent pas le drapeau OCSP-Must-Staple ... ce qui a été rapporté et corrigé upstream dans la version 0.0.56.

Versionnage de la configuration

Vu qu'une partie de /var/lib/acme tient de la configuration (conf et desired), et qu'on versionne la configuration dans /etc avec etckeeper, on a déplacé ces deux dossiers vers /etc/acme et on les a remplacés par des liens symboliques :

# ls -l /etc/acme
total 4
drwxr-xr-x 2 root root 4096 Aug  8 19:03 hooks

# mv /var/lib/acme/{conf,desired} /etc/acme/
# ls -l /etc/acme/
total 12
drwxr-xr-x 2 acme acme 4096 Aug  8 21:48 conf
drwxr-xr-x 2 acme acme 4096 Aug  8 22:06 desired
drwxr-xr-x 2 root root 4096 Aug  8 19:03 hooks

# cd /var/lib/acme
# ln -s ../../../etc/acme/{conf,desired} .
# chown -R root:root /etc/acme/conf

/etc/acme/desired reste la propriété de l'user acme car de nouveaux fichiers de configuration sont créés lorsqu'on invoque acmetool want.