Let’s Encrypt und Puppet

lets-encrypt-logoIch habe früher fast alle meine Zertifikate von CAcert bezogen. Ich habe sie regelmäßig aktualisiert und für das deployen habe ich ein Puppet Modul, dass die Zertifikate verteilt.

Nach und nach bin ich auf Let’s Encrypt Zertifikate umgestiegen. Da ein hoher Grad an Automatisierung bei Let’s Encrypt immer wieder propagiert wird dachte ich mir, dass sollte auch mit Puppet dann kein zu großes Problem sein. Hier die Lösung, die bei mir nun in Betrieb ist:

Als erstes habe ich das Puppet Modul bzed/letsencrypt installiert. Das Modul benötigt eine PuppetDB. Über exported resources  transportiert es die CSRs auf den puppetmaster, macht dort die gesamte Abwicklung und transferiert dann die Ergebnisse wieder zurück auf den Node. Das funktioniert auch sehr gut.

Auf dem Puppetmaster habe ich die Klasse eingebunden und einige wenige Einstellungen gesetzt (hiera). Bei dem Hook handelt sich m übrigen um einen letsencrypt.sh Hook:

---
classes:
  - letsencrypt

letsencrypt::challengetype: 'http-01'
letsencrypt::hook_source: 'puppet:///modules/helper/%{::fqdn}/le_hook.sh'

Auf den Nodes habe ich die Klasse eingebunden und die Domains definiert für die ein Zertifikat bezogen werden soll:

---
classes:
- letsencrypt

letsencrypt::domains:
- 'foo.example.net'
- 'bar.example.net'
- 'baz.example.net'

PL_logo_vertical_RGB_lgIn meinem recht simplen Szenario ist es so, dass ich einen Gate-Server habe, hinter dem sich alle anderen Maschinen „verstecken“. Dort läuft ein Apache Server als Proxy, der Anfragen über HTTP nach hinten weiterreicht. Die Konfiguration von Apache erfolgt ebenfalls über Puppet. Eine Authentifizierung über DNS für ACME klappt bei mir leider nicht, weswegen ich HTTP nehmen muss. Das habe ich so gelöst, dass ich für die Apache vhosts einfach über ProxyPassMatch den .well-known/acme-challenge/ auf einen Apache Vhost auf dem Puppetmaster weiterreiche. Auf dem Gate-Server sieht das für einen Vhost wie folgt aus:

apache::vhost:
  'proxy-foo.example.net':
    servername: 'foo.example.net'
    serveradmin: 'webmaster@example.net'
    port: '80'
    docroot: '/var/www/empty'
    proxy_dest: 'http://10.20.30.1'
    proxy_pass_match:
      -
        path: '^/.well-known/acme-challenge/(.*)$'
        url: 'http://10.20.30.2/$1'
        params:
          retry: '0'
    headers:
      - 'unset X-Powered-By'
    proxy_preserve_host: true

Auf dem Puppetmaster wiederum läuft ein Vhost, der einfach alle Domains als ServerAlias eingetragen hat.

Nun kommt noch der Hook für letsencrypt.sh ins Spiel den ich oben bereits erwähnt habe. Das Skript schreibt die ACME-Challenge in eine Textdatei in den DocRoot und löscht sie nach dem Erfolg wieder:

#!/bin/bash
 
#
# http-01 hook
#
 
CHALLENGEDIR="/var/www/example.net/letsencrypt"
 
done="no"
if [[ "$1" = "deploy_challenge" ]]; then
    echo "${4}" > "${CHALLENGEDIR}/${3}"
    chmod 644 "${CHALLENGEDIR}/${3}"
    done="yes"
fi
 
if [[ "$1" = "clean_challenge" ]]; then
    rm "${CHALLENGEDIR}/${3}"
    done="yes"
fi
 
if [[ "${1}" = "deploy_cert" ]]; then
    # do nothing for now
    done="yes"
fi
 
if [[ ! "${done}" = "yes" ]]; then
    echo Unkown hook "${1}"
    exit 1
fi
 
exit 0

Voila! Es braucht ein paar Durchläufe bis alles über die Puppetdb jeweils transportiert wurde, aber alles läuft vollautomatisch ab. Sehr cool!

Projekt: pregos files

Vor ein paar Jahren hab ich mal file delivery implementiert, dann aber nie weiter verfolgt. Jetzt habe ich das ganze noch einmal deutlich einfacher geskriptet.

pregos files

Die Features sind:

  • Dateiuploads laufen nach einer Zeitperiode ab
  • Downloadnamen werden automatisch generiert um nicht einfach geraten zu werden
  • Optional kann ein eigener, sprechender Downloadname angegeben werden
  • Optional können Downloads mit einem Passwort gesichert werden
  • Emailbenachrichtigung bei Download
  • Emailbenachrichtigung wenn eine Datei bald abläuft
  • Benutzerauthentifizierung für Dateiupload
  • Standard- und Admin Benutzerrollen
  • Adminbenutzer können andere Benutzer verwalten und sehen eine Liste aller verfügbarer Dateien

Den Quelltext gibt es auf Github.

Clusterssh

Viele Admins stehen häufig vor der Aufgabe einen Befehl auf vielen Maschinen gleichzeitig auszuführen. Eine Möglichkeit das zu tun ist mit dem Tool clusterssh. Es lässt sich meist direkt aus den Paketquellen installieren:

sudo apt-get install clusterssh

Anschließend kann man sich mit dem folgenden Befehl auf mehreren Servern verbinden und dort gleichzeitig Befehle ausführen:

cssh server1 user@server2 server3

In der Datei ~/.clusterssh/config kann man sich verschiedene Cluster definieren. Dafür wird eine Zeile benötigt die sagt was Cluster sind, und dann jeweils eine weitere Zeile die die Cluster definiert. Beispiel:

clusters = physical webserver
physical = phys1 phys2 user@phys3
webserver = user1@web01 user2@web02 user3@web03, user1@web04 web05

Anschließend kann man sich einfach mit dem folgenden Befehl mit allen Webservern verbinden:

cssh webserver

Häufig auszuführende Kommandos kann man sich auch im Menü hinterlegen. Dafür zuständig ist die Datei ~/.csshrc_send_menu. Sie ist im XML-Format aufgebaut und kann zum Beispiel so aussehen:

<?xml version="1.0"?>
<send_menu>
  <menu title="htop">
    <command>htop%n</command>
  </menu>
  <menu title="autoremove">
    <command>sudo apt-get -y autoremove%n</command>
  </menu>
  <menu title="updates">
          <command>apt-get update &amp;&amp; apt-get dist-upgrade &amp;&amp; exit%n</command>
  </menu>
  <menu title="firewall restart">
          <command>sudo /root/skripte/firewall.sh%n</command>
  </menu>
</send_menu>

Damit das ganze funktioniert wird XML::Simple benötigt:

sudo apt-get install libxml-simple-perl

Oft benutze ich persönlich auf den Shortcut Alt+r zum Fenster neu anordnen. Ruft man auf allen Servern einen Befehl auf und schließt die Fenster auf denen der Befehl erfolgreich bearbeitet wurde, dann hat man irgendwann einen Fleckenteppich auf dem Bildschirm. Mit Alt+r wird der wieder neu angeordnet.

Update 01.02.2016: Danke @Aiko für den Kommentar, ich habe das oben in das Beispiel mit eingepflegt.

Snippets: 07.01.2016

  • UIDs nochmal hervorgekramt: Reserviert ist per Definition nur UID=0 für root. Quasi überall ist UID=65534 der Nutzer nobody. Es hat sich etabliert, dass die UIDs 1-99 von Systembenutzern für Dienste ohne Login belegt ist. Verschiedene Distributionen starten mit lokalen Benutzeraccounts an verschiedenen Stellen, RedHat zum Beispiel bei UID=500, Debian erst bei UID=1000.
  • In Gnome 3 hatte ich das Problem, dass in „Dateien“ die Entf-Taste nicht ging um Dateien und Ordner in den Papierkorb zu verschieben. Ich musste immer markieren, rechtsklick mit der Maus und dann sagen „In den Papierkorb verschieben“. Lösung ist die .config/nautilus/accels zu öffnen und dort die folgende Zeile suchen:
    ; (gtk_accel_path "/DirViewActions/Trash" "Delete")

    einkommentieren und das <Primary> löschen so dass sie so aussieht:

    (gtk_accel_path "/DirViewActions/Trash" "Delete")
  • Ich suche oft noch mit aptitude search foo* | grep „^i“. Schneller ist allerdings dpkg -l foo* | grep ii und die Pipe + grep kann ich mir sparen mit dpkg –get-selections foo*