Coder un mot de passe en dur dans un state est une faute. Les pillars sont la réponse de Salt : des données confidentielles, servies par le master, ciblées par minion, que les states consomment sans les contenir. Ce module apprend à externaliser toute la configuration de plusieurs applications. Public visé : intermédiaires ayant écrit des states avec Jinja.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Structurer un arbre de pillars.
- Cibler des données par minion avec le pillar top file.
- Séparer données publiques et données sensibles.
- Externaliser la configuration de plusieurs applications.
Prérequis
Section intitulée « Prérequis »- Savoir écrire des states et utiliser Jinja.
Grains ou pillars : ne pas confondre
Section intitulée « Grains ou pillars : ne pas confondre »La distinction est fondamentale. Les grains sont des faits collectés côté minion (système, CPU, rôle) : le minion les connaît, ils ne sont pas secrets. Les pillars sont des données définies côté master et poussées vers les minions autorisés : c'est l'endroit des secrets et de la configuration par environnement. Un minion ne voit que les pillars qui lui sont assignés.
Structurer et cibler les pillars
Section intitulée « Structurer et cibler les pillars »Les pillars vivent dans un arbre séparé des states (/srv/pillar par défaut),
avec leur propre top file qui décide quel minion reçoit quelles données,
avec le même ciblage que partout dans Salt.
base: 'role:web': - match: grain - web 'db1': - dbLe top file des pillars ne sert qu'à deux choses : inclure des fichiers
pillar et cibler les minions qui les reçoivent. On n'y déclare jamais de
variable : les données vivent dans les fichiers inclus (ici web.sls et
db.sls), pas dans le top.sls.
Un fichier pillar porte le nom de son state : un pillar apache.sls
alimente les states apache, un pillar web.sls les states du rôle web.
Cette correspondance de nommage rend l'arbre lisible.
paquets_web: - nginx - certbotapp: admin_email: ops@exemple.frVérifier ce que reçoit un minion
Section intitulée « Vérifier ce que reçoit un minion »pillar.items liste les pillars d'un minion. Notez que Salt masque les valeurs
en sortie de terminal, un garde-fou pour ne pas exposer un secret dans un
historique de commandes ou un log :
salt web1 pillar.itemsweb1: ---------- app: ---------- admin_email: ********** paquets_web: - ********** - **********L'isolation est la propriété clé : un minion ne voit que ses pillars. Le
secret de base de données, ciblé par identifiant db1, est servi à db1...
salt db1 pillar.get db:passworddb1: **********...mais reste invisible pour web1, qui n'y a pas droit :
salt web1 pillar.get db:passwordweb1:Consommer un pillar dans un state
Section intitulée « Consommer un pillar dans un state »Le masquage protège le terminal, mais la valeur réelle circule bien jusqu'au
minion. Dans un state ou un template, on lit un pillar avec la syntaxe mapping
salt['pillar.get'](...), entre crochets, jamais la forme pointée
salt.pillar.get(...). Le second argument fournit une valeur de repli qui
évite un rendu en échec quand la clé est absente.
# écrit la valeur du pillar dans un fichier de configuration/etc/ops-contact.conf: file.managed: - mode: "0644" - contents: | admin_email={{ salt['pillar.get']('app:admin_email', 'root@localhost') }}À l'application, le fichier déployé contient la vraie valeur, preuve que la donnée a traversé le master jusqu'au minion :
salt web1 state.apply webconfsalt web1 cmd.run 'cat /etc/ops-contact.conf'web1: admin_email=ops@exemple.frUn second passage ne change rien, file.managed étant idempotent :
Comment: File /etc/ops-contact.conf is in the correct stateDonnées sensibles
Section intitulée « Données sensibles »Les secrets vivent exclusivement en pillar : jamais dans un grain, jamais dans un state versionné. Un grain est modifiable côté minion, donc non fiable pour une donnée sensible ; un state poussé dans Git expose le secret à quiconque lit le dépôt. Le pillar reste le seul emplacement qui limite la diffusion aux minions autorisés.
Cibler par identifiant ne suffit pourtant pas à protéger la valeur au repos. Un pillar reste stocké en clair sur le master tant que vous ne le chiffrez pas : le ciblage contrôle qui reçoit la donnée, pas comment elle est protégée sur le disque du master ou dans Git.
Environnements
Section intitulée « Environnements »Les pillars se déclinent par environnement (base, dev, prod) pour
servir des valeurs différentes selon le contexte : une base de données de test en
dev, la vraie en prod, avec le même code de states. Chaque environnement a sa
section dans le top file, ce qui évite de dupliquer les states pour changer une
poignée de valeurs.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
| Un minion ne reçoit pas son pillar | Cache non rafraîchi | salt '<minion>' saltutil.refresh_pillar |
pillar.get renvoie vide dans un state | Clé absente ou mauvais chemin | Fournir un repli : pillar.get('x', defaut) |
| Un minion voit un pillar qui ne le concerne pas | Ciblage trop large dans le top file | Restreindre le match, cibler les secrets par identifiant |
À retenir
Section intitulée « À retenir »- Les grains sont des faits du minion ; les pillars sont des données du master ciblées par minion.
- Le pillar top file décide qui reçoit quoi, par inclusion et ciblage.
- Salt masque les valeurs de pillar en sortie CLI : un garde-fou, la donnée circule quand même jusqu'au minion.
pillar.geten syntaxe mapping avec une valeur de repli évite les états indéfinis.- Un pillar clair n'est pas chiffré : les vrais secrets passent par GPG ou Vault.