Comment acquérir un certificat Let's Encrypt à l'aide d'Ansible sur Ubuntu 18.04

De Get Docs
Aller à :navigation, rechercher

L'auteur a sélectionné la Electronic Frontier Foundation pour recevoir un don dans le cadre du programme Write for DOnations.

Introduction

La gestion moderne de l'infrastructure se fait mieux à l'aide de processus et d'outils automatisés. L'acquisition d'un certificat Let's Encrypt à l'aide du client standard Certbot est simple et rapide, mais il s'agit généralement d'une tâche qui doit être effectuée manuellement lors de la mise en service des serveurs. Ceci est gérable pour une configuration de serveur individuelle, mais peut devenir fastidieux lors du déploiement d'une flotte plus importante.

L'utilisation d'un outil de gestion de configuration tel que Ansible pour acquérir un certificat rend cette tâche complètement automatique et reproductible. Si jamais vous devez reconstruire ou mettre à jour votre serveur, vous pouvez simplement exécuter votre Ansible playbook, plutôt que d'avoir à recommencer manuellement les étapes.

Dans ce didacticiel, vous allez écrire un playbook Ansible pour acquérir automatiquement un certificat Let's Encrypt pour une machine hôte Ansible.

Conditions préalables

Pour terminer ce tutoriel, vous aurez besoin de :

  • Deux serveurs Ubuntu 18.04 configurés en suivant la configuration initiale du serveur avec Ubuntu 18.04, y compris un utilisateur sudo non root.

Le premier serveur sera utilisé comme serveur Ansible, que nous appellerons Serveur Ansible tout au long de ce didacticiel. C'est là qu'Ansible s'exécutera pour envoyer les commandes à la machine hôte. Vous pouvez également utiliser votre machine locale ou toute autre machine sur laquelle votre inventaire Ansible est configuré comme votre serveur Ansible.

Sur votre serveur Ansible, vous aurez besoin :

Le deuxième serveur sera utilisé comme hôte Ansible, que nous appellerons la machine hôte ' tout au long de ce didacticiel. Il s'agit de la machine sur laquelle vous souhaitez configurer et émettre des certificats. Cette machine exécutera également un serveur Web pour servir les fichiers de validation d'émission de certificat.

Sur votre machine hôte, vous aurez besoin :

  • Un nom de domaine pour lequel vous pouvez acquérir un certificat TLS, avec les enregistrements DNS requis configurés pour pointer vers votre machine hôte Ansible '. Dans cet exemple particulier, le playbook acquerra un certificat valide pour your-domain et www.your-domain, mais il peut être ajusté pour d'autres domaines ou sous-domaines si nécessaire.
  • Un serveur Web accessible depuis Internet via le port 80 (HTTP), par exemple en suivant les étapes 1, 2 et 3 de Comment installer le serveur Web Apache sur Ubuntu 18.04. Il peut également s'agir d'un serveur Nginx ou de tout autre logiciel de serveur Web approprié.

Une fois que vous les avez prêts, connectez-vous à votre serveur Ansible en tant qu'utilisateur non root pour commencer.

Étape 1 - Configuration des paramètres du module Let's Encrypt Ansible

Ansible possède un module intégré nommé letsencrypt, qui vous permet d'acquérir des certificats TLS valides à l'aide du protocole ACME (Automated Certificate Management Environment).

Dans cette première étape, vous allez ajouter un fichier de configuration des variables hôtes pour définir les variables de configuration nécessaires à l'utilisation du module.

Remarque : Le module letsencrypt a été renommé acme_certificate depuis Ansible 2.6. Le nom letsencrypt est maintenant un alias de acme_certificate, il fonctionnera donc toujours, mais vous souhaitez utiliser acme_certificate à la place, pour assurer la pérennité de vos playbooks. Vous pouvez vérifier votre version Ansible en utilisant ansible --version. Au moment de la rédaction de ce didacticiel, les référentiels Ubuntu 18.04 Apt ne prennent pas encore en charge acme_certificate.


Tout d'abord, créez le répertoire host_vars Ansible sur votre serveur Ansible :

sudo mkdir /etc/ansible/host_vars

Ensuite, créez un nouveau fichier dans le répertoire /etc/ansible/host_vars avec le nom de votre machine Ansible host. Dans cet exemple, vous utiliserez host1 comme nom d'hôte :

sudo nano /etc/ansible/host_vars/host1

L'exemple de configuration suivant comprend tout ce dont vous avez besoin pour commencer, y compris : la méthode de validation et l'adresse du serveur, une adresse e-mail pour recevoir les rappels d'expiration de certificat et les répertoires où vos clés et certificats Let's Encrypt seront enregistrés.

Copiez l'exemple de configuration dans le fichier :

/etc/ansible/host_vars/host1

---
acme_challenge_type: http-01
acme_directory: https://acme-v02.api.letsencrypt.org/directory
acme_version: 2
acme_email: [email protected]
letsencrypt_dir: /etc/letsencrypt
letsencrypt_keys_dir: /etc/letsencrypt/keys
letsencrypt_csrs_dir: /etc/letsencrypt/csrs
letsencrypt_certs_dir: /etc/letsencrypt/certs
letsencrypt_account_key: /etc/letsencrypt/account/account.key
domain_name: your-domain

Enregistrez et fermez le fichier lorsque vous avez terminé.

Ajustez le nom de domaine et l'adresse e-mail si nécessaire. Vous pouvez utiliser n'importe quelle adresse e-mail, pas nécessairement celle de your-domain.

Certains des chemins de répertoire/fichier définis peuvent ne pas encore exister sur votre serveur. C'est acceptable; la première partie du playbook consistera à créer ces répertoires et à attribuer les autorisations correspondantes.

Vous avez ajouté les variables de configuration requises à votre fichier d'inventaire Ansible. Ensuite, vous commencerez à écrire le playbook pour acquérir un certificat.

Étape 2 - Création des répertoires Let's Encrypt et de la clé de compte

Dans cette étape, vous allez écrire les tâches Ansible que vous utiliserez pour créer les répertoires Let's Encrypt requis, attribuer les autorisations appropriées et générer une clé de compte Let's Encrypt.

Tout d'abord, créez un nouveau playbook nommé letsencrypt-issue.yml sur votre serveur Ansible dans un nouveau répertoire de votre choix, par exemple /home/user/ansible-playbooks :

cd ~
mkdir ansible-playbooks
cd ansible-playbooks
nano letsencrypt-issue.yml

Avant de pouvoir commencer à écrire des tâches Ansible, vous devez spécifier les hôtes et les paramètres associés. Ajustez les éléments suivants en fonction de la façon dont vous avez fait référence à vos hôtes dans le tutoriel prérequis. Ajoutez ensuite ce qui suit en haut du fichier :

letencrypt-issue.yml

---
- hosts: "host1"
  tasks:

Vous pouvez maintenant commencer à écrire les tâches requises, dont la première consiste à créer les répertoires du système de fichiers requis pour stocker les fichiers Let's Encrypt. Ajoutez la tâche Ansible suivante au fichier après le contenu précédent :

letencrypt-issue.yml

...
  - name: "Create required directories in /etc/letsencrypt"
    file:
      path: "/etc/letsencrypt/{{ item }}"
      state: directory
      owner: root
      group: root
      mode: u=rwx,g=x,o=x
    with_items:
    - account
    - certs
    - csrs
    - keys

Cette tâche Ansible créera les répertoires account, certs, csrs et keys dans /etc/letsencrypt, où se trouvent les fichiers requis pour les certificats d'acquisition seront stockés.

Vous définissez le propriétaire des répertoires sur root et appliquez les autorisations u=rwx,g=x,o=x afin que seul root y ait accès en lecture et en écriture. Ceci est recommandé car les répertoires contiendront des clés privées, demandes de signature de certificat (CSR) et des certificats signés, qui doivent rester confidentiels.

Ensuite, la clé de compte Let's Encrypt doit être créée. Vous l'utiliserez pour vous identifier auprès du service Let's Encrypt.

Ajoutez la tâche suivante à votre playbook :

letencrypt-issue.yml

...
  - name: "Generate a Let's Encrypt account key"
    shell: "if [ ! -f {{ letsencrypt_account_key }} ]; then openssl genrsa 4096 | sudo tee {{ letsencrypt_account_key }}; fi"

La clé de compte n'a pas besoin d'être recréée chaque fois que vous renouvelez les certificats, vous ajoutez donc également une vérification d'une clé existante if [ ! -f Modèle:Letsencrypt account key ];, pour vous assurer qu'elle n'est pas écrasée.

Vous continuerez à travailler dans letsencrypt-issue.yml à l'étape suivante, donc ne fermez pas encore ce fichier.

Vous avez créé votre playbook et mis en place la configuration et les tâches initiales afin de préparer l'acquisition de votre certificat Let's Encrypt. Ensuite, vous ajouterez d'autres tâches pour la génération de clé privée et de CSR.

Étape 3 - Génération de votre clé privée et de votre demande de signature de certificat

Au cours de cette étape, vous allez écrire les tâches du playbook pour générer la clé privée requise et la demande de signature de certificat.

La première tâche de cette section générera la clé privée requise pour votre certificat. Ajoutez ce qui suit à la fin de votre playbook que vous avez commencé à écrire à l'étape 2 :

letencrypt-issue.yml

...
  - name: "Generate Let's Encrypt private key"
    shell: "openssl genrsa 4096 | sudo tee /etc/letsencrypt/keys/{{ domain_name }}.key"

Les sous-domaines d'un même domaine seront tous ajoutés au même certificat grâce à l'utilisation de Subject Alternate Names (SAN), vous n'avez donc besoin de générer qu'une seule clé privée pour l'instant.

Vous utiliserez la tâche suivante pour générer une demande de signature de certificat (CSR) pour le certificat que vous souhaitez acquérir. Celui-ci est soumis à Let's Encrypt afin qu'ils valident et émettent chaque certificat.

Ajoutez ce qui suit à la fin du playbook :

letencrypt-issue.yml

...
  - name: "Generate Let's Encrypt CSR"
    shell: "openssl req -new -sha256 -key /etc/letsencrypt/keys/{{ domain_name }}.key -subj \"/CN={{ domain_name }}\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"\n[SAN]\nsubjectAltName=DNS:{{ domain_name }},DNS:www.{{ domain_name }}\")) | sudo tee /etc/letsencrypt/csrs/{{ domain_name }}.csr"
    args:
      executable: /bin/bash

Cette tâche génère un CSR pour votre domaine, avec le sous-domaine www ajouté au certificat en tant que SAN.

Vous continuerez à travailler dans letsencrypt-issue.yml à l'étape suivante, donc ne fermez pas encore ce fichier.

Vous avez écrit les tâches Ansible pour générer la clé privée et le CSR pour votre certificat. Ensuite, vous travaillerez sur les tâches qui lanceront le processus de validation et d'émission.

Étape 4 - Démarrage du processus de validation ACME

Dans cette étape, vous allez rédiger une tâche pour soumettre la demande de signature de certificat à Let's Encrypt à l'aide des fichiers générés à partir de la tâche documentée à l'étape 3. Cela renverra certains fichiers challenge, que vous devrez servir sur votre serveur Web afin de prouver la propriété du nom de domaine et du sous-domaine pour lesquels vous demandez un certificat.

La tâche suivante soumettra le CSR pour your-domain. Ajoutez-le à la fin de votre playbook :

letencrypt-issue.yml

...
  - name: "Begin Let's Encrypt challenges"
    letsencrypt:
      acme_directory: "{{ acme_directory }}"
      acme_version: "{{ acme_version }}"
      account_key_src: "{{ letsencrypt_account_key }}"
      account_email: "{{ acme_email }}"
      terms_agreed: 1
      challenge: "{{ acme_challenge_type }}"
      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}.crt"
      remaining_days: 91
    register: acme_challenge_your_domain

Cette tâche utilise largement les variables que vous avez configurées à l'étape 1. Il enregistre une variable contenant les fichiers de challenge ACME que vous utiliserez à l'étape suivante. Vous devrez ajuster manuellement le nom de la variable pour qu'il contienne your-domain, mais avec tous les caractères . remplacés par un _, car les points ne peuvent pas être utilisés dans un nom de variable . Par exemple, la variable pour example.com deviendrait acme_challenge_example_com.

Vous continuerez à travailler dans letsencrypt-issue.yml à l'étape suivante, donc ne fermez pas encore ce fichier.

Vous avez écrit une tâche pour soumettre votre CSR à Let's Encrypt. Ensuite, vous allez ajouter une tâche pour implémenter les fichiers de challenge ACME pour la finalisation du processus de validation du certificat.

Étape 5 - Mise en œuvre des fichiers ACME Challenge

Dans cette étape, vous allez écrire une tâche Ansible pour lire et implémenter les fichiers de challenge ACME. Ces fichiers prouvent que vous êtes éligible pour acquérir un certificat pour les domaines et sous-domaines demandés.

Les fichiers de challenge ACME doivent être servis sur un serveur Web écoutant sur le port 80, sur le chemin /.well-known/acme-challenge/ du domaine ou du sous-domaine pour lequel vous demandez un certificat. Par exemple, afin de valider la demande de certificat pour www.your-domain, le fichier de challenge ACME devra être accessible sur Internet au chemin suivant : http://www.your-domain/.well-known/acme-challenge.

La méthode de diffusion de ces fichiers aux destinations requises varie considérablement en fonction de la configuration actuelle de votre serveur Web. Cependant, dans ce guide, nous supposerons que vous disposez d'un serveur Web (selon le didacticiel prérequis) configuré pour servir les fichiers hors du répertoire /var/www/html. Par conséquent, vous devrez peut-être ajuster la tâche en conséquence afin d'être compatible avec la configuration de votre propre serveur Web.

Tout d'abord, ajoutez la tâche suivante qui crée la structure de répertoires .well-known/acme-challenge/ requise pour servir les fichiers jusqu'à la fin de votre playbook :

letencrypt-issue.yml

...
  - name: "Create .well-known/acme-challenge directory"
    file:
      path: /var/www/html/.well-known/acme-challenge
      state: directory
      owner: root
      group: root
      mode: u=rwx,g=rx,o=rx

Assurez-vous d'ajuster le chemin en conséquence si vous utilisez un répertoire autre que /var/www/html pour servir les fichiers avec votre serveur Web.

Ensuite, vous allez implémenter les fichiers de challenge ACME qui ont été enregistrés dans la variable acme_challenge_your-domain à l'étape 4 avec la tâche suivante :

letencrypt-issue.yml

...
  - name: "Implement http-01 challenge files"
    copy:
      content: "{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource_value'] }}"
      dest: "/var/www/html/{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource'] }}"
      owner: root
      group: root
      mode: u=rw,g=r,o=r
    with_items:
    - "{{ domain_name }}"
    - "www.{{ domain_name }}"

Notez que vous devez ajuster manuellement le nom de la variable acme_challenge_your_domain dans la tâche à définir sur le nom de votre variable de défi ACME, qui est acme_challenge_ suivi de votre nom de domaine, mais avec tous les [X195X ] caractères remplacés par _. Cette tâche Ansible copie les fichiers de validation ACME de la variable dans le chemin .well-known/acme-challenge sur votre serveur Web. Cela permettra à Let's Encrypt de les récupérer afin de vérifier la propriété du domaine et votre éligibilité à acquérir un certificat.

Vous continuerez à travailler dans letsencrypt-issue.yml à l'étape suivante, donc ne fermez pas encore ce fichier.

Vous avez écrit les tâches Ansible requises pour créer le répertoire et les fichiers de validation ACME. Ensuite, vous terminerez le processus de vérification ACME et acquerrez le certificat signé.

Étape 6 - Acquisition de votre certificat

Dans cette étape, vous allez écrire une tâche pour déclencher Let's Encrypt afin de vérifier les fichiers de challenge ACME que vous avez soumis, ce qui vous permettra d'acquérir votre ou vos certificats signés.

La tâche suivante valide les fichiers de challenge ACME que vous avez implémentés à l'étape 5 et enregistre vos certificats signés dans les chemins spécifiés. Ajoutez-le à la fin de votre playbook :

letencrypt-issue.yml

...
  - name: "Complete Let's Encrypt challenges"
    letsencrypt:
      acme_directory: "{{ acme_directory }}"
      acme_version: "{{ acme_version }}"
      account_key_src: "{{ letsencrypt_account_key }}"
      account_email: "{{ acme_email }}"
      challenge: "{{ acme_challenge_type }}"
      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
      chain_dest: "{{ letsencrypt_certs_dir }}/chain_{{ domain_name }}.crt"
      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}"
      data: "{{ acme_challenge_your_domain }}"

Comme pour l'étape 4, cette tâche utilise les variables que vous avez configurées à l'étape 1. Une fois la tâche terminée, elle enregistrera le certificat signé dans les chemins spécifiés, vous permettant de commencer à l'utiliser pour votre application ou service.

Notez que vous devrez ajuster manuellement la valeur data dans la tâche à définir sur le nom de votre variable de défi ACME, de la même manière qu'à l'étape 5.

Vous trouverez ci-dessous le playbook complet montrant chacune des tâches que vous avez ajoutées :

letencrypt-issue.yml

- hosts: "host1"
  tasks:

  - name: "Create required directories in /etc/letsencrypt"
    file:
      path: "/etc/letsencrypt/{{ item }}"
      state: directory
      owner: root
      group: root
      mode: u=rwx,g=x,o=x
    with_items:
    - account
    - certs
    - csrs
    - keys

  - name: "Generate a Let's Encrypt account key"
    shell: "if [ ! -f {{ letsencrypt_account_key }} ]; then openssl genrsa 4096 | sudo tee {{ letsencrypt_account_key }}; fi"

  - name: "Generate Let's Encrypt private key"
    shell: "openssl genrsa 4096 | sudo tee /etc/letsencrypt/keys/{{ domain_name }}.key"

  - name: "Generate Let's Encrypt CSR"
    shell: "openssl req -new -sha256 -key /etc/letsencrypt/keys/{{ domain_name }}.key -subj \"/CN={{ domain_name }}\" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf \"\n[SAN]\nsubjectAltName=DNS:{{ domain_name }},DNS:www.{{ domain_name }}\")) | sudo tee /etc/letsencrypt/csrs/{{ domain_name }}.csr"
    args:
      executable: /bin/bash

  - name: "Begin Let's Encrypt challenges"
    letsencrypt:
      acme_directory: "{{ acme_directory }}"
      acme_version: "{{ acme_version }}"
      account_key_src: "{{ letsencrypt_account_key }}"
      account_email: "{{ acme_email }}"
      terms_agreed: 1
      challenge: "{{ acme_challenge_type }}"
      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}.crt"
      remaining_days: 91
    register: acme_challenge_your_domain

  - name: "Create .well-known/acme-challenge directory"
    file:
      path: /var/www/html/.well-known/acme-challenge
      state: directory
      owner: root
      group: root
      mode: u=rwx,g=rx,o=rx

  - name: "Implement http-01 challenge files"
    copy:
      content: "{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource_value'] }}"
      dest: "/var/www/html/{{ acme_challenge_your_domain['challenge_data'][item]['http-01']['resource'] }}"
      owner: root
      group: root
      mode: u=rw,g=r,o=r
    with_items:
    - "{{ domain_name }}"
    - "www.{{ domain_name }}"

  - name: "Complete Let's Encrypt challenges"
    letsencrypt:
      acme_directory: "{{ acme_directory }}"
      acme_version: "{{ acme_version }}"
      account_key_src: "{{ letsencrypt_account_key }}"
      account_email: "{{ acme_email }}"
      challenge: "{{ acme_challenge_type }}"
      csr: "{{ letsencrypt_csrs_dir }}/{{ domain_name }}.csr"
      dest: "{{ letsencrypt_certs_dir }}/{{ domain_name }}.crt"
      chain_dest: "{{ letsencrypt_certs_dir }}/chain_{{ domain_name }}.crt"
      fullchain_dest: "{{ letsencrypt_certs_dir }}/fullchain_{{ domain_name }}"
      data: "{{ acme_challenge_your_domain }}"

Enregistrez et fermez votre fichier lorsque vous avez terminé.

Vous avez ajouté la tâche pour relever les défis ACME et acquérir votre certificat signé. Ensuite, vous exécuterez le playbook sur votre machine hôte Ansible ' afin d'exécuter toutes les actions.

Étape 7 - Exécution de votre Playbook

Maintenant que vous avez écrit le playbook et toutes les tâches requises, vous pouvez l'exécuter sur votre machine hôte Ansible ' pour émettre le certificat.

Depuis votre serveur Ansible, vous pouvez exécuter le playbook à l'aide de la commande ansible-playbook :

ansible-playbook letsencrypt-issue.yml

Cela exécutera le playbook, une tâche à la fois. Vous verrez une sortie semblable à la suivante :

OutputPLAY [host1] **********************************************************************************

TASK [Gathering Facts] ************************************************************************
ok: [host1]

TASK [Create required directories in /etc/letsencrypt] ****************************************
changed: [host1] => (item=account)
changed: [host1] => (item=certs)
changed: [host1] => (item=csrs)
changed: [host1] => (item=keys)

TASK [Generate a Let's Encrypt account key] ***************************************************
changed: [host1]

TASK [Generate Let's Encrypt private key] *****************************************************
changed: [host1]

TASK [Generate Let's Encrypt CSR] *************************************************************
changed: [host1]

TASK [Begin Let's Encrypt challenges] *********************************************************
changed: [host1]

TASK [Create .well-known/acme-challenge directory] ********************************************
changed: [host1]

TASK [Implement http-01 challenge files] ******************************************************
changed: [host1] => (item=your-domain)
changed: [host1] => (item=www.your-domain)

TASK [Complete Let's Encrypt challenges] ******************************************************
changed: [host1]

PLAY RECAP ************************************************************************************
host1                      : ok=9    changed=8    unreachable=0    failed=0

Si des erreurs sont rencontrées pendant l'exécution du playbook, elles seront affichées pour votre examen.

Une fois le playbook terminé, votre certificat Let's Encrypt valide sera enregistré dans le répertoire /etc/letsencrypt/certs sur votre machine hôte. Vous pouvez ensuite l'utiliser, avec la clé privée dans /etc/letsencrypt/keys, pour sécuriser les connexions à votre serveur Web, serveur de messagerie, etc.

Les certificats Let's Encrypt sont valides pendant 90 jours par défaut. Vous recevrez des rappels de renouvellement par e-mail à l'adresse que vous avez indiquée à l'étape 1. Pour renouveler votre certificat, vous pouvez réexécuter le playbook. Assurez-vous de vérifier que tous les services utilisant votre certificat ont récupéré le nouveau, car vous devrez parfois l'installer manuellement, le déplacer vers un répertoire particulier ou redémarrer le service pour qu'il adopte correctement le nouveau certificat.

Dans cette étape, vous avez exécuté votre playbook qui a émis votre certificat Let's Encrypt valide.

Conclusion

Dans cet article, vous avez écrit un playbook Ansible pour demander et acquérir un certificat Let's Encrypt valide.

Dans une prochaine étape, vous pouvez envisager d'utiliser votre nouveau playbook pour émettre des certificats pour une grande flotte de serveurs. Vous pouvez même créer un serveur de validation ACME central qui peut émettre des certificats de manière centralisée et les distribuer aux serveurs Web.

Enfin, si vous souhaitez en savoir plus sur la spécification ACME et le projet Let's Encrypt, vous pouvez consulter les liens suivants :

Vous pouvez également consulter d'autres didacticiels Ansible pertinents :