Puppet est un outil permettant la centralisation et le déploiement de configuration sur un parc de machines plus ou moins hétérogène, du moment qu'un client puppet a été développé pour le système d'exploitation utilisé.
Le besoin se résume ainsi :
Gérer de manière efficace et centralisée la configuration de plusieurs machines tout en ayant la souplesse de s'adapter aux spécificités de chacune d'entre elles.
Quand il faut gérer un nombre important de serveurs, il est intéressant (voire indispensable) de disposer d'un outil permettant de déployer et de mettre à jour facilement leur configuration. Bien entendu le but ici n'est pas de copier sur X machines une configuration identique, mais bien d'adapter celle-ci au cas par cas. Cela se résume en partie par l'utilisation de modèles de fichiers de configuration, utilisant des variables qui seront adaptées sur chaque machine cible. Certains administrateurs développent leurs propres scripts de configuration, arrivant à peu près à ce genre de résultat, mais avec les inconvénients que cela peut avoir (temps, ressource, maintenance, robustesse, etc). Heureusement, il existe depuis un certain temps des outils plus aboutis répondant à ce besoin particulier, le plus connu étant cfEngine. Mais bien que cfEngine réponde parfaitement à cette tâche, il est un peu trop complexe, ne serait-ce que dans sa syntaxe, le rendant quelque peu hermétique pour le débutant.
Le réel avantage de Puppet est de proposer des fichiers de configuration clairs et lisibles, facilement compréhensibles.
Puppet permet :
En tant qu'administrateur, vous utiliserez le langage de configuration de Puppet pour déclarer l'état final de vos systèmes.
Ainsi, nous décrivons Puppet comme «déclaratif».
Sur tout nœud que vous contrôlez, une application nommée “Puppet Agent”. L'agent évalue et implémente les manifestes Puppet, ou les fichiers contenant le langage de configuration Puppet qui déclare l'état souhaité du noeud. L'agent évalue l'état de chaque composant décrit dans un manifeste et détermine si un changement est nécessaire ou non. Si le composant doit être modifié, l'agent apporte les modifications demandées et enregistre l'événement.
Si Puppet est configuré pour utiliser un maître centralisé, Puppet envoie les données du nœud au maître et reçoit un catalogue précompilé contenant uniquement la stratégie à appliquer du nœud. Vous pensez peut-être à présent: - « Et si je ne souhaite exécuter que la commande sur un sous-ensemble de nœuds ? » , Puppet propose différentes méthodes pour classifier et catégoriser les nœuds afin de limiter les ressources à appliquer sur des nœuds.
Vous pouvez utiliser des informations de noeud telles que le nom d’hôte, le système d’exploitation, le type de noeud, la version de Puppet et bien d’autres. Mieux encore, il est facile de créer de nouveaux critères personnalisés pour votre environnement.
L'agent Puppet évalue l'état d'un seul nœud. Dans ce modèle, vous pouvez avoir des agents sur des dizaines, des centaines ou des milliers de noeuds pour évaluer leurs catalogues et implémenter les modifications sur leurs noeuds exactement au même moment.
Comme nous l'avons vu précédemment, Puppet fournit une infrastructure bien conçue pour gérer l'état de plusieurs nœuds simultanément.
Voici quelques raisons de l'utiliser:
Puppet Server est configuré pour utiliser 2 Go de RAM par défaut. Si vous souhaitez simplement jouer avec une installation sur une machine virtuelle, cette quantité de mémoire n'est pas nécessaire.
Note:
Pour modifier l'allocation de mémoire, voir l'aide : Allocation de mémoire.
Pour changer la valeur de l'allocation de mémoire, éditez le fichier ci-dessous :
[ user@puppet ~]$ sudo nano /etc/sysconfig/puppetserver
Modifiez la valeur affichée comme ci-dessous.
JAVA_ARGS="-Xms2g -Xmx2g"
par
JAVA_ARGS="-Xms512m -Xmx512m"
Redémarrez le service “puppetserver” après toute modification de ce fichier.
Nous allons maintenant installer et activer le référentiel de la collection de paquets de Puppet sur notre nouveau système.
En commençant par le répertoire de base, suivez les étapes suivantes.
[ user@puppet ~]$ sudo yum localinstall https://yum.puppet.com/puppet5-release-el-7.noarch.rpm
Cette commande installera et activera le référentiel du paquet “puppet” de Puppet.com, qui contient le paquet Puppet 5.
Une fois l'installation terminée, vous pouvez confirmer qu'il est activé avec la commande suivante.
[ user@puppet ~]$ sudo yum repolist
Puppet Server est le logiciel serveur qui s'exécute sur le nœud principal “Puppet Master”. Puppetmaster pousse les configurations vers les nœuds gérés (puppet-agent).
Installez le serveur Puppet en utilisant la commande ci-dessous.
[ user@puppet ~]$ sudo yum install -y puppetserver
Puppet Master ne nécessite aucune configuration. Nous pouvons simplement démarrer le service “puppetserver”. Il utilisera les paramètres par défaut.
[ user@puppet ~]$ sudo systemctl start puppetserver [ user@puppet ~]$ sudo systemctl enable puppetserver
Note:
Confiuration avancée : https://puppet.com/docs/puppet/5.5/config_file_main.html
Le Puppet Master écoute sur le port 8140, configurez donc le pare-feu de manière à ce que les nœuds gérés puissent se connecter au maître.
[ user@puppet ~]$ sudo firewall-cmd --permanent --add-port=8140/tcp success [ user@puppet ~]$ sudo firewall-cmd --reload success
Nous allons maintenant installer et activer le référentiel de la collection de paquets de Puppet sur notre nouveau système.
En commençant par le répertoire de base, suivez les étapes suivantes.
[ user@agent ~]$ sudo yum localinstall https://yum.puppet.com/puppet5-release-el-7.noarch.rpm
Cette commande installera et activera le référentiel du paquet “puppet” de Puppet.com, qui contient le paquet Puppet 5.
Une fois l'installation terminée, vous pouvez confirmer qu'il est activé avec la commande suivante.
[ user@agent ~]$ sudo yum repolist
Installez l'agent Puppet sur client à l'aide de la commande ci-dessous.
[ user@agent ~]$ yum -y install puppet-agent
Note:
CN du certificat client
Lors du premier démarrage du client puppet, ce dernier génère une demande de signature avec un certificat utilisant comme CN son FQDN. Il est possible de forcer ce nom dans /etc/puppet/puppet.conf avec la clef certname. Les certificats déjà existant ne seront pas refait, il faut les supprimer de /var/lib/puppet/ssl/* et relancer le client (pour régénérer les certificats).
Il faudra aussi les re-signer sur le serveur.
L'agent de puppet utilise également certains paramètres par défaut pour se connecter au nœud principal (Puppet Master). Cependant, nous devons modifier le fichier de configuration de l'agent et définir les informations relatives à son maître.
[root@agent ~]# vi /etc/puppetlabs/puppet/puppet.conf
Définir comme ci-dessous.
[main] certname = agent.oowy.lan server = puppet.oowy.lan environment = production runinterval = 30m
Note:
Définissez la valeur “server” selon le nom de votre nœud maître.
Définissez la valeur “certname” selon le nom d’hôte client.
Démarrez l'agent de puppet sur le nœud et faites-le démarrer automatiquement au démarrage du système.
[ user@agent ~]$ /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
Notice: /Service[puppet]/ensure: ensure changed 'stopped' to 'running'
service { 'puppet':
ensure => 'running',
enable => 'true',
}
La première fois que Puppet s'exécute sur un nœud “agent”, il envoie une demande de signature de certificat au maître Puppet. Avant que Puppet Server puisse communiquer avec et contrôler le nœud, il doit signer le certificat de ce même nœud.
Se connecter au server Puppet Master pour la gestion des certificats.
Sur le puppet master, exécutez la commande suivante pour répertorier toutes les demandes de certificat non signé :
[ user@puppet ~]# sudo puppetserver ca list Requested Certificates: "agent.oowy.lan" (SHA256) CE:BA:8C:C1:FF:5F:CC:A5:D8:EA:AA:05:29:0C:CF:B0:8F:2C:AB:12:72:99:45:8C:6F:09:61:A1:20:81:05:E6
Pour signer une demande de certificat, utilisez la commande puppetserver ca sign, avec le nom d'hôte du certificat que vous souhaitez signer.
Par exemple, pour signer le certificat de “agent.oowy.lan”, utilisez la commande suivante :
[ user@puppet ~]# sudo puppetserver ca sign agent.oowy.lan Successfully signed certificate request for agent.oowy.lan
Vous voudrez peut-être supprimer un hôte de Puppet ou reconstruire un hôte puis le rajouter à Puppet.
Dans ce cas, vous souhaiterez révoquer le certificat de l'hôte puppet master. Pour ce faire, vous pouvez utiliser l'action de nettoyage :
[ user@puppet ~]$ puppetserver ca clean <_hostname_>
Les certificats associés à l'hôte spécifié seront supprimés de Puppet.
Si vous souhaitez afficher toutes les demandes, signées et non signées, exécutez la commande suivante :
[ user@puppet ~]$ sudo puppetserver ca list --all
Signed Certificates:
puppet.oowy.lan (SHA256) ED:E3:C3:8F:CE:31:27:62:89:28:01:06:E1:FA:92:E1:03:1E:95:5D:2B:45:77:D2:D3:59:B1:2D:74:5F:82:EA alt names: ["DNS:puppet", "DNS:puppet.oowy.lan"]
agent.oowy.lan (SHA256) 4B:F2:86:EB:3C:07:F1:91:5A:BF:38:E1:08:ED:0C:DB:D9:D7:36:3E:E8:C0:F9:93:92:57:98:74:C1:F7:46:76
agent2.oowy.lan (SHA256) 7E:43:3E:C5:5A:95:6B:FC:F2:AE:AE:7B:57:4A:31:3C:D4:0F:B8:D5:97:2B:4B:64:84:14:7E:90:A7:73:06:F3
[ user@agent ~]$ sudo /opt/puppetlabs/bin/puppet agent --test Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Retrieving locales Info: Caching catalog for agent.oowy.lan Info: Applying configuration version '1557064831' Notice: Applied catalog in 0.01 seconds
Le tout premier concept que nous souhaitons présenter est le manifeste Puppet. Un manifeste est un fichier contenant le langage de configuration de Puppet qui décrit comment les ressources doivent être configurées. Le manifeste est ce qui se rapproche le plus de ce que l’on pourrait considérer comme un programme Puppet. Il utilise des ressources pour définir une stratégie à appliquer à un nœud. Il s'agit donc du composant de base de la stratégie de configuration de Puppet et d'un bloc de construction pour les modules Puppet complexes.
L'écriture des manifestes est la partie la plus importante de l’élaboration des politiques relatives aux marionnettes. Commençons par le plus petit composant d’un manifeste.
Les ressources sont le plus petit élément constitutif du langage de configuration de Puppet. Ils représentent un élément singulier que vous souhaitez évaluer, créer ou supprimer. Puppet comprend de nombreuses ressources intégrées. Ces ressources par défaut manipulent des composants système que vous connaissez déjà, notamment:
… et beaucoup plus. De plus, vous pouvez créer vos propres ressources. Cependant, commençons par l’une des ressources les plus simples - la ressource de notification. Commençons par le premier programme stéréotypé écrit dans toutes les langues.
notify { 'greeting':
message => 'Hello, world!'
}
Ce code déclare une ressource de notification nommée “greeting”. Il a un attribut unique, “message” qui a la valeur que nous attendions dans notre premier programme.
Les attributs sont séparés de leurs valeurs à l'aide d'une grosse virgule (également appelée “Hash rocket”), qui est un moyen très courant d'identifier les paires clé/valeur dans les langages de script Perl, Ruby et PHP.
Ce petit bout de code est un manifeste pleinement fonctionnel et valide. Ce manifeste (avec une seule ressource) ne fait qu'une chose, qui consiste à sortir ce message stéréotypé à chaque appel.
Continuons et utilisons Puppet pour évaluer ce manifeste.
[ user@agent ~]$ cat helloworld.pp
notify { 'greeting':
message => 'Hello, world!'
}
Comme vous pouvez le voir dans cet exemple, les manifestes sont des fichiers texte portant une extension “.pp” qui décrivent les ressources à l'aide du langage de configuration de Puppet. Vous pouvez créer ou modifier un manifeste Puppet à l'aide de n'importe quel éditeur de texte.
L'une des meilleures fonctionnalités de Puppet est la facilité de test de votre code. Puppet ne vous oblige pas à configurer des environnements de test compliqués pour évaluer les manifestes. Il est facile, voire carrément trivial, de tester un manifeste Puppet.
Continuons et implémentons ce manifeste. Pour ce faire, nous utiliserons la commande “puppet apply” qui indique à Puppet de mettre en œuvre un seul manifeste Puppet.
[ user@agent ~]$ puppet apply helloworld.pp
Comme vous pouvez le constater, Puppet a implémenté le manifeste. Cela se fait en plusieurs étapes:
Ne vous inquiétez pas de la mémorisation de ces étapes à ce stade du processus d’apprentissage. Nous voulions simplement vous présenter les idées que nous allons approfondir.
Pour l’instant, rappelez-vous que vous allez utiliser “puppet apply” pour implémenter les manifestes Puppet. Il vous fournira des informations détaillées sur les actions que Puppet a entreprises pour aligner les ressources cibles sur la stratégie déclarée.
Il n'y a que quelques règles à retenir lors de la déclaration de ressources.
Le format est toujours le même:
resource_type { 'resource_title':
ensure => present, # usually 'present' or 'absent'
attribute1 => 1234, # number
attribute2 => 'value', # string
attribute3 => ['red','blue'], # array
noop => false, # boolean
}
La règle la plus importante pour les ressources est la suivante : il ne peut y en avoir qu'une. Dans un manifeste ou un ensemble de manifestes appliqués ensemble (le catalogue pour un nœud), une ressource d'un type donné ne peut être déclarée qu'une seule fois avec un titre donné. Toute autre ressource de ce type doit faire référence à un composant sous-jacent différent et avoir un titre unique.
Par exemple, le manifeste suivant va échouer car le même titre est utilisé pour les deux ressources de fichier.
[ user@agent ~]$ cat myfile.pp
file { 'my_file':
ensure => present,
path => 'my_file.txt',
}
file { 'my_file':
ensure => present,
path => 'my_file.csv',
}
notice { 'my_file':
message => "My file is present",
}
[ user@agent ~]$ puppet apply myfile.pp
Error: Evaluation Error: Error while evaluating a Resource Statement, Duplicate declaration: File[
Vous remarquerez qu'aucune erreur n'a été formulée pour la ressource Notice du même titre. Ce n'est pas un conflit. Seules les ressources du même type ne peuvent pas utiliser le même titre. Nommer les fichiers ci-dessus avec leurs chemins complets ne garantit aucun conflit :
file { '/home/vagrant/my_file.txt':
ensure => present,
path => '/home/vagrant/my_file.txt',
}
file { '/home/vagrant/my_file.csv':
ensure => present,
path => '/home/vagrant/my_file.csv',
}
Une fonctionnalité intéressante de Puppet est qu’elle peut vous montrer une ressource existante écrite en langage Puppet. Cela facilite la génération de code basé sur les configurations existantes.
Voyons cela avec un alias de courrier électronique.
[ user@puppet ~]$ puppet resource mailalias postmaster
mailalias { 'postmaster':
ensure => 'present',
recipient => ['root'],
target => '/etc/aliases',
}
Cette sortie vous fournit la structure, la syntaxe et les attributs permettant de déclarer cet alias dans vos règles Puppet. Vous pouvez écrire cette sortie dans un fichier manifeste, modifier le destinataire, puis utiliser “puppet apply” sur ce manifeste pour modifier l'alias postmaster de ce nœud.
Examinons une autre ressource - l’utilisateur pour lequel vous êtes connecté.
[ user@puppet ~]$ sudo puppet resource user myuser
user { 'myuser':
ensure => 'present',
gid => '500',
groups => ['wheel'],
home => '/home/myuser',
password => '$1$sC3NqLSG$FsXVyW7azpoh76edOfAWm1',
password_max_age => '99999',
password_min_age => '0',
shell => '/bin/bash',
uid => '500',
}
Si vous examinez la ressource, vous comprendrez pourquoi l'accès root (sudo) est nécessaire. La ressource utilisateur contient le hachage de mot de passe de l'utilisateur, qui requiert le privilège root pour pouvoir être lu à partir du fichier reflet. Comme avec l'alias ci-dessus, vous pouvez l'écrire dans un fichier, remplacer le mot de passe haché et utiliser “sudo puppet apply” pour changer le mot de passe root.
Examinons d’autres types de ressources: commandes ou exécutables. Vous pouvez utiliser une ressource “exec” pour exécuter des programmes dans le cadre de votre manifeste. Voyons cela maintenant.
exec { 'echo-holy-cow':
path => ['/bin'],
cwd => '/tmp',
command => 'echo "holy cow!" > testfile.txt',
creates => '/tmp/testfile.txt',
returns => [0],
logoutput => on_failure,
}
Maintenant, lorsque vous appliquez ce manifeste, le fichier “testfile.txt” sera créé. Notez que nous utilisons des guillemets simples pour encapsuler les valeurs attribuées aux attributs.
La ressource “exec” définie ci-dessus utilise l'attribut “create”. Cet attribut définit le résultat attendu de l'exécution de la commande. Lorsque le fichier nommé existe, la commande n'est pas exécutée. Cela signifie que le manifeste peut être exécuté à plusieurs reprises et que rien ne changera après la création initiale du fichier.
Voyons cela ici:
[ user@puppet ~]$ puppet apply tmp-testfile.pp Notice: Compiled catalog for puppet.oowy.lan in environment production in 0.03 seconds Notice: /Stage[main]/Main/Exec[echo-holy-cow]/returns: executed successfully Notice: Finished catalog run in 0.07 seconds [ user@puppet ~]$ puppet apply tmp-testfile.pp Notice: Compiled catalog for puppet.oowy.lan in environment production in 0.03 seconds Notice: Finished catalog run in 0.01 seconds
Si vous examinez la ressource “exec” ci-dessus, vous remarquerez que nous devons déclarer comment effectuer le changement et également s’il faut ou non le faire. Cela ressemble beaucoup à la programmation procédurale et peut être très difficile à maintenir.
Il est généralement plus difficile d'écrire du code déclaratif à l'aide d'un “exec”. On a tendance à revenir en arrière dans un style de programmation procédurale. Sauf dans les cas où aucune autre méthode n'est possible, un “exec” est généralement une indication d'une stratégie mal écrite.
Note:
Évitez d'utiliser “exec” chaque fois que cela est possible, en particulier lorsqu'une ressource native Puppet peut faire le travail.
Sinon, comment pourrions-nous créer ce fichier ? Nous aurions pu utiliser la ressource “file”.
Voyons un maintenant.
file { '/tmp/testfile.txt':
ensure => present,
mode => '0644',
replace => true,
contents => 'holy cow!',
}
C'est une politique proprement déclarative. Nous déclarons que le fichier doit exister et quel doit en être le contenu. Nous n'avons pas besoin de nous demander comment et quand apporter des modifications au fichier. De plus, nous avons pu nous assurer que le contenu du fichier reste cohérent, ce qui n’est pas possible avec une commande “echo”.
Note:
Vous remarquerez également que le manifeste déclaratif utilise moins de lignes de texte et garantit une sortie plus cohérente.