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, sinonDNSCLIENT_HOME, sinon le./.conf/dns-clientlocal 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 listetaccount listla 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'espacedefault, sinon erreur 250 (« zone ambiguë » / « compte ambigu » : préciserappA/wwwouappB/www). Un nom ne contient pas de/. - Déclaration :
account add appA/acme …écrit dansappA/(créé au besoin) ;account add acme …remplace le compte là où il existe, sinon va dansdefault/. 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.jsonne couvrent que les zones de leur espace ;policy allow appA/www add "A:www"viseappA/,policy allow www …résout l'espace comme un nom de zone (*→ tous les espaces qui déclarent une zone : un seul, sinondefault, sinon 250).policy listgroupe par espace. Les suggestions émises pour une opération inconnue portent déjà la référence qualifiée. defaultspar espace :timeoutSecondss'applique aux zones de l'espace ;sessionInactivityMinutes(global) vient dedefault, 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 :
- 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 ; - opérations —
add, listelist,add, ou*(list,add,update,delete) ; - motif d'entrée — glob simple (
*seul métacaractère) sur la chaîne normaliséeTYPE:nom(ex.A:www,TXT:_acme-challenge*,*) ; l'opérationlists'é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
denyest 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
allowoudenyest une décision explicite de l'utilisateur : présenter l'opération inconnue, recueillir la décision, puis seulementpolicy allow/policy deny(ourecord … --oncepour 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 (plusieursA,MX,TXT),--old-value(update) ou--value(delete) désigne laquelle (code 2 sinon, avec les candidates). updatene change ni le type ni le nom (procéder pardelete+add).- TTL : 60 à 60000 s, défaut 1799.
--mx-pref: typeMXseulement, défaut 10. L'ajout d'unMX/MXEbascule 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:). --jsonproduit 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 :
setHostsremplaç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.
| Version | Downloads | Last updated |
|---|---|---|
| 3.0.0-build.20260819.1 | 11 | 08/20/2026 |