Ziel dieser Anleitung ist es, ein skalierendes Puppet Setup auf einem CentOS 6.5 Host bereitzustellen. Vorinstalliert ist ausschließlich ein sshd.
Puppet ist in Ruby geschrieben und unterstützt mittlerweile Ruby2. Hier gibt es signifikante Performanceoptimierungen im Vergleich zu Ruby 1.8.7. Leider ist dies die Standardversion unter CentOS, weshalb wir Ruby 2 über RVM nachinstallieren:
curl -L get.rvm.io | bash -s stable source /etc/profile.d/rvm.sh rvm requirements rvm install 2.1.1 rvm use 2.1.1 --default rvm rubygems current
Außerdem ist es empfehlenswert auf einen aktuelleren Kernel zu wechseln (z.B. kernel-lt), diese bieten große Performanceoptimierungen:
Installation des ELRepo + Kernel-LT
Zusätzlich wird das EPEL Repository benötigt für aktuelle Tools wie z.B. htop:
Installation von EPEL
Der Puppet-Master ist eine Ruby App welche einen Webserver benötigt da es mit den Clients über eine Pseudo-YAML/HTTP API spricht. In großen Setups bietet sich nginx an da dieser effizienter als Apache arbeitet. Die nginx Version im CentOS Repo ist leider sehr alt, glücklicherweise bieten die nginx Entwickler ein eigenes Repo an. Eine Anleitung zum einrichten findet sich hier.
Danach kann nginx ganz normal installiert, gestartet und für den Autostart markiert werden:
yum install nginx service nginx configtest service nginx start chkconfig nginx on
Für Puppet muss noch ein vHost unter /etc/nginx/conf.d/puppet.conf
angelegt werden:
server { listen 8140 ssl; server_name puppet puppet.example.org; access_log /var/log/nginx/puppet_access.log; error_log /var/log/nginx/puppet_error.log; root /usr/share/puppet/rack/puppetmasterd/public; # accept huge puppet reports client_max_body_size 5M; ssl_certificate /var/lib/puppet/ssl/certs/puppet.example.com.pem; ssl_certificate_key /var/lib/puppet/ssl/private_keys/puppet.example.com.pem; ssl_crl /var/lib/puppet/ssl/ca/ca_crl.pem; ssl_client_certificate /var/lib/puppet/ssl/certs/ca.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256: [BR] +AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED: [BR] !ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA; add_header Strict - Transport - Security max - age =2592000; ssl_prefer_server_ciphers on; ssl_verify_client optional; ssl_verify_depth 1; ssl_session_cache shared:SSL:128m; ssl_session_timeout 5m; proxy_redirect http://$host/ https://$host/; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Scheme $scheme; proxy_set_header X-Client-Verify $ssl_client_verify; proxy_set_header X-Client-DN $ssl_client_s_dn; proxy_set_header X-SSL-Subject $ssl_client_s_dn; proxy_set_header X-SSL-Issuer $ssl_client_i_dn; proxy_read_timeout 65; proxy_set_header X-Forwarded-Protocol https; proxy_set_header X-Forwarded-SSL on; } upstream backend { server unix:/usr/share/puppet/rack/puppetmasterd/tmp/production.socket; } }
Nginx fungiert nach außen als Proxy, der Puppet Server ist in Ruby geschrieben, dieser Ruby Code wird von Puma ausgeführt und an nginx weitergereicht. Puma wird über gem installiert, dem Ruby Libs/Apps Paket Manager. Dieser hat noch diverse Systemabängigkeiten die im Vorfeld installiert werden müssen, im Anschluss erfolgt die eigentliche Installation von puma. Als Schnittstelle zwischen unserem Ruby Webserver Puma und der eigentlichen Ruby-App läuft Rack, dies wird ebenfalls über gem installiert:
yum install ruby-devel gcc openssl-devel gem install puma rack
Puppetlabs stellt einen yum Mirror mit aktuellen Packages für CentOS 6 bereit. Der Mirror wird wie folgt eingerichtet:
yum install http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-7.noarch.rpm
Installation von Puppet:
yum update yum install puppet-server
Alternativer Weg:
Puppet kann man auch über gem installieren. Ob man yum oder gem bevorzugt ist Geschmackssache, in meinem Fall ist es gem:
gem install puppet
In beiden Fällen ist es danach noch nötig einige Ordner anzulegen und passende Rechte zu setzen:
mkdir -p /usr/share/puppet/rack/puppetmasterd
mkdir /usr/share/puppet/rack/puppetmasterd/public /usr/share/puppet/rack/puppetmasterd/tmp /usr/share/puppet/rack/puppetmasterd/log
cp /usr/share/puppet/ext/rack/files/config.ru /usr/share/puppet/rack/puppetmasterd/
chown puppet:puppet /usr/share/puppet/rack/puppetmasterd/*[/bash]
In der /etc/puppet/puppet.conf
muss noch folgender Part ergänzt werden:
[agent] server = puppet.example.org [master] certname = puppet.example.org
Puma lässt sich nun schon auf der Bash starten:
puma /usr/share/puppet/rack/puppetmasterd/config.ru Puma starting in single mode... * Version 2.7.1, codename: Earl of Sandwich Partition * Min threads: 0, max threads: 16 * Environment: development * Listening on tcp://0.0.0.0:9292 Use Ctrl-C to stop
Wir möchten Puma aber noch mehrere Parameter übergeben. Z.B. ein Pfad zu einer Logdatei, zum passenden Unix Socket auf dem gelauscht werden soll oder die zugehörige pid Datei. Dazu wird die Datei /usr/share/puppet/rack/puppetmasterd/puma.rb
erstellt mit folgendem Inhalt:
#!/usr/bin/env puma application_path = '/usr/share/puppet/rack/puppetmasterd/' railsenv = 'production' directory application_path environment railsenv daemonize true pidfile "#{application_path}tmp/puma-#{railsenv}.pid" state_path "#{application_path}tmp/puma-#{railsenv}.state" stdout_redirect "#{application_path}/log/puma-#{railsenv}.stdout.log" "#{application_path}/log/puma-#{railsenv}.stderr.log" threads 0, 16 bind "unix://#{application_path}tmp/#{railsenv}.socket"
Puma startet sich nun wie folgt:
RAILS_ENV=production puma -C /usr/share/puppet/rack/puppetmasterd/puma.rb
Über ein Gemset kann man definieren welche Gems alle benötigt werden für eine Ruby App. Über dieses Gemfile kann man gezielt alle passenden Abhängigkeiten automatisch installieren und updaten. Das Gemfile wird als /usr/share/puppet/rack/puppetmasterd/Gemfile
mit folgendem Inhalt erstellt:
gem 'puma' gem 'rack' gem 'puppet'
Puma muss nun leicht abgeändert gestartet werden und liefert folgenden Output:
RAILS_ENV=production bundle exec puma -C /usr/share/puppet/rack/puppetmasterd/puma.rb Puma starting in single mode... * Version 2.7.1, codename: Earl of Sandwich Partition * Min threads: 0, max threads: 16 * Environment: production
Warum Puma:
In den meisten Installationsanleitungen wird Passenger als Ruby Webserver empfohlen. Dieser bietet von Haus aus ein passendes Apache Modul an. Nginx benötigt ebenfalls ein Modul, leider können hier keine Module zur Laufzeit eingebunden werden sondern nur bei der initialen Kompilierung. Aufgrund der Wartbarkeit möchte ich auf selbst kompilierte Software verzichten. Puma ist ein relativ junger Ruby Webserver welcher laut einigen Benchmarks mit Passenger konkurieren kann hinsichtlich der Performance. Puma kann zwar (im Gegensatz zu Passenger) weder node.js noch Python ansteuern sondern nur Ruby, aber dies ist in unserem Fall ausreichend.
Installation der Puppetdb:
In der PuppetDB können Facts und Kataloge der einzelnen Nodes gespeichert werden, dies wird für Funktionen wie exported resources benötigt. Die PuppetDB ist in Java geschrieben und schreibt Ihre Daten in ein Postgres Backend. CentOS 6.5 bietet nur Postgres 8.4, aus Performancegründen installieren wir die aktuelle 9.3 Version direkt von den Postgres Entwicklern:
Zuerst müssen wir in der Datei /etc/yum.repos.d/CentOS-Base.repo
in den Abschnitten [base]
und [updates]
den Eintrag exclude=postgresql*
ergänzen. Danach fügen wir das neue Repo hinzu, installieren die benötigten Pakete, initialisieren Postgres und setzen den Dienst auf autostart:
yum install http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-redhat93-9.3-1.noarch.rpm yum install postgresql93-server postgresql93-contrib service postgresql-9.3 initdb chkconfig postgresql-9.3 on
Die PuppetDB wird über ein Puppet Modul installiert, dieses wird zuerst von Puppet Forge heruntergeladen:
puppet module install puppetlabs/puppetdb
Das Modul muss noch angepasst werden, ansonsten installiert es Postgres 8.4 und nutzt nicht die schon installierte Version 9.3. Dies geschieht in der Datei /etc/puppet/modules/postgresql/manifests/params.pp
. In den Zeilen 25-31 werden die zu installierenden Pakete aufgelistet. Die neuen Versionen heisen nicht mehr nur noch ‘postgres’ sondern nun ‘postgresql93’.
Die PuppetDB Klasse kann man nun dem Node zuweisen in der /etc/puppet/manifests/site.pp
:
node /puppet.example.org/ {
include puppetdb
include puppetdb::master::config
}
Die Vorbereitungen sind abgeschlossen, nun kann ein puppet Run erfolgen welcher die DB einrichtet:
puppet agent -t
Warum ein Loadbalancer/Proxy vor dem eigentlichen Webserver?
Nginx ist ein leichtgewichtiger Webserver mit vielen unbekannten Talenten. Zum einen kann er auch als Webfirewall dienen und bösartige Anfragen herausfiltern um somit Attacken auf Puma/Rack/Puppet-Master zu unterbinden, zum anderen kann er SSL terminieren und mehrere Backends ansprechen. Dies ist notwendig um ein flexibles Setup zu bauen das man problemlos um mehrere Puppet-Master Nodes erweitern und verkleinern kann.
Abschliesende Funktionalitätstests:
Man kann sich nun auf einem Client Puppet installieren und testweise eine Verbindung zu unserem neuen Setup aufbauen. Hier eine beispielhafte Installationsanleitung für einen Puppet Client unter Debian Wheezy. Leider ist die Version in dem Repo zu alt weshalb ich zuerst den APT-Repo von Puppetlabs hinzufüge:
wget https://apt.puppetlabs.com/puppetlabs-release-wheezy.deb dpkg -i puppetlabs-release-wheezy.deb aptitude update aptitude -y safe-upgrade aptitude install puppet
Nun kann der erste Puppetrun gestartet werden:
puppet agent --server puppet.example.com --onetime --no-daemonize --verbose --noop Info: Creating a new SSL key for meine-tolle-testkiste.example.com Info: Caching certificate for ca Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml Info: Creating a new SSL certificate request for meine-tolle-testkiste.example.com Info: Certificate Request fingerprint (SHA256): D9:13:F7:01:FF:F8:97:97:40:95:95:55:21:FA:D2:02:EF:05:9D:14:E5:45:3C:CD:61:4E:44:AC:B8:CD:19:05 Info: Caching certificate for ca Exiting; no certificate found and waitforcert is disabled
Auf unserem Puppet-Master liegt nun ein Clientzertifikat das wir signieren müssen. Danach kann der Client SSL-verschlüsselt mit dem Master kommunizieren:
puppet cert sign meine-tolle-testkiste.example.com Notice: Signed certificate request for meine-tolle-testkiste.example.com Notice: Removing file Puppet::SSL::CertificateRequest meine-tolle-testkiste.example.com at '/var/lib/puppet/ssl/ca/requests/meine-tolle-testkiste.example.com.pem'
Ein erneuter Puppet run auf dem Client ist nun erfolgreich:
puppet agent --server puppet.rackmonkey.de --onetime --no-daemonize --verbose --noop Info: Retrieving plugin Info: Caching catalog for host02.bastelfreak.org Info: Applying configuration version '1387582674' Notice: Finished catalog run in 0.01 seconds
Für ein ordentliches Life-Cycle Management sowie als Webfrontend für Puppet bietet sich Foreman an. Zur dessen Installation wird zuerst das RPM Repository hinzugefügt, dann benötigte Gems installiert und dann der eigentliche Foreman:
yum install http://yum.theforeman.org/releases/latest/el6/x86_64/foreman-release.rpm yum update yum upgrade gem install highline gem install kafo yum install foreman-installer
Nützliche Links:
Wie implementiert man sichere Crypto
Rails Server Throwdown
Nginx+Passenger für den Puppet-Master
Anleitung von Puppetlabs für Apache+Passenger/Rack
Puma+Nginx 1
Puma+Nginx 2
Sicherer SSL Cipher Suite inklusive Perfect Forward Secrecy
Informationen über PFS (Perfect Forward Secrecy)
Installation einer PuppetDB unter CentOS 6.4
Hallo,
obwohl das HOWTO super verständlich geschrieben ist, ich habe hier ein Problem.
Beim: puma /usr/share/puppet/rack/puppetmasterd/config.ru erhalte ich folgenden Fehler:
Puma starting in single mode…
* Version 2.7.1, codename: Earl of Sandwich Partition
* Min threads: 0, max threads: 16
* Environment: development
! Unable to load application
/usr/local/rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require’: cannot load such file — puppet/util/command_line (LoadError)
from /usr/local/rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require’
from /usr/share/puppet/rack/puppetmasterd/config.ru:32:in `block in ‘
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize’
from /usr/share/puppet/rack/puppetmasterd/config.ru:in `new’
from /usr/share/puppet/rack/puppetmasterd/config.ru:in `’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/rack-1.5.2/lib/rack/builder.rb:49:in `eval’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/rack-1.5.2/lib/rack/builder.rb:49:in `new_from_string’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/rack-1.5.2/lib/rack/builder.rb:40:in `parse_file’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/puma-2.7.1/lib/puma/configuration.rb:93:in `app’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/puma-2.7.1/lib/puma/runner.rb:105:in `load_and_bind’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/puma-2.7.1/lib/puma/single.rb:73:in `run’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/puma-2.7.1/lib/puma/cli.rb:442:in `run’
from /usr/local/rvm/gems/ruby-2.0.0-p353/gems/puma-2.7.1/bin/puma:10:in `’
from /usr/local/rvm/gems/ruby-2.0.0-p353/bin/puma:23:in `load’
from /usr/local/rvm/gems/ruby-2.0.0-p353/bin/puma:23:in `’
from /usr/local/rvm/gems/ruby-2.0.0-p353/bin/ruby_executable_hooks:15:in `eval’
from /usr/local/rvm/gems/ruby-2.0.0-p353/bin/ruby_executable_hooks:15:in `’
Das System ist ein frisch installiertes CentOS 6.5 minimal mit sshd. Weiß hier jemand Rat?
Gruß tholie