Nous allons ici prendre un cas particulier de création de certificats SSL via let's encrypt : le DNS challenge.

Pour rappel, il existe 3 différents types de challenges afin de valider l'identité de votre site web auprès de l'API let's encrypt :

  • HTTP-01
  • DNS-01
  • TLS-ALPN-01

Vous trouverez également sur internet des informations sur un 4éme challenge, désactivé depuis Mars 2019 :

  • TLS-SNI-01

Les deux challenges les plus fréquemment utilisés sont le challenge HTTP et le TLS. Je vais toutefois m'attarder aujourd'hui sur le challenge DNS. Pourquoi utiliser ce challenge plutôt que les deux précédemment cités ? Quel(s) intérêt(s) ?

Le DNS challenge

En quoi consiste cette méthode de vérification ?

En réalité, cette méthode consiste à vérifier que vous êtes réellement le propriétaire d'un nom de domaine en créant des enregistrements DNS au format TXT. Cet enregistrement sera dérivé du token ACME, envoyé au client, et de votre identifiant de compte. Il se présente donc sous la forme d'un enregistrement TXT du type _acme-challenge.<YOUR_DOMAIN>.

Ce type de challenge offre quelques avantages :

  • Fournir des certificats Wildcards,
  • Obtenir des certificats sans donner un accès HTTP ou HTTPS externes à votre machine.

Mais aussi des inconvénients :

  • Garder des identifiants d'API DNS sur votre serveur web.
  • Tous les fournisseurs DNS n'offrent pas d'API,
  • Le temps de propagation DNS.

Le DNS challenge n'est surement pas le plus utilisé car il nécessite de donner à Traefik des droits, afin de créer des enregistrements DNS du type TXT. Pour des raisons de sécurité donc, de nombreuses entreprises ou service IT vont donc éviter l'utilisation de cette solution.

Dans notre cas, je souhaite fournir un certificat SSL à un service interne ( qui n'est pas en frontal sur internet ). Nous allons voir comment mettre en place cette solution avec Traefik et mon fournisseur DNS : OVH, et - bien évidemment - de façon sécurisée.

API OVH

Tout d'abord nous devons permettre à Traefik de créer et supprimer des enregistrements DNS. OVH fournit une API qui permet d'interagir avec différents éléments de votre compte client, notamment vos DNS.

Vous devez d'abord pour cela, créer un compte d'application sur l'API fournit par OVH. Pour créer ce compte, rendez-vous à l'adresse suivante :

  • https://eu.api.ovh.com/createApp/

Une fois vos informations de compte saisie, vous allez obtenir votre identifiant d'application ( Application Key ) et son mot de passe ( Application Secret ) pour votre application.

Vous pouvez vérifier sur l'API d'OVH que votre application est bien créée, pour cela utilisez la console à disposition sur l'adresse suivante : https://eu.api.ovh.com/console

Enfin rechercher l'élément suivant : /me/api/application et utilisez la méthode GET pour obtenir la liste de vos applications :

Dans mon cas je possède une application : 103430.

On peut vérifier cette application en utilisant la méthode GET /me/api/application/{applicationID}:

Il est maintenant nécessaire de donner des droits à notre application. Qu'est-elle autoriser à faire sur mon compte OVH ?

Pour cela je vais utiliser curl mais vous pouvez également le faire à l'aide de l'interface suivante : https://eu.api.ovh.com/createToken/

Ma commande curl :

$ curl -XPOST -H"X-Ovh-Application: 96RP9WCaLT9yJvBS" -H "Content-type: application/json" \
https://eu.api.ovh.com/1.0/auth/credential  -d '{
    "accessRules": [
        {
            "method": "POST",
            "path": "/domain/zone/<domain.com>/record"
        },
        {
            "method": "POST",
            "path": "/domain/zone/<domain.com>/refresh"
        },
        {
            "method": "DELETE",
            "path": "/domain/zone/<domain.com>/record/*"
        }
    ],
    "redirection":"https://www.<domain.com>/"
}'

Je vais donc autoriser mon compte à utiliser les méthodes POST et DELETE de l'API pour un nom de domaine bien précis : <domain.com> dans l'exemple, qui est bien évidemment à remplacer par vos informations.

Le paramètre de redirection n'est pas obligatoire, il va juste permettre de renvoyer cette page une fois connecté sur l'API.

Vous allez recevoir une réponse du type :

{"state":"pendingValidation","validationUrl":"https://eu.api.ovh.com/auth/?credentialToken=sBpLTCzRaOBa7qMVOMB","consumerKey":"K7ltlP9Xj5P5C3HaCwyPoI26AfFDNqnZ"}

Notez bien votre consumerKey, elle va servir à Traefik pour créer des enregistrements. Il est nécessaire de vous connecter à l'adresse suivante : https://eu.api.ovh.com/auth/?credentialToken=XXXXX  afin de valider les droits de votre application :

⚠️ Pensez à modifier la durée de validité des droits, je vous conseille de choisir intelligemment le délai. Une durée trop longue peut être un risque de sécurité alors qu'un choix trop court peut lui devenir contraignant techniquement. ⚠️

Vous allez être redirigé vers la page indiquée dans le paramètre redirection après la connexion.

Une dernière vérification, celle-ci va nous permettre de valider la création de nos droits. Je vais tout d'abord récupérer l'identifiant des droits de l'application avec la méthode GET /me/api/credential :

Ensuite je vais pouvoir visualiser ce doit avec la méthode GET /me/api/credential/{credentialID} :

Nous avons configuré notre application sur l'API d'OVH. Nous allons pouvoir configurer Traefik afin d'utiliser le DNS challenge !

Configuration de Traefik

Finalement il s'agit de la partie la plus simple de ce tutoriel 😂

Nous allons fournir les informations de connexion à Traefik, afin de créer les entrées DNS automatiquement lorsque c'est nécessaire. Afin de réaliser cette configuration, il est nécessaire de modifier deux fichiers de notre configuration :

  • docker-compose.yml : Les variables d'environnement dans la déclaration du service,
  • traefik.yml : Déclarer l'utilisation du challenge DNS dans le fichier de configuration statique au format YML ou TOML.

Ajout des variables d'environnement :

    environment:
      - "TZ=Europe/Paris"
      - "OVH_ENDPOINT=ovh-eu"
      - "OVH_APPLICATION_KEY=96RP9WCaLT9yJvBS"
      - "OVH_APPLICATION_SECRET=9bedrf8SXjgxgvLigA22exk3jDN9vMlB"
      - "OVH_CONSUMER_KEY=K7ltlP9Xj5P5C3HaCwyPoI26AfFDNqnZ"

Il est nécessaire  de déclarer l'utilisation du DNS dans la partie associée à let's encrypt :

certificatesResolvers:
  caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
  myresolver:
    acme:
      email: "XXXXXX"
      storage: "/letsencrypt/acme.json"
      dnsChallenge:
        provider: ovh
        delayBeforeCheck: 0

🚩Petit bonus, j'utilise ici le serveur staging de let's encrypt, vous pouvez utiliser ce serveur lorsque vous réalisez des tests. Les limitations de ce serveur sont moins importantes en cas d'erreurs, par exemple sur le nombre de tentatives par heure. Pensez à retirer cette ligne une fois votre configuration validée. 🚩

L'option delayBeforeCheck indique à Traefik le délai d'attente avant de vérifier l'entrée DNS TXT.

Attention à l'utilisation de la valeur 0 pour le paramètre  delayBeforeCheck , en fonction de la vitesse de propagation du DNS cela peut provoquer des erreurs dans le challenge. Vous pouvez utiliser la valeur 10 ( c'est en secondes, je n'ai pas eu de soucis avec cette valeur ).

Il existe une alternative à l'utilisation de variable d'environnement pour la déclaration des éléments liés à la configuration de l'API OVH : Les secrets.

Voici un exemple de configuration avec utilisation des secrets de Docker :

secrets:
  # secret name also used to name the file exposed within the container
  ovh_endpoint:
     # path on the host
    file: "./secrets/ovh_endpoint.secret"
  ovh_application_key:
    file: "./secrets/ovh_application_key.secret"
  ovh_application_secret:
    file: "./secrets/ovh_application_secret.secret"
  ovh_consumer_key:
    file: "./secrets/ovh_consumer_key.secret"

services:
  traefik:
    # expose the predefined secret to the container by name
    secrets:
        - "ovh_endpoint"
        - "ovh_application_key"
        - "ovh_application_secret"
        - "ovh_consumer_key"
        
    environment:
    # expose the path to file provided by docker containing the value we want for OVH_ENDPOINT.
        - "OVH_ENDPOINT_FILE=/run/secrets/ovh_endpoint"
        - "OVH_APPLICATION_KEY_FILE=/run/secrets/ovh_application_key"
        - "OVH_APPLICATION_SECRET_FILE=/run/secrets/ovh_application_secret"
        - "OVH_CONSUMER_KEY_FILE=/run/secrets/ovh_consumer_key"

Cette option offre une couche de sécurité supplémentaire, elle n'exposera pas vos identifiants dans le fichier docker-compose.yml.

Peu importe l'option choisie, une fois terminée vous pouvez redémarrer votre instance de Traefik et générer votre certificat !


Nous avons donc pu voir dans ce tutoriel, comment créer une application au sein de l'API OVH, lui donner les droits nécessaires afin d'effectuer les opérations et se servir de l'API afin que Traefik puisse générer des certificats let's encrypt.

Même si le challenge DNS n'est clairement pas la méthode la plus simple à mettre en oeuvre, elle offre quelques avantages. Comme par exemple la possibilité de fournir un certificat SSL à une application interne. Je ne me suis pas attardé sur la création de certificat wildcard, car même s'il s'agit d'un des avantages de cette solution, je déconseille l'utilisation de certificat générique.

Vous arrive t-il de vouloir fournir un certificat SSL valide à un environnement interne ? Pour quelle(s) raison(s) ?😊

En tout cas  n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter, c'est toujours un plaisir d'avoir des retours et des échanges !