Cet article documente la strategie complete de deploiement de l image BIND9 hardened : creation des jeux de donnees de test, validation, pipeline CI/CD et mise en production.
Vue d ensemble du pipeline
flowchart LR
subgraph dev["Developpement"]
code["Dockerfile<br/>init.go<br/>go.mod"]
end
subgraph build["Build"]
docker["docker build<br/>multi-stage"]
end
subgraph test["Tests"]
local["Test local<br/>docker run + dig"]
parallel["Test parallele<br/>VyOS IP .11"]
end
subgraph ci["CI/CD"]
lint["Hadolint<br/>ShellCheck"]
validate["named-checkconf<br/>named-checkzone"]
sign["cosign sign<br/>OIDC keyless"]
scan["Trivy + Grype"]
end
subgraph prod["Production"]
transfer["skopeo + scp<br/>podman load"]
swap["config.boot<br/>restart container"]
end
code --> docker --> local --> parallel --> transfer --> swap
docker --> lint
lint --> validate --> sign --> scan
Jeux de donnees de test (JDD)
Structure des JDD
Les fichiers de test reproduisent la configuration de production avec des donnees sanitisees :
playbook/etc/bind/
named.conf # Config principale (statique)
named.conf.options # Forwarders, ACL, rate-limit
named.conf.local # Genere : vues, zones, includes
db.jbsky.fr # Zone publique
db.home.arpa # Zone interne (vue local)
<vue>_db.home.arpa # Zone interne par vue
db.
<subnet> # Zones reverses
<vue>_db.<subnet> # Symlinks reverses par vue
zones.*.in-addr.arpa # Snippets zone reverse
zones.home.arpa # Snippet zone forward
zones.jbsky.fr # Snippet zone publique + update-policy
tsig.key # Cle TSIG (generee, jamais committee)
Generation des JDD
Les zones sont generees par le playbook bind.yaml a partir de l inventaire Ansible. Chaque host avec une IP et un netmask genere automatiquement les sous-reseaux, les vues et les zones reverses :
ansible-playbook playbook/bind.yaml -i inventories/production
Cette commande produit ~35 fichiers dans playbook/etc/bind/ en environ 35 secondes. Les fichiers generes sont commites dans le repo comme trace de ce qui est deploye.
JDD de test TSIG
Pour les tests locaux, un tsig.key factice est cree :
key "tsig-key" {
algorithm hmac-sha512;
secret "dGVzdGtleWZvcmxvY2FsdGVzdGluZw==";
};
En CI, la cle est generee dynamiquement (64 octets aleatoires) par le job generate_tsig.
Tests
Test local (docker run)
Apres le build de l image, un test local valide le fonctionnement de base :
flowchart TB
subgraph local["Test local sur ansible.home.arpa"]
build["docker build<br/>bind9-hardened:9.20.24"]
run["docker run<br/>config montee en volume"]
check["Verification"]
end
build --> run
run --> check
check --> dig["dig jbsky.fr A"]
check --> hc["init --healthcheck"]
check --> ver["dig version.bind CH TXT"]
check --> proc["docker top : UID 5300"]
Commandes de validation :
# Lancer le container de test
docker run -d --name bind9-test \
--cap-add NET_BIND_SERVICE \
-v /path/to/bind-config:/etc/bind \
-v /path/to/cache:/var/cache/bind \
-p 5353:53/udp -p 5353:53/tcp \
jbsky/bind9-hardened:9.20.24
# Verifier le DNS
dig @127.0.0.1 -p 5353 jbsky.fr A +short
dig @127.0.0.1 -p 5353 pve.home.arpa A +short
dig @127.0.0.1 -p 5353 version.bind CH TXT +short
# Verifier le healthcheck
docker exec bind9-test /usr/local/bin/init --healthcheck
# Verifier le process (non-root)
docker top bind9-test
# Doit afficher UID 5300, PID 1 = tini, PID 2 = named
Test parallele sur VyOS
Avant de basculer la production, un container de test tourne en parallele sur une IP differente :
sequenceDiagram
participant Dev as Poste dev
participant VyOS as VyOS
participant Prod as bind9 prod .10
participant Test as bind9-test .11
Dev->>VyOS: scp image.tar
Dev->>VyOS: podman load
Dev->>VyOS: podman run --ip .11
Note over Prod: Toujours actif
Note over Test: Container parallele
Dev->>VyOS: dig @.11 jbsky.fr
VyOS->>Test: DNS query
Test-->>VyOS: Reponse OK
Note over Dev: Validation OK
Dev->>VyOS: podman rm bind9-test
Dev->>VyOS: modifier config.boot
VyOS->>Prod: restart container
Note over Prod: Nouvelle image active
Le test parallele ne recoit pas de trafic reel (le firewall zone bind9 n autorise que l IP .10). Seules les requetes depuis VyOS lui-meme atteignent le container test.
Pipeline CI/CD GitLab
Stages
flowchart LR
subgraph keygen["Stage keygen"]
tsig["generate_tsig<br/>Cle TSIG aleatoire"]
end
subgraph validate["Stage validate"]
check["validate_bind9<br/>checkconf + checkzone<br/>demarrage named<br/>dig de controle"]
end
subgraph deploy["Stage deploy"]
bind["deploy_bind9<br/>rsync zones VyOS<br/>MANUEL"]
end
subgraph inject["Stage inject"]
cert["deploy_certbot<br/>Injecte TSIG sur<br/>BIND9 + certbot"]
end
tsig --> check --> bind --> cert
style bind fill:#f90,color:#fff
Le stage deploy est manuel : il necessite une validation humaine avant de pousser les zones en production.
Job validate_bind9 en detail
Le job de validation execute une serie de tests dans un container Alpine avec bind-tools :
Validation syntaxique : named-checkconf
Validation zone jbsky : named-checkzone jbsky.fr db.jbsky.fr
Validation zone home : named-checkzone home.arpa db.home.arpa
Validation zones reverse : boucle sur tous les db.192.168.* et db.172.17.*
Test fonctionnel : demarrage named + dig pve.home.arpa + dig jbsky.fr + dig MX
Si un test echoue, le pipeline s arrete et le deploiement est bloque.
Job deploy_bind9
Le deploiement utilise rsync pour synchroniser les fichiers de zone :
rsync -az --delete --chmod=D0755,F0644 \
--exclude=tsig.key \
playbook/etc/bind/ \
vyos:/config/containers/bind9/
Points critiques :
--exclude=tsig.key: la cle est deployee separement par le jobdeploy_certbot--delete: supprime les fichiers orphelins (important quand un subnet disparait)- Les fichiers
.jnlne sont PAS exclus (sinon desync avec les zones dynamiques)
Apres le rsync, le playbook :
- Fixe les permissions (UID 5300 sur db.jbsky.fr, chmod 644 sur tsig.key)
- Redemarre le container via
restart container bind9 - Attend le port 53
- Execute des dig de controle
Deploiement d une nouvelle version d image
Workflow complet
flowchart TB
A["Modifier Dockerfile ou init.go"] --> B["Build local"]
B --> C{"Tests locaux OK ?"}
C -->|"Non"| A
C -->|"Oui"| D["docker save + scp vers VyOS"]
D --> E["podman load sur VyOS"]
E --> F["Test parallele IP .11"]
F --> G{"dig + healthcheck OK ?"}
G -->|"Non"| A
G -->|"Oui"| H["Modifier config.boot<br/>image + capability"]
H --> I["commit + save"]
I --> J["Verification production"]
J --> K["Backup VyOS"]
K --> L["Push GitHub + GitLab"]
style C fill:#f90,color:#fff
style G fill:#f90,color:#fff
Transfer de l image vers VyOS
VyOS n a pas d acces Internet sortant. Le transfer se fait en 3 etapes :
# Sur le poste de build
docker save jbsky/bind9-hardened:9.20.24 -o /tmp/bind9.tar
scp /tmp/bind9.tar user@vyos:/tmp/
# Sur VyOS
podman load -i /tmp/bind9.tar
rm /tmp/bind9.tar
Bascule production
La modification de config.boot se fait via le wrapper VyOS natif :
set container name bind9 image docker.io/jbsky/bind9-hardened:9.20.24
set container name bind9 capability net-bind-service
delete container name bind9 environment BIND9_USER
commit
save
Le commit arrete l ancien container et demarre le nouveau avec la nouvelle image. Coupure DNS de 5 a 10 secondes.
Verification post-deploiement
Checklist de validation apres chaque deploiement :
- Resolution forward :
dig jbsky.fr Aretourne l IP publique - Resolution interne :
dig pve.home.arpa Aretourne l IP Proxmox - Resolution reverse : `dig -x ` retourne le FQDN
- Version masquee :
dig version.bind CH TXTretourne "not disclosed" - Healthcheck :
podman exec bind9 /usr/local/bin/init --healthcheckretourne 0 - Process : UID 5300, PID 1 = tini, PID 2 = named
- Logs :
podman logs bind9ne montre pas d erreur
Liens
- Code source : bind9-hardened
- Image Docker : Docker Hub
Laisser un commentaire