Aller au contenu
Infrastructure as Code medium

Projet final : une VM qui naît déjà conforme avec Salt

10 min de lecture

Logo Salt Project

Vous savez décrire un état, le servir depuis Git et le durcir. Il manque la dernière marche : supprimer l'étape manuelle. Ce projet final relie Terraform, cloud-init et Salt pour qu'une VM tout juste provisionnée s'enrôle seule, applique son highstate au premier démarrage, et naisse déjà conforme. Sur le lab, il s'écoule 51 secondes entre terraform apply et un serveur web opérationnel, sans qu'aucune commande ne soit tapée. Public visé : avancés ayant suivi le parcours.

  • Enrôler automatiquement un minion avec autosign.
  • Installer et configurer le minion depuis cloud-init.
  • Déclencher un highstate au premier démarrage.
  • Obtenir une VM conforme sans aucune intervention.

Jusqu'ici, chaque nouvelle machine demandait des gestes : installer le minion, le pointer vers le master, accepter sa clé, puis lancer un highstate. Quatre occasions d'oublier quelque chose, et autant de machines qui dérivent dès leur naissance.

L'objectif est d'éliminer ces gestes en chaînant trois briques :

BriqueRôle dans la chaîne
TerraformCrée la VM et lui injecte sa configuration cloud-init
cloud-initInstalle le minion, pose son identité, son rôle et son master
SaltAccepte la clé (autosign) et applique le highstate au démarrage

Chaque brique fait une chose, et le résultat est une machine qui se configure elle-même.

Le premier verrou, c'est l'acceptation de clé : par défaut, un nouveau minion attend qu'un humain valide sa clé sur le master. L'option autosign_file lève ce verrou, mais sans ouvrir la porte à n'importe qui : seuls les identifiants listés sont acceptés automatiquement.

/etc/salt/master.d/autosign.conf
autosign_file: /etc/salt/autosign.conf

Le fichier ne contient que les identifiants attendus, et Salt exige des permissions strictes, faute de quoi il ignore silencieusement le fichier :

Fenêtre de terminal
echo 'web2' | sudo tee /etc/salt/autosign.conf
sudo chown salt:salt /etc/salt/autosign.conf
sudo chmod 0600 /etc/salt/autosign.conf

cloud-init s'exécute au premier démarrage de la VM. C'est là qu'on installe le minion et qu'on lui donne son identité (minion_id), son rôle (un grain) et son master. La ligne décisive est startup_states: highstate : elle demande au minion d'appliquer tout ce que le top file lui assigne dès qu'il démarre.

#cloud-config
packages:
- gnupg
- curl
- ca-certificates
write_files:
- path: /etc/salt/minion_id
content: web2
- path: /etc/salt/grains
content: |
role: web
- path: /etc/salt/minion.d/capstone.conf
content: |
master: 192.168.10.40
startup_states: highstate
runcmd:
- install -d -m 0755 /etc/apt/keyrings
- curl -fsSL https://packages.broadcom.com/artifactory/api/security/keypair/SaltProjectKey/public | gpg --batch --yes --dearmor -o /etc/apt/keyrings/salt-archive-keyring.pgp
- curl -fsSL https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources -o /etc/apt/sources.list.d/salt.sources
- apt-get update -qq
- apt-get install -y salt-minion
- systemctl enable --now salt-minion

Notez que l'installation passe par le dépôt signé officiel, pas par un script téléchargé et exécuté à l'aveugle. La machine naît avec une chaîne de confiance vérifiable.

Côté Terraform, cette configuration est injectée comme user-data de la VM. Le provisionnement se résume alors à décrire la machine et à lui attacher ce fichier :

resource "proxmox_virtual_environment_vm" "capstone" {
name = "saltminion4"
# ... cpu, mémoire, disque, réseau ...
initialization {
ip_config {
ipv4 {
address = "192.168.10.44/24"
gateway = var.gateway
}
}
user_data_file_id = proxmox_virtual_environment_file.capstone_cloudinit.id
}
}

Un détail décide du succès ou de l'échec, et il coûte cher à découvrir. Si vous servez vos states par GitFS (module précédent), c'est le top file du dépôt Git qui fait autorité : il supplante celui posé dans /srv/salt. Une machine qui démarre appliquera donc ce que Git lui assigne, pas ce qui traîne sur le disque du master.

# top.sls, dans le dépôt Git
base:
'*':
- motd
'role:web':
- match: grain
- nginx

Tout est en place. On lance le provisionnement, puis on ne touche plus à rien :

Fenêtre de terminal
terraform apply

En moins d'une minute, la machine s'enrôle et se configure. Le master l'a acceptée automatiquement :

Fenêtre de terminal
sudo salt-key -L
Accepted Keys:
db1
proxy1
web1
web2

Le grain posé par cloud-init est bien là, et c'est lui qui a déclenché l'application du bon state :

Fenêtre de terminal
sudo salt web2 grains.get role
web2:
web

Et la machine est conforme : le paquet installé, la configuration gérée par Salt en place, et le site qui répond, sans qu'aucune commande n'ait été tapée sur cette VM.

Fenêtre de terminal
sudo salt web2 cmd.run 'systemctl is-active nginx; tail -1 /etc/nginx/conf.d/tuning.conf; curl -s http://localhost/ | head -1'
web2:
active
client_max_body_size 32m;
<!DOCTYPE html>

Le chronomètre s'arrête à 51 secondes entre le terraform apply et un serveur web opérationnel et conforme. Le highstate rejoué ensuite ne change rien, preuve que l'état est stable dès la naissance :

Fenêtre de terminal
sudo salt web2 state.apply
Succeeded: 4
Failed: 0

La machine n'est plus configurée après coup, elle naît conforme. La différence n'est pas cosmétique.

La dérive disparaît à la racine : il n'existe aucune fenêtre entre la création de la VM et son alignement, donc aucun serveur ne vit jamais dans un état non décrit. Le remplacement devient trivial : une machine douteuse se détruit et se recrée, au lieu de se réparer à la main. C'est le passage d'une infrastructure que l'on soigne à une infrastructure que l'on remplace, et Salt en est le garant à chaque démarrage.

SymptômeCause probableSolution
La clé du minion reste en attenteautosign.conf ignoréVérifier chown salt:salt et chmod 0600 sur le fichier
Le minion s'enrôle mais rien ne s'appliqueLe top file Git n'assigne rien à ce minionsalt <minion> state.show_top et corriger le top file dans Git
Le state attendu n'est pas appliquéLe top file de GitFS supplante celui de /srv/saltDéclarer le state dans le top file du dépôt Git
Le grain de rôle est absentcloud-init n'a pas écrit /etc/salt/grainsVérifier write_files et relancer saltutil.sync_grains
La VM démarre sans minionLe dépôt Salt n'était pas joignableVérifier DNS et sortie réseau dans runcmd
  1. autosign_file enrôle les minions listés sans intervention ; le fichier doit appartenir à salt et être en 0600.
  2. Un autosign_file contenant * accepterait n'importe quelle machine : listez des identifiants précis.
  3. cloud-init installe le minion et pose son identité, son rôle et son master au premier démarrage.
  4. startup_states: highstate fait converger la machine dès son démarrage, et la réaligne à chaque reboot.
  5. Avec GitFS, le top file du dépôt Git supplante celui de /srv/salt : c'est lui qui décide ce que reçoit la nouvelle machine.
  6. Résultat : une VM née conforme en moins d'une minute, sans dérive possible entre sa création et son alignement.
  • Formation Terraform : approfondir le provisionnement qui déclenche cette chaîne.
  • Cloud-init : tout ce que l'on peut préparer au premier démarrage d'une machine.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn