claria.tools.dns-client 3.0.0-build.20260819.1

Build Information

Provenance Azure DevOps Pipeline
Owner kntera (Yan Boivin)
Date de compilation 2026-08-20 03:32:52 UTC
Version 3.0.0.20260819.1
SHA256 c459994b8934484f497073c13eb1e289a1d66b28

dns-client

Outil en ligne de commande qui édite les entrées DNS d'une zone hébergée chez un fournisseur (Namecheap en premier) sous le contrôle d'une politique d'autorisation (allow / deny). Conçu pour permettre à des agents d'opérer le DNS en gardant l'humain aux commandes sur toute opération non couverte par la politique — même modèle de sécurité que ssh-client, restapi-client et sql-client.


Contexte

Plutôt que d'exposer l'API du fournisseur (ou curl brut) à un agent, dns-client s'intercale comme garde-fou : chaque opération (combinaison zone + opération + entrée TYPE:nom) est évaluée contre une liste allow et une liste deny avant d'être exécutée. Une opération refusée n'ouvre même pas de connexion ; une opération inconnue signale à l'appelant qu'une décision humaine est requise. Chaque opération (y compris les refus) est journalisée dans une session.

L'API Namecheap ne connaît que le remplacement complet de la zone (setHosts) : l'outil relit systématiquement la zone (getHosts) immédiatement avant chaque écriture et ne modifie que l'entrée visée — les autres entrées sont repoussées telles quelles.

Spécifications complètes : doc/spec/** (A01 portée, E01 CLI, E02 comptes et zones, E03 politique, E04 édition, E05 sessions, E06 domaines, E07 espaces de configuration).


Utilisation

dns-client record list   --zone <nom> [--type <t>] [--name <n>] [--json] [--once]
dns-client record add    --zone <nom> --type <t> --name <n> --value <v>
                         [--ttl <s>] [--mx-pref <n>] [--json] [--once]
dns-client record update --zone <nom> --type <t> --name <n> [--old-value <v>]
                         [--value <v>] [--ttl <s>] [--mx-pref <n>] [--json] [--once]
dns-client record delete --zone <nom> --type <t> --name <n> [--value <v>] [--json] [--once]
dns-client policy check  <zone> <opération> <entrée>
dns-client policy allow  <zone> <opérations> <motif-entrée>
dns-client policy deny   <zone> <opérations> <motif-entrée>
dns-client policy remove <zone> <opérations> <motif-entrée>
dns-client policy list [--json]
dns-client account add <nom> --provider namecheap --client-ip <ipv4>
                       --api-user <utilisateur> --api-key-stdin
                       [--user-name <compte>] [--sandbox] [--endpoint <url>]
dns-client account remove <nom>
dns-client account list [--json]
dns-client account domains <nom> [--json]
dns-client zone add <nom> --account <compte> --domain <domaine>
dns-client zone remove <nom>
dns-client zone list [--json]
dns-client zone test <nom>
dns-client session start [<id>]
dns-client session end [<id>]
dns-client session current [--json]
dns-client session list [--json]
dns-client --version | --readme | --help

Option globale : --config-dir <chemin> fixe la racine de configuration (sinon DNSCLIENT_HOME, sinon ./.conf/dns-client s'il existe, sinon ~/.conf/dns-client s'il existe, sinon ./.conf/dns-client créé à la première écriture — voir « Espaces de configuration »). --session <id> cible une session précise (créée si absente). --no-sessions désactive l'inscription locale des sessions (équivaut à DNSCLIENT_NO_SESSIONS=1).


Espaces de configuration (.conf/)

La configuration est lue par agrégation de sous-répertoires, comme les conf.d/ de nginx. La racine .conf/dns-client/ contient un sous-répertoire par espace de configuration, chacun autonome (ses comptes et ses zones avec leurs defaults dans config.json, ses secrets dans credentials.json, sa politique dans policies.json) ; les journaux — sessions et debug — vont dans .log/dns-client/ du répertoire de travail :

.conf/dns-client/
├── default/   config.json, credentials.json, policies.json   ← espace par défaut
└── appA/      config.json, credentials.json, policies.json   ← autre espace

.log/dns-client/
├── sessions/  index.json, <date>-<id>.jsonl
└── dns-debug-AAAA-MM-JJ.log
  • Racine : --config-dir, sinon DNSCLIENT_HOME, sinon le ./.conf/dns-client local s'il existe, sinon celui du profil (~/.conf/dns-client) s'il existe, sinon le local (créé à la première écriture). Une seule racine sert aux lectures et aux écritures d'une invocation ; zone list et account list la rappellent sur stderr.
  • Références : une zone ou un compte se désigne par <espace>/<nom> (exacte) ou <nom> seul → l'unique espace qui le déclare, sinon l'espace default, sinon erreur 250 (« zone ambiguë » / « compte ambigu » : préciser appA/www ou appB/www). Un nom ne contient pas de /.
  • Déclaration : account add appA/acme … écrit dans appA/ (créé au besoin) ; account add acme … remplace le compte là où il existe, sinon va dans default/. Une zone est déclarée dans l'espace de son compte (zone add www --account appA/acme → appA/www) ; un nom de zone qualifié d'un autre espace est refusé.
  • Politique par espace : les règles d'un policies.json ne couvrent que les zones de leur espace ; policy allow appA/www add "A:www" vise appA/, policy allow www … résout l'espace comme un nom de zone (* → tous les espaces qui déclarent une zone : un seul, sinon default, sinon 250). policy list groupe par espace. Les suggestions émises pour une opération inconnue portent déjà la référence qualifiée.
  • defaults par espace : timeoutSeconds s'applique aux zones de l'espace ; sessionInactivityMinutes (global) vient de default, sinon de l'unique espace, sinon 10 min.
  • L'ancien ./.dns-client/ n'est plus lu : un diagnostic invite à déplacer ses fichiers dans ./.conf/dns-client/default/.

Comptes et zones

Comptes et zones sont déclarés dans un espace de configuration (référence <nom> ou <espace>/<nom>, voir « Espaces de configuration »). Un compte est un compte fournisseur (Namecheap) : ip cliente whitelistée, environnement, et — à part dans credentials.json (durci), jamais dans config.json — ses secrets, fournis sur l'entrée standard. Une zone est un domaine opéré à travers un compte déclaré : elle ne porte aucun identifiant, elle référence son compte. Plusieurs zones partagent naturellement un même compte.

# Compte de production (l'ip doit être whitelistée dans le panneau API Namecheap)
printf '%s' 'la-clé-api' | dns-client account add perso --provider namecheap \
  --client-ip 203.0.113.10 --api-user yan --api-key-stdin

# Compte du sandbox Namecheap
printf '%s' 'la-clé-sandbox' | dns-client account add labo --provider namecheap \
  --client-ip 203.0.113.10 --api-user yan --api-key-stdin --sandbox

# Compte dans un espace de configuration dédié (.conf/dns-client/appA/) — référence appA/acme
printf '%s' 'la-clé-api' | dns-client account add appA/acme --provider namecheap \
  --client-ip 203.0.113.10 --api-user yan --api-key-stdin

dns-client account domains perso     # domaines accessibles du compte (getList paginé)
dns-client account list

# Zones opérées à travers ces comptes
dns-client zone add kntera --account perso --domain kntera.com
dns-client zone add labo   --account labo  --domain labo-kntera.dev

dns-client zone test kntera    # getHosts réel : rapporte le nombre d'entrées et la durée
dns-client zone list

account domains est une lecture de découverte (hors politique de zone, journalisée) : elle liste les domaines auxquels le compte a accès pour amorcer les zone add. La suppression d'un compte est refusée tant que des zones le référencent.

Prérequis côté Namecheap : activer l'accès API du compte (Profile → Tools → API Access), whitelister l'ip publique de la machine qui exécute l'outil, et fournir cette ip via --client-ip.


Politique d'autorisation (allow / deny)

Une règle est la combinaison de trois éléments :

  1. zone — nom de la zone déclarée (* accepté), précédé au besoin de son espace (appA/www) pour désigner la politique de cet espace ;
  2. opérations — add, liste list,add, ou * (list, add, update, delete) ;
  3. motif d'entrée — glob simple (* seul métacaractère) sur la chaîne normalisée TYPE:nom (ex. A:www, TXT:_acme-challenge*, *) ; l'opération list s'évalue contre *.
dns-client policy check kntera add "A:www"           # décision sans exécuter
dns-client policy allow kntera list "*"              # lecture libre de la zone
dns-client policy allow kntera add,update "TXT:_acme-challenge*"   # validations ACME
dns-client policy deny  "*"    delete "MX:*"         # jamais supprimer le courriel (espace default, ou l'unique espace)
dns-client policy list
  • La liste deny est prioritaire ; le défaut est fermé : une opération non couverte n'est jamais exécutée silencieusement (code 253, décision humaine requise).
  • Masquage automatique : la clé d'api ne transite jamais dans une URL, et toute occurrence littérale dans une sortie ou un journal est remplacée par [REDACTED].
code Signification
0 Succès.
1 Erreur retournée par le fournisseur (Status=ERROR, statut HTTP non 2xx).
2 Cible invalide dans l'état de la zone : introuvable, ambiguë (--old-value / --value requis), ou déjà existante.
250 Erreur de configuration (zone inconnue ou ambiguë entre plusieurs espaces, identifiants absents).
251 Délai d'un appel dépassé (défaut 30 s, --timeout 0 = illimité). Après un délai sur l'écriture, relancer record list — état incertain.
252 Erreur d'usage.
253 Opération inconnue — autorisation utilisateur requise (rien envoyé).
254 Refusée par une règle deny (rien envoyé).
255 Erreur de connexion HTTP (réseau, DNS, TLS).

L'ajout d'une règle allow ou deny est une décision explicite de l'utilisateur : présenter l'opération inconnue, recueillir la décision, puis seulement policy allow / policy deny (ou record … --once pour une autorisation ponctuelle).

Face à un code 253, les quatre décisions possibles de l'utilisateur :

Décision Action de l'agent
Autoriser toujours policy allow <zone> <opération> "<entrée>" puis relancer record.
Autoriser une seule fois Relancer record avec --once ; aucune persistance.
Refuser toujours policy deny <zone> <opération> "<entrée>" ; ne pas exécuter.
Refuser cette fois-ci Ne rien persister, ne pas exécuter.

Ne jamais généraliser un motif au-delà de ce que l'utilisateur a approuvé ; ne jamais proposer de motif large pour une opération mutative (add, update, delete) — en particulier, jamais delete *.


Édition des entrées

dns-client record list   --zone kntera
dns-client record list   --zone kntera --type TXT
dns-client record add    --zone kntera --type A --name www --value 203.0.113.20 --ttl 300
dns-client record add    --zone kntera --type TXT --name _acme-challenge --value "jeton-de-validation"
dns-client record add    --zone kntera --type MX --name @ --value mail.kntera.com --mx-pref 10
dns-client record update --zone kntera --type A --name www --value 203.0.113.21
dns-client record delete --zone kntera --type TXT --name _acme-challenge
  • Une entrée est adressée par --type + --name ; quand plusieurs entrées partagent ce couple (plusieurs A, MX, TXT), --old-value (update) ou --value (delete) désigne laquelle (code 2 sinon, avec les candidates).
  • update ne change ni le type ni le nom (procéder par delete + add).
  • TTL : 60 à 60000 s, défaut 1799. --mx-pref : type MX seulement, défaut 10. L'ajout d'un MX/MXE bascule au besoin le type de courriel de la zone (EmailType), avec diagnostic.
  • En mode texte, les entrées touchées sont écrites sur stdout ; le résumé est un diagnostic stderr (préfixé dns-client:).
  • --json produit un unique objet structuré sur stdout : zone, fournisseur, domaine, opération, entrée ciblée, décision, règle, changed, records, recordCount, error, durationMs, timedOut.

Sessions

Une session regroupe les opérations d'une période de travail et journalise chaque opération (y compris refusée, en conflit ou en erreur) dans .log/dns-client/sessions/<AAAAMMJJhhmmss>-<id>.jsonl (dans le répertoire de travail, commun à tous les espaces) : zone (référence qualifiée), opération, entrée ciblée, décision, entrées touchées, appels au fournisseur (commande, statut, durée), erreur — plus un événement dédié par account domains (compte, nombre de domaines, appels par page). En complément, chaque appel réellement envoyé est tracé dans un journal de debug DNS quotidien, dns-debug-AAAA-MM-JJ.log (dans .log/dns-client/ du répertoire de travail) : paramètres (clé d'api masquée) et corps XML intégral de la réponse. Ce journal n'est pas affecté par --no-sessions.

dns-client session start migration-vps
dns-client session current
dns-client session end migration-vps

La session active est la dernière session non terminée et non expirée (expiration : 10 min d'inactivité par défaut). Sans session active, une opération en crée une automatiquement.


Sécurité

  • Deny prioritaire et défaut fermé : une opération non couverte n'est jamais exécutée silencieusement.
  • Écriture minimale : setHosts remplaçant la zone entière, l'outil relit toujours la zone immédiatement avant d'écrire et ne modifie que l'entrée visée ; une lecture douteuse (erreur, délai) interrompt l'opération avant toute écriture.
  • Secrets isolés dans credentials.json (permissions propriétaire seul sous POSIX), fournis sur stdin, envoyés en POST (jamais dans une URL), jamais affichés ni journalisés — toute occurrence littérale est remplacée par [REDACTED].
  • Journalisation intégrale de chaque opération (décision, entrées touchées, appels au fournisseur) dans la session.

Le modèle est coopératif : dns-client structure et trace les opérations DNS d'un agent ; il se combine à l'allowlist du harnais (n'autoriser que dns-client, jamais curl brut vers l'API du fournisseur, ni l'édition directe des fichiers de politique et d'identifiants).

No packages depend on claria.tools.dns-client.

Build 3.0.0.20260819.1 du 2026-08-20 03:32:53 UTC - pipeline skill tools - dns-client run 2121 - commit c459994b8934484f497073c13eb1e289a1d66b28

This package has no dependencies.

Version Downloads Last updated
3.0.0-build.20260819.1 11 08/20/2026