Wanneer je een besturingssysteem op een server geïnstalleerd hebt, weet je op dat moment de exacte configuratie van het systeem. Die heb je zelf handmatig ingesteld, of geïnitialiseerd via een systeem zoals Kickstart (Red Hat) of Jumpstart (Solaris). Maar zodra de server begint te draaien, wordt de configuratie minder bekend. Bij het tweaken kun je bijvoorbeeld configuratiebestanden aanpassen en vergeten dit te documenteren. Loopt er later iets mis en moet je het systeem herstellen van een backup, dan kan dit proces nog heel wat handmatige taken vereisen.

Met behulp van een configuratiebeheersysteem kunnen we dit beter aanpakken. Daarmee voer je alle veranderingen van de configuratie op een centrale plaats uit en "push" je ze naar de verschillende servers. Na een herinstallatie hoeft een server zijn configuratie dan slechts van die centrale plaats te halen. Eén van deze systemen is Puppet van Reductive Labs. Het stelt je in staat om onder andere gebruikers, groepen, bestanden en packages te beheren en dit te abstraheren zodat dit op elk systeem op de juiste manier gebeurt, of het nu Debian, Red Hat, FreeBSD of Solaris is.

Een verandering in de configuratie testen is dankzij Puppet bovendien heel eenvoudig: installeer een nieuwe server (fysiek of virtueel) en geef deze de oorspronkelijke configuratie. Daarna push je de nieuwe configuratie naar de testserver en controleer je of alles naar behoren werkt. Zo ja, dan kun je de wijziging ook op de productieserver uitvoeren. Wanneer toch ooit blijkt dat de configuratie van de productieserver tot problemen leidt, kun je altijd terugkeren naar de vorige configuratie, als je tenminste de configuratiebestanden van Puppet in een versiebeheersysteem bijhoudt.

Puppet

Laten we dus eens naar Puppet kijken. Dit gebruikt een client-server architectuur. De server installeer je op de computer waar je alle configuraties bijhoudt, terwijl je de client op elke computer installeert waarnaar je de configuratie wilt pushen. Puppet werkt op zowat alle min of meer POSIX-compatibele besturingssystemen en houdt een lijst bij van besturingssystemen waarop het met succes getest is. In ons voorbeeld installeren we de Puppet-server ("puppetmaster") op Debian Lenny en Puppet-clients op FreeBSD 8 en Ubuntu 9.10. We doen dit om te tonen hoe je met Puppet verschillen in platformen opvangt.

Standaard gebruikt Puppet een pull-model: de clients contacteren elk half uur de server en halen de nieuwste configuratie op. Ze voeren deze configuratie elk door en sturen een rapport terug naar de server. Daarvoor moeten we eerst betrouwbare communicatie tussen de clients en de server opzetten. Voer op elke client het volgende commando uit:

# puppetd --server mypuppetserver.example.com --waitforcert 60 --test

Daarna kijk je op de server of die de aanvragen van de clients ontvangen heeft:

# puppetca --list

ubuntu

freebsd

Nu onderteken je het certificaat van elke client op de server:

# puppetca --sign ubuntu.example.com

# puppetca --sign freebsd.example.com

Manifest

Voor de configuratie van onze systemen kijkt Puppet in het bestand /etc/puppet/manifests/site.pp. Om het geheel wat overzichtelijk te houden, schrijven we echter niet alle code hierin, maar importeren we code uit andere bestanden. We willen bijvoorbeeld een consistente configuratie van sudo op al onze systemen hebben. In site.pp verwijzen we hier als volgt naar:

node default {

include sudo

}

Met de "node default" definitie geven we aan dat elk systeem dat een Puppet-client heeft draaien de sudo-code moet uitvoeren, tenzij anders aangegeven. Maar hoe weet Puppet waar hij de sudo-code vindt? Standaard kijkt Puppet daarvoor in /etc/puppet/modules. We maken daarom een directorystructuur aan voor een sudo-module:

# mkdir -p /etc/puppet/modules/sudo/{manifests,files}

Het echte werk gebeurt nu in /etc/puppet/modules/sudo/manifests/init.pp:

class sudo {

file { "/etc/sudoers":

owner => "root",

group => "root",

mode => 440,

source => "puppet:///sudo/sudoers",

require => Package["sudo"]

}

package { sudo: ensure => latest }

}

Hiermee geven we aan dat het bestand /etc/sudoers op alle systemen als eigenaar en als groep root heeft en alleen door deze gelezen kan worden (mode 440 is u=r,g=r). Bovendien geven we aan dat dit bestand als bron puppet:///sudo/sudoers moet hebben (dat leggen we hieronder uit) en het pakket sudo vereist. In de definitie van het pakket sudo vereisten we dat de recentste sudo geïnstalleerd is.

De source "puppet:///sudo/sudoers" kunnen we interpreteren als een url met als protocol puppet, de :// die we kennen van urls bij websites en dan een pad /sudo/sudoers. Dit pad wordt dan vertaald naar /etc/puppet/modules/sudo/files/sudoers op de Puppet-server. Daarom kopiëren we het bestand /etc/sudoers (of een ander speciaal sudoers-bestand met de gewenste configuratie) naar deze locatie.

Als je nu de permissies van /etc/sudoers op een client handmatig wijzigt, en daarna puppetd --test uitvoert, krijg je door de volgende melding te zien dat Puppet zijn werk doet:

notice: //Node[default]/sudo/File[/etc/sudoers]/mode: mode changed '660' to '440'

Ook als je op een client handmatig de inhoud van /etc/sudoers wijzigt, wordt deze wijziging ongedaan gemaakt door de volgende keer dat de Puppet-client de configuratie opvraagt. Als er een nieuwe versie van sudo uitkomt, wordt dit ook automatisch geïnstalleerd en wanneer we per ongeluk het pakket sudo handmatig verwijderen, wordt dit opnieuw geïnstalleerd.

Platformonafhankelijkheid

Tot nu toe hebben we dit alleen op de Ubuntu-client uitgevoerd, maar als je dit ook op de FreeBSD-client hebt uitgeprobeerd, zul je zien dat dit daar niet gelukt is. FreeBSD kent immers geen groep root, maar een groep wheel. En het bestand /etc/sudoers vinden we daar in /usr/local/etc/sudoers als we sudo uit de ports-collectie installeren. Bovendien moet dit bestand ook een andere inhoud krijgen: onder Ubuntu kunnen leden van de admin-groep root-privileges krijgen, terwijl dit onder FreeBSD leden van de wheel-groep zijn.

We passen het bestand /etc/puppet/modules/sudo/manifests/init.pp daarom aan:

class sudo {

$filename = $operatingsystem ? {

freebsd => "/usr/local/etc/sudoers",

default => "/etc/sudoers"

}

$rootgroup = $operatingsystem ? {

freebsd => "wheel",

default => "root"

}

$sourcefile = $operatingsystem ? {

freebsd => "puppet:///sudo/sudoers.freebsd",

default => "puppet:///sudo/sudoers"

}

file { "$filename":

owner => "root",

group => "$rootgroup",

mode => 440,

source => "$sourcefile",

require => Package["sudo"]

}

package { sudo: ensure => latest }

}

We plaatsen dan een voor FreeBSD aangepast bestand /etc/sudoers in /etc/puppet/modules/sudo/files/sudoers.freebsd. Merk op dat we voor het installeren van het package sudo niets hoefden aan te passen: Puppet weet zelf dat het apt-get moet gebruiken in Ubuntu en een make-commando in de juiste Ports-directory in FreeBSD.

En verder

We hebben nu voor sudo een module aangemaakt, maar we kunnen dit nog voor heel wat andere systeemdiensten doen, zoals ssh, de package manager, etc. Al deze modules krijgen een eigen directory in /etc/puppet/modules/. Daarna voegen we de module toe met "include modulenaam" in site.pp.

We hoeven echter niet op alle clients dezelfde configuratie te gebruiken. Wil je bijvoorbeeld op één client niet van deze sudo-configuratie gebruik maken, dan voeg je in site.pp het volgende toe:

node node1.example.com {

}

Puppet laat veel meer toe dan we in deze korte introductie kunnen tonen. Gelukkig is er heel wat documentatie te vinden. De Language Tutorial toont je alle mogelijkheden die je kunt uitdrukken in Puppet-configuratiebestanden. Ook vaak gestelde vragen zijn op de wiki te vinden, evenals best practices. Een aantal recepten kunnen je al op weg helpen met het configureren. Puppet vereist wel wat configuratiewerk, maar als dit eenmaal in orde is, kun je je servers quasi automatisch beheren.

Bron: Techworld