Spis treści
W trzeciej części naszych przygód z puppet’em skupimy się bardziej na jego uniwersalności. Do naszego środowiska testowego dodamy dwie nowe maszyny. Jedna z nich ma zainstalowany systemem Ubuntu, a druga OpenBSD. Jako punkt startu wykorzystamy konfigurację z części 2 (warto też zajrzeć do części 1), którą rozwiniemy tak, aby działała z dwoma nowymi systemami.
Krótkie podsumowanie dla wszystkich maszyn znajduje się w poniższej tabeli:
Nazwa hosta (fqdn) | Adres IP | Rola | System |
---|---|---|---|
puppet-master.local.net | 192.168.34.20 | Serwer | CentOS 6.5 |
puppet-slave01.local.net | 192.168.34.21 | Klient | CentOS 6.5 |
puppet-slave02.local.net | 192.168.34.22 | Klient | OpenBSD 5.5 |
puppet-slave03.local.net | 192.168.34.23 | Klient | Ubuntu 14.04 |
Puppet – instalacja w OpenBSD
Niezbędne pakiety znajdziemy w repozytoriach systemu. Pamiętamy o ustawieniu zmiennej PKG_PATH
root@puppet-slave02:~> tail /root/.profile export PKG_PATH=http://artfiles.org/openbsd/5.5/packages/amd64/
root@puppet-slave02:~> sh .profile root@puppet-slave02:~> echo $PKG_PATH http://artfiles.org/openbsd/5.5/packages/amd64/
Przechodzimy do instalacji:
root@puppet-slave02:~> pkg_add -i puppet
pkg_add
automatycznie rozwiąże wszystkie zależności, a po chwili pakiet jest już dostępny w systemie. Dodane zostały też 2 skrypty startowe: /etc/rc.d/puppetd
oraz /etc/rc.d/puppetmasterd
. Skrypt puppetd wpisujemy do /etc/rc.conf.local
, dzięki czemu proces będzie automatycznie startował z systemem:
root@puppet-slave02:~> cat rc.conf.local pkg_scripts="puppetd"
Tak jak pisaliśmy już w pierwszej części puppet agent domyślnie szuka serwera korzystając z nazwy hosta puppet. Uzupełniamy więc nasz plik /etc/hosts
:
192.168.34.20 puppet-master.local.net puppet.local.net puppet
Uruchamiamy agenta po raz pierwszy, po czym podpisujemy nowy certyfikat na puppet-master
root@puppet-slave02:~> puppet agent --test Exiting; no certificate found and waitforcert is disabled
[root@puppet-master ~]# puppet cert --list "puppet-slave02.local.net" (SHA256) 27:71:C0:8F:DB:24:2F:7A:A1:12:A7:E4:6C:A1:53:4C:56:84:A1:8F:03:8E:6C:D2:48:FE:C1:75:15:96:FF:D2
[root@puppet-master ~]# puppet cert sign puppet-slave02.local.net Notice: Signed certificate request for puppet-slave02.local.net Notice: Removing file Puppet::SSL::CertificateRequest puppet-slave02.local.net at '/var/lib/puppet/ssl/ca/requests/puppet-slave02.local.net.pem'
Testujemy ponownie połączenie:
root@puppet-slave02:~> puppet agent --test Info: Caching certificate for puppet-slave02.local.net Info: Caching certificate_revocation_list for ca Info: Caching certificate for puppet-slave02.local.net Info: Retrieving plugin Notice: /File[/var/puppet/lib]/group: group changed '_puppet' to 'wheel' Info: Caching catalog for puppet-slave02.local.net Info: Applying configuration version '1414481522' Info: Creating state file /var/puppet/state/state.yaml Notice: Finished catalog run in 0.31 seconds
Świetnie. Czas na Ubuntu.
Puppet – instalacja w Ubuntu
Tutaj także znajdziemy wszystkie niezbędne pakiety w oficjalnym repozytorium, instalujemy je korzystając z polecenia apt-get
:
root@puppet-slave03:~# apt-get install puppet
Pamiętamy o dodaniu hosta puppet do pliku /etc/hosts
, następnie uruchamiamy testowo agenta:
root@puppet-slave03:~# puppet agent --test Info: Caching certificate for ca Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml Info: Creating a new SSL certificate request for puppet-slave03.local.net Info: Certificate Request fingerprint (SHA256): AB:43:B9:7D:36:14:0D:F4:49:27:C6:C1:4B:78:3D:2A:48:D1:BC:B2:18:89:1A:D7:9B:96:5C:F6:1C:B2:52:AE Info: Caching certificate for ca Exiting; no certificate found and waitforcert is disabled
Nowy certyfikat został wygenerowany, musimy go teraz podpisać:
[root@puppet-master ~]# puppet cert list "puppet-slave03.local.net" (SHA256) AB:43:B9:7D:36:14:0D:F4:49:27:C6:C1:4B:78:3D:2A:48:D1:BC:B2:18:89:1A:D7:9B:96:5C:F6:1C:B2:52:AE
[root@puppet-master ~]# puppet cert sign puppet-slave03.local.net Notice: Signed certificate request for puppet-slave03.local.net
Uwaga w Ubuntu musimy jeszcze aktywować agenta wpisując następujące polecenie:
root@puppet-slave03:~# puppet agent --enable
Testujemy ponownie połączenie:
root@puppet-slave03:~# puppet agent --test Info: Retrieving plugin Info: Caching catalog for puppet-slave03.local.net Info: Applying configuration version '1414586482' Info: Creating state file /var/lib/puppet/state/state.yaml Notice: Finished catalog run in 0.04 seconds
Puppetmaster – konfiguracja
Czas rozwinąć naszą konfigurację. W naszym środowisku mamy teraz 3 klientów, na każdym z nich działa inny system operacyjny. Chcemy też na wszystkich hostach uruchomić serwer www (apache), który podobnie jak poprzednio będzie wyświetlał prostą stronę www.
Moduł firewall
Zmiany konfiguracji dla CentOS
Zaczniemy od małej reogranizacji. W pliku init.pp
zdefiniujemy tylko klasę firewall, a następnie będziemy wczytywać/załączać odpowiedni plik .pp. Dla CentOS będzie to centos.pp, dla OpenBSD openbsd.pp i analogicznie w przypadku Ubuntu.
[root@puppet-master manifests]# cat init.pp class firewall { include "firewall::$::operatingsystem" }
Poniżej zawartość centos.pp
:
[root@puppet-master manifests]# cat centos.pp class firewall::centos inherits firewall { package { 'iptables': ensure => present, } service { "iptables": ensure => running, enable => true, require => Package['iptables'], } file { "/etc/sysconfig/iptables": ensure => present, owner => root, group => root, mode => 600, source => "puppet://$puppetmaster/modules/firewall/iptables", require => Package["iptables"], notify => Service["iptables"], } }
oraz struktura plików i katalogów w module firewall:
[root@puppet-master firewall]# tree -n . ├── files │ ├── iptables │ └── pf-openbsd └── manifests ├── centos.pp ├── init.pp ├── openbsd.pp └── ubuntu.pp
Packet filter w OpenBSD
Czas na OpenBSD. Reguły firewall’a zapisane są w pliku /etc/pf.conf:
[root@puppet-master ~]# cd /etc/puppet/modules/firewall/files/ [root@puppet-master files]# cat pf-openbsd set skip on lo block return # block stateless traffic pass quick proto tcp from any to self port 80 pass quick proto tcp from any to self port 443 pass # establish keep-state block return in on ! lo0 proto tcp to port 6000:6010
Jest to praktycznie domyślna konfiguracja firewall’a w OpenBSD, dodaliśmy tylko poglądowo 2 reguły zezwalające na ruch na portach 80 i 443. Są one tak naprawdę zbędne (poniżej mamy regułę pass, która zezwala „na wszystko”), ale pakiety które przychodzą na wskazane porty będą osobno wyszczególnione (przydatne np. do statystyk).
Edytujemy teraz openbsd.pp
:
class firewall::openbsd inherits firewall { file { "/etc/pf.conf": ensure => present, owner => root, group => wheel, mode => 600, source => "puppet://$puppetmaster/modules/firewall/pf-openbsd", } exec { "/sbin/pfctl -f /etc/pf.conf": subscribe => File["/etc/pf.conf"], refreshonly => true, } }
/etc/pf.conf
– w nim znajdziemy odpowiednie reguły dla firewalla. Jego źródłem jest pf-openbsd
. Dodatkowo ustawiamy mu odpowiednie prawa, etc.
Podobnie jak w przypadku iptables musimy być pewni, że po każdej zmianie w pf-openbsd
puppet agent przeładuje reguły firewall’a. W systemie OpenBSD używamy do tego celu polecenia /sbin/pfctl -f /etc/pf.conf
, które zdefiniowaliśmy w sekcji exec.
Na koniec pozostało nam dodanie nowego serwera do pliki nodes.pp
oraz przetestowanie konfiguracji:
[root@puppet-master manifests]# cat nodes.pp ... node 'puppet-slave02.local.net' { include firewall }
root@puppet-slave02:~>puppet agent --test Info: Retrieving plugin Info: Caching catalog for puppet-slave02.local.net Info: Applying configuration version '1414666094' Notice: /Stage[main]/Firewall::Openbsd/File[/etc/pf.conf]/content: --- /etc/pf.conf Thu Oct 30 13:08:28 2014 +++ /tmp/puppet-file20141030-8833-s4iu02 Thu Oct 30 13:08:40 2014 ... ... Info: /Stage[main]/Firewall::Openbsd/File[/etc/pf.conf]: Filebucketed /etc/pf.conf to puppet with sum 42c7a9a23e82f3ab1d327e5022c23de6 Notice: /Stage[main]/Firewall::Openbsd/File[/etc/pf.conf]/content: content changed '{md5}42c7a9a23e82f3ab1d327e5022c23de6' to '{md5}e97864ad5e5781cbf5b7c28f2ed2a7b0' Info: /Stage[main]/Firewall::Openbsd/File[/etc/pf.conf]: Scheduling refresh of Exec[/sbin/pfctl -f /etc/pf.conf] Notice: /Stage[main]/Firewall::Openbsd/Exec[/sbin/pfctl -f /etc/pf.conf]: Triggered 'refresh' from 1 events
Świetnie puppet nadpisał domyślną konfigurację firewall’a, następnie go zrestartował. Sprawdźmy czy reguły są w użyciu:
root@puppet-slave02:~>pfctl -sr block return all pass quick inet6 proto tcp from any to ::1 port = 80 flags S/SA pass quick inet6 proto tcp from any to ::1 port = 443 flags S/SA pass quick inet proto tcp from any to 127.0.0.1 port = 80 flags S/SA pass quick inet proto tcp from any to 10.0.2.15 port = 80 flags S/SA pass quick inet proto tcp from any to 192.168.34.22 port = 80 flags S/SA pass quick inet proto tcp from any to 127.0.0.1 port = 443 flags S/SA pass quick inet proto tcp from any to 10.0.2.15 port = 443 flags S/SA pass quick inet proto tcp from any to 192.168.34.22 port = 443 flags S/SA pass all flags S/SA block return in on ! lo0 proto tcp from any to any port 6000:6010
Wygląda dokładnie tak jak zdefiniowaliśmy, naszym kolejnym krokiem będzie system Ubuntu.
Iptables w Ubuntu
W Ubuntu brakuje skryptów startowych dla iptables (domyślnie używa się ufw – Uncomplicated Firewall). Z pomocą przychodzi tutaj pakiet iptables-persistent, po instalacji którego wszystkie reguły możemy wpisać do /etc/iptables/rules.v4
. Tworzymy ubuntu.pp
z następującą zawartością
class firewall::ubuntu inherits firewall { package { 'iptables-persistent': ensure => present, } service { "iptables-persistent": ensure => running, enable => true, require => Package['iptables-persistent'], } file { "/etc/iptables/rules.v4": ensure => present, owner => root, group => root, mode => 600, source => "puppet://$puppetmaster/modules/firewall/iptables", require => Package["iptables-persistent"], notify => Service["iptables-persistent"], } }
Jak widzimy jedyna różnica w stosunku do systemu CentOS to wykorzystanie pakietu iptables-persistent. Pakiet iptables zostanie doinstalowany automatycznie jako brakująca zależność, dlatego nie musimy się o niego martwić. Oczywiście uzupełniamy nodes.pp
i testujemy:
[root@puppet-master manifests]# cat nodes.pp ... node 'puppet-slave03.local.net' { include firewall }
root@puppet-slave03:~# puppet agent --test Info: Retrieving plugin Info: Caching catalog for puppet-slave03.local.net Info: Applying configuration version '1414670082' Notice: /Stage[main]/Firewall::Ubuntu/Package[iptables-persistent]/ensure: created Notice: /Stage[main]/Firewall::Ubuntu/File[/etc/iptables/rules.v4]/content: --- /etc/iptables/rules.v4 2014-10-30 12:58:19.632736962 +0100 +++ /tmp/puppet-file20141030-12711-md9eho 2014-10-30 12:58:25.084668422 +0100 ... ... Info: /Stage[main]/Firewall::Ubuntu/File[/etc/iptables/rules.v4]: Filebucketed /etc/iptables/rules.v4 to puppet with sum 62280ca1bc9b97f613ab995a7ed6f043 Notice: /Stage[main]/Firewall::Ubuntu/File[/etc/iptables/rules.v4]/content: content changed '{md5}62280ca1bc9b97f613ab995a7ed6f043' to '{md5}8aadda5bfc7398bbc0912b2e6130e1b0' Info: /Stage[main]/Firewall::Ubuntu/File[/etc/iptables/rules.v4]: Scheduling refresh of Service[iptables-persistent] Notice: /Stage[main]/Firewall::Ubuntu/Service[iptables-persistent]/ensure: ensure changed 'stopped' to 'running' Info: /Stage[main]/Firewall::Ubuntu/Service[iptables-persistent]: Unscheduling refresh on Service[iptables-persistent] Notice: Finished catalog run in 17.08 seconds
Wszystkie pakiety zostały poprawnie doinstalowane, a nasz firewall działa:
root@puppet-slave03:~# dpkg -l | awk '/iptables/ { print $2" "$3 } ' iptables 1.4.21-1ubuntu1 iptables-persistent 0.5.7
root@puppet-slave03:~# iptables -L INPUT -n Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:443 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Moduł httpd
Czas przygotować drugi moduł. Tak samo jak dla firewall’a każda z dystrybucji będzie mieć osobny plik .pp, poniżej struktura katalogu modules/httpd:
[root@puppet-master httpd]# tree . ├── manifests │ ├── centos.pp │ ├── init.pp │ ├── openbsd.pp │ └── ubuntu.pp └── templates ├── default-vhost.erb └── index.html.erb
oraz zawartość init.pp
:
class httpd { include "httpd::$::operatingsystem" }
Zmiany w konfiguracji dla CentOS
W przypadku tej dystrybucji jedyna zmiana ma miejsce w pierwszej linii przy definicji klasy:
class httpd::centos inherits httpd { package { httpd: ensure => present, } service { "httpd": ensure => running, enable => true, require => Package["httpd"], } file { "/etc/httpd/conf.d/00-default-vhost.conf": ensure => present, owner => root, group => root, mode => 444, content => template("httpd/default-vhost.erb"), require => Package["httpd"], notify => Service["httpd"], } file { "/var/www/html/index.html": ensure => present, owner => apache, group => apache, mode => 444, content => template("httpd/index.html.erb"), require => Package["httpd"], } }
Jedyna zmiana ma miejsce w pierwszej linii przy definicji klasy.
httpd w OpenBSD
W OpenBSD httpd jest domyślnie zainstalowany, ale wyłączony. W systemie dostępny jest też skrypt startowy (/etc/rc.d/httpd
). Do uruchomienia procesu powinniśmy zmienić wartość zmiennej w pliku /etc/rc.conf
(lub lepiej w /etc/rc.conf.local
) z http_flags=NO na httpd_flags=””:
root@puppet-slave02:~>/etc/rc.d/httpd start /etc/rc.d/httpd: need -f to force start since httpd_flags=NO
Moglibyśmy też po prostu użyć flagi „-f”… jednak lepiej zrobić to we właściwy sposób. Potrzebujemy aby puppet dodał odpowiedni wpis do /etc/rc.conf.local
, ale tylko jeśli wspomnianego wpisu w tym pliku jeszcze nie ma (czyli właściwie tylko za pierwszym razem). W module httpd w pliku init.pp
zdefiniujemy funkcję, która nam pomoże w osiągnięciu naszego celu:
class httpd { include "httpd::$::operatingsystem" define line($file, $line, $ensure = 'present') { exec { "/bin/echo '${line}' >> '${file}'": unless => "grep -qFx '${line}' '${file}'", path => "/bin:/usr/bin", } } }
Przy pomocy polecenia echo dopisujemy do pliku ($file) linię ($line), pod warunkiem że grep nie znajdzie już tego samego wpisu.
Proces www działa domyślnie w środowisku chroot w katalogu /var/www
. Poniżej gotowy plik openbsd.pp
:
class httpd::openbsd inherits httpd { file { "/etc/rc.conf.local": ensure => present, owner => root, group => wheel, mode => 644, } file { "/var/www/htdocs/index.html": ensure => present, owner => www, group => www, mode => 444, content => template("httpd/index.html.erb"), } file { "/var/www/conf/00-default-vhost.conf": ensure => present, owner => root, group => daemon, mode => 444, content => template("httpd/default-vhost.erb"), notify => Service["httpd"], } line { rc_conf_local: file => "/etc/rc.conf.local", line => "httpd_flags=\"\"", } line { httpd_conf: file => "/var/www/conf/httpd.conf", line => "Include \"/var/www/conf/00-default-vhost.conf\"" , } service { "httpd": ensure => running, } }
A w nim:
- tworzymy (jeśli nie istnieją) pliki
rc.conf.local
orazindex.html
. Nadajemy im odpowiednie prawa - korzystając z template’u tworzymy plik
00-default-vhost.conf
. Dodatkowo będziemy informować usługę httpd o wszelkich zmianach w tym pliku - dodajemy wspomnianą wcześniej linię httpd_flags=”” do
rc.conf.local
- dodajemy linijkę z definicją vhost’a do
httpd.conf
- upewniamy się, że proces httpd działa
Na koniec aktywujemy ten moduł dla puppet-slave02:
node 'puppet-slave02.local.net' { include firewall include httpd }
Apache2 w Ubuntu
Tutaj czekają nas tylko drobne zmiany w porównaniu do CentOS:
[root@puppet-master manifests]# cat ubuntu.pp class httpd::ubuntu inherits httpd { package { apache2: ensure => present, } service { "apache2": ensure => running, enable => true, require => Package["apache2"], } file { "/etc/apache2/sites-available/000-default.conf": ensure => present, owner => root, group => root, mode => 444, content => template("httpd/default-vhost.erb"), require => Package["apache2"], notify => Service["apache2"], } file { "/var/www/html/index.html": ensure => present, owner => root, group => root, mode => 444, content => template("httpd/index.html.erb"), require => Package["apache2"], } }
Nazwa daemona to apache2 (zamiast httpd), a domyślny plik wirtualnego hosta to /etc/apache2/sites-available/000-default.conf
. Zmiana w pliku nodes.pp
:
[root@puppet-master manifests]# cat nodes.pp node 'puppet-slave03.local.net' { include firewall include httpd }
Modyfikacja plików template
W poprzedniej części stworzyliśmy dwa pliki template. Jeden z nich generował prosty index.html
, drugi konfigurację dla vhost’a. Korzystamy teraz z różnych systemów musimy dynamicznie ustawić właściwe ścieżki w pliku default-vhost.erb
, zgodnie z poniższą tabelą:
System operacyjny | DocumentRoot | ErrorLog |
---|---|---|
CentOS 6.5 | /var/www/html | /var/log/httpd/<%= fqdn %>.error_log |
OpenBSD 5.5 | /htdocs/ | /logs/<%= fqdn %>.error_log |
Ubuntu 14.04 | /var/www/html | /var/log/apache2/<%= fqdn %>.error_log |
Skorzystamy tu ze zmiennej operatingsystem oraz z prostych warunków if/else:
[root@puppet-master templates]# cat default-vhost.erb <VirtualHost *:80> ServerAdmin admin@local.net ServerName <%= fqdn %> <% if operatingsystem == "Ubuntu" %> DocumentRoot /var/www/html/ ErrorLog /var/log/apache2/<%= fqdn %>.error_log <% elsif operatingsystem == "OpenBSD" %> DocumentRoot /htdocs/ ErrorLog logs/<%= fqdn %>.error_log <% else %> DocumentRoot /var/www/html/ ErrorLog /var/log/httpd/<%= fqdn %>.error_log <% end %> </VirtualHost>
oraz zawartość index.html.erb
:
[root@puppet-master templates]# cat index.html.erb <html> <body> Default index.html site from <%= fqdn %> (System: <%= operatingsystem %>). </body> </html>
Test całego środowiska
Konfiguracja jest już gotowa, czas na wielki test naszego środowiska. Na każdym z systemów tak jak uprzednio uruchomimy puppet agenta, który miejmy nadzieje ustawi wszystko tak jak należy.
CentOS
Zaczynamy od CentOS:
[root@puppet-slave01 ~]# puppet agent --test
Zajmie to trochę czasu, ale pod koniec powinniśmy mieć działający proces httpd w systemie:
[root@puppet-slave01 ~]# /etc/init.d/httpd status httpd (pid 1604) is running...
oraz reguły w iptables:
[root@puppet-slave01 ~]# iptables -L -n | grep -E "80|443" ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:443
Na koniec wpisujemy adres puppet-slave01.local.net w przeglądarce:
OpenBSD
Kolejny w kolejce jest system z rodziny *BSD. Procedura dokładnie taka sama jak poprzednio:
[root@puppet-slave02 ~]# puppet agent --test
Zobaczmy, czy puppet dodał właściwe linie do plików rc.conf.local
oraz httpd.conf
:
root@puppet-slave02:~>tail -n1 /etc/rc.conf.local httpd_flags=""
root@puppet-slave02:~>tail -n1 /var/www/conf/httpd.conf Include "/var/www/conf/00-default-vhost.conf"
Oraz zrzut ekranu z przeglądarki:
Ubuntu
Na koniec popularna dystrybucja Ubuntu, tutaj też nie przewidujemy żadnych problemów:
root@puppet-slave03:~# puppet agent --test
root@puppet-slave03:~# /etc/init.d/apache2 status * apache2 is running
root@puppet-slave03:~# iptables -L -n | grep -E "80|443" ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:443
oraz przeglądarka:
Myślę, że powyższy przykład dowiódł uniwersalności puppeta. Początki mogą wydawać się trudne i żmudne, zwłaszcza że musimy wziąć pod uwagę wiele zależności (jak wymagania pakietów, ścieżki oraz nazwy usług) jednak nasz wysiłek opłaci się w przyszłości. Wszystkie większe zmiany najlepiej testować na „czystych” systemach, przez co upewnimy się, że puppet wykonał wszystkie kroki tak jak należy.
Pełną konfigurację katalogu /etc/puppet
z puppet-master można też pobrać stąd.
Szukam czegoś podobnego do pracy! dzięki!