Dns Devops

Pierre Gambarotto

Created: 2023-03-28 mar. 13:50

Génèse du projet

PLMParty 2022 : il faut refaire la gestion des DNS Mathrice

  • actuel : à la main sur ns1.math.cnrs.fr
  • objectifs :
    • pouvoir régénérer un serveur maître facilement
    • pouvoir déléguer la gestion des zones à des personnes différentes
  • discussions sur les outils : Devops !

L’idée

Une zone DNS = un projet git

Gérer les autorisations sur la zone par les permissions sur le projet

L’intégration continue doit :

  • vérifier la syntaxe des modifications
  • indiquer au serveur DNS qu’il doit prendre en compte les modifications apportées

la toolbox

Gitlab, et en particulier :

À retenir :

  • Functionnality Y not available for Gitlab Community : USE THE API Duh !

Intégration continue

  • déclenche sous certaine condition un pipeline, e.g. nouveau commit sur la branche main
  • un runner, disponible pour le projet,
  • va récupérer la nouvelle version du dépôt
  • va lancer un script
  • qui va faire des choses !
  • éventuellement en utilisant des binaires provenant d’une image docker
  • le tout dans un environnement d’exécution spécifique, e.g. conteneur docker

Limpide non ? git push => ça réagit

RFC : forum dans la partie PLMTeam

Octobre 2022

copie visible ici

Quelques évolutions depuis, mais mineure

Organisation des dépôts

dns                          <- Groupe Gitlab
├── ci                       <- scripts d'intégration continue
├── dns0                     <- mise en place du serveur DNS
└── zones                    <- Groupe Gitlab zones
    ├── lollipop.org         <- projet zone
    └── mazone.math.cnrs.fr  <- projet zone

Exemple de dépôt pour une zone :

lollipop.org/
├── lollipop.org.data  <- le fichier zone
├── metadata.json      <- optionnel, pour des usages avancés
└── README.md          <- instructions pour utilisation

Principe de l’intégration continue

Pour proposer une nouvelle version d’une zone, le gestionnaire de zone doit :

  • créer une branche
  • faire des modifications sur la branche
  • créer une Merge Request vers la branche main du dépôt

Chaque projet zone est configuré pour interdire les push direct sur la branche main.

Les pipelines d’intégration continue

groupe de runers quelconques : MR -> vérifier la zone -> accepter la MR

runner sur le serveur DNS : main mis à jour -> mise à jour du serveur DNS

IC : vérification de la syntaxe de la zone

Pipeline déclenché par la demande de MR

  • utilise named-checkzone fourni avec bind pour vérifier la syntaxe de la zone

IC : acceptation de la MR

MR Result Pipelines : PREMIUM only

Il faut passer par l’API

GITLAB="https://plmlab.math.cnrs.fr/api/v4/"
cat <<EOF > mr.json
{
  "id": "${CI_PROJECT_ID}",
  "merge_request_iid": "${CI_MERGE_REQUEST_IID}",
  "merge_when_pipeline_succeeds": true
}
EOF
curl -v --request PUT --header "PRIVATE-TOKEN: ${apiToken}" \
     --header "Content-Type: application/json" --data @mr.json \
  "${GITLAB}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/merge"

CI Côté technique

J’ai appris pas mal de choses sur ce projet, voici un florilège

Le plus important : installer dès que possible un gitlab-runner local => accélère grandement le cycle de mise au point

Utiliser un .gitlab-ci.yaml d’un autre projet

Tous les projets de zone DNS partagent la même configuration.

Dans la config de chaque projet : Settings > CICD > General Pipelines

Spécialiser les runners avec des tags

Principe : dans le .gitlab-ci.yml, on rajoute des tags à un ou plusieurs jobs.

check-zone-syntax:
  tags: [merge-zone]
  stage: test
  script:
    - /bin/check-zone-syntax
  only:
    - merge_request

Les runners doivent être lancés avec l’option adéquate pour ne prendre que les tags voulus.

Gérer l’authentification à l’API

  • générer un token au niveau du groupe englobant dns
  • dans chaque projet zone, stocker ce token en tant que variable dispo pour l’IC : Settings > CI/CD > Variables > Add Variable apiToken

Installation du serveur DNS

  • projet dns0
  • va utiliser un token pour manipuler l’API, stocké en tant que variables CI/CD du projet. Ce token doit avoir un accès complet à l’API.
  • à partir d’une installation classique de bind, par exemple sur une base debian 11
  • script init-zones.sh : génère /etc/bind/zones en clonant tous les projets du groupe dns/zones

=> un répertoire est créé pour chaque zone

Générer le fichier de configuration de bind

script update-conf.sh génère /etc/bind/mathrice-zones

Ce fichier est à inclure dans la configuration du serveur, par exemple dans named.conf.local :

# mathrice-zones is generated from all repositories
# in plmlab:plmteam/services/dns/zones
include "/etc/bind/mathrice-zones";

Exemple

zone gricad.cloud.math.cnrs.fr {
      type master;
      file "/etc/bind/zones/gricad.cloud.math.cnrs.fr/gricad.cloud.math.cnrs.fr.data";
      allow-query { any; };
};
zone ijclab.cloud.math.cnrs.fr {
      type master;
      file "/etc/bind/zones/virtualdata.cloud.math.cnrs.fr/virtualdata.cloud.math.cnrs.fr.data";
      allow-query { any; };
};
zone virtualdata.cloud.math.cnrs.fr {
      type master;
      file "/etc/bind/zones/virtualdata.cloud.math.cnrs.fr/virtualdata.cloud.math.cnrs.fr.data";
      allow-query { any; };
};

IC : gitlab-runner local

Chaque projet de zone va déclencer le runner local :

  • tags update-master
  • uniquement les nouvelles versions sur la branche main

Le runner doit réaliser les actions suivantes :

  • mémoriser le commit de départ
  • git stash pour les modifications locales sur le serial
  • mise à jour du clone local de la zone par git pull
  • récupérer la valeur courante du SN, incrémenter, mettre à jour le fichier de zone
  • rechargement de la zone par rdnc reload <zone name> en cas d’échec, retour à la version du commit de départ, et récupération du git stash
  • Gestion du serial

    Fichier de zone minimal

    $TTL 86400
    @ IN SOA ns1.example.com. hostmaster.example.com. (
      2022030901 ; serial    <------ valeur à mettre à jour !!!
      3600       ; refresh
      1800       ; retry
      604800     ; expire
      86400      ; minimum TTL
    )
    @ IN NS ns1.example.com.
    ns1 IN A 192.0.2.1
    

    Problème

    valeur maximale du serial : 2 147 483 647

    Pour utiliser un classique codage YYYYMMDDHHSS : on ne peut aller que jusqu’en 2038 :-(

    Solution : utiliser une incrémentation classique, gérée par le serveur

    Gestion par le serveur

    Toujours par API, le runner du serveur va stocker dans chaque projet une variable contenant le SN courant

    • initialisation par le SN contenu dans le fichier zone
    • incrémentation par 1 ensuite

    Cela permet de ne pas être limité sur le nombre d’incrémentations chaque jour.

    Lecture et modification d’un fichier zone

    plmlab:gamba/zoneparser

    script en haskell :

    • analyse syntaxique d’une zone
    • extraction du SN
    • modification du SN

    => la syntaxe très lâche d’un fichier de zone a été pénible à gérer …

    Serveur maître, goodies

    Rajout d’un fichier optionnel metadata.json dans les dépôt de zones => gestion de cas avancées

    • un fichier pour gérer 2 zones identiques

      metadata.json :

      { "zones": [ "ijclab.cloud.math.cnrs.fr",
                   "virtualdata.cloud.math.cnrs.fr" ]
      }
      
    • gestion de zones dynamiques metadata.json :

      { "dynamic": true }
      

    Conclusion et perspective

    Avancée:

    • IC check de zone : ok, en cours de test
    • IC serveur : en cours