| Zeile 3: |
Zeile 3: |
| | cert_client: Rechner, auf den die Zertifikate übertragen werden. | | cert_client: Rechner, auf den die Zertifikate übertragen werden. |
| | | | |
| − | Vorbereitungen für Cert_master:
| + | ==cert_master== |
| | + | |
| | + | ===Software besorgen/installieren:=== |
| | | | |
| | apache, openssl installieren | | apache, openssl installieren |
| | | | |
| − | Dehydrated besorgen: | + | Dehydrated: |
| | | | |
| − | git clone https://github.com/lukas2511/dehydrated | + | <source lang=bash inline>git clone https://github.com/lukas2511/dehydrated</source> |
| | | | |
| | an passende stelle kopieren, /etc/dehydrated erstellen | | an passende stelle kopieren, /etc/dehydrated erstellen |
| | | | |
| | + | <source lang=bash> |
| | cp dehydrated/dehydrated /usr/local/sbin/dehydrated | | cp dehydrated/dehydrated /usr/local/sbin/dehydrated |
| | + | mkdir -p /etc/dehydrated |
| | + | </source> |
| | + | |
| | + | ===Apache konfigurieren=== |
| | + | |
| | + | '''/etc/apache2/sites-available/letsencrypt.conf''':Apache muss so konfiguriert werden, dass $domain/.well-known/acme-challenge/ auf das richtige Verzeichnis zeigt. Somit kann die Acme challenge erfolgreich durchgeführt werden. |
| | + | <source lang=bash> |
| | + | Alias /.well-known/acme-challenge/ /var/www/dehydrated/ |
| | + | <Directory "/var/www/dehydrated/"> |
| | + | Options None |
| | + | AllowOverride None |
| | + | Require all granted |
| | + | ForceType text/plain |
| | + | Options -Indexes |
| | + | </Directory> |
| | + | </source> |
| | + | Dann noch die config aktivieren und apache neu laden: |
| | + | <source lang=bash> |
| | + | a2enconf letsencrypt |
| | + | apachectl restart |
| | + | </source> |
| | + | |
| | + | ===Dehydrated konfigurieren:=== |
| | | | |
| − | folgende Dateien erstellen: | + | folgende Dateien unter /etc/dehydrated erstellen: |
| − | config:
| |
| | | | |
| | + | '''config''': Hier werden die Optionen von dehydrated eingestellt. |
| | <source lang=bash> | | <source lang=bash> |
| | ######################################################## | | ######################################################## |
| Zeile 125: |
Zeile 151: |
| | # renewal (default: yes) | | # renewal (default: yes) |
| | #PRIVATE_KEY_RENEW="yes" | | #PRIVATE_KEY_RENEW="yes" |
| − |
| |
| − | # Create an extra private key for rollover (default: no)
| |
| − | #PRIVATE_KEY_ROLLOVER="no"
| |
| − |
| |
| − | # Which public key algorithm should be used? Supported: rsa, prime256v1 and
| |
| − | # secp384r1
| |
| − | #KEY_ALGO=rsa
| |
| − |
| |
| − | # E-mail to use during the registration (default: )
| |
| − | CONTACT_EMAIL=admin@lists.freifunk-mwu.de
| |
| − |
| |
| − | # Lockfile location, to prevent concurrent access (default: $BASEDIR/lock)
| |
| − | #LOCKFILE="${BASEDIR}/lock"
| |
| | | | |
| | # Option to add CSR-flag indicating OCSP stapling to be mandatory (default: | | # Option to add CSR-flag indicating OCSP stapling to be mandatory (default: |
| Zeile 144: |
Zeile 157: |
| | </source> | | </source> |
| | | | |
| − | hook.sh: | + | '''hook.sh''': Funktionen, die ausgeführt werden, wenn verschiedene Aktionen durchgeführt wurden. Wir verwenden deploy_cert() für neue und verlängerte Zertifikate. Dort werden lokale (zuckerwatte) Zertifikate für den apache kopiert, Berechtigungen angepasst und apache neugestartet. Und es werden Zertifikate nach /home/cert kopiert, dieses ist das Transferverzeichnis für andere Hosts. Am Ende werden noch alte Zertifikate archiviert (dehydrated -gc). |
| | <source lang=bash> | | <source lang=bash> |
| | #!/usr/bin/env bash | | #!/usr/bin/env bash |
| Zeile 200: |
Zeile 213: |
| | #fi | | #fi |
| | | | |
| − | # Copy certs to apache, fix permissions | + | echo "Renewed/Created: $DOMAIN at `date -d @$TIMESTAMP`" >&2 |
| − | mkdir -p /etc/apache2/ssl/$DOMAIN/ | + | |
| − | cp $KEYFILE /etc/apache2/ssl/$DOMAIN/
| + | # Copy local Certificates |
| − | cp $CERTFILE /etc/apache2/ssl/$DOMAIN/
| + | if [[ "$DOMAIN" == "zuckerwatte.freifunk-mwu.de" ]] |
| − | cp $CHAINFILE /etc/apache2/ssl/$DOMAIN/
| + | then |
| | + | rm -r /etc/apache2/ssl/* |
| | + | mkdir -p /etc/apache2/ssl/$DOMAIN/ |
| | + | cp $KEYFILE /etc/apache2/ssl/$DOMAIN/ |
| | + | cp $CERTFILE /etc/apache2/ssl/$DOMAIN/ |
| | + | cp $CHAINFILE /etc/apache2/ssl/$DOMAIN/ |
| | + | fi |
| | + | |
| | | | |
| | chown www-data.www-data -R /etc/apache2/ssl/ | | chown www-data.www-data -R /etc/apache2/ssl/ |
| | chmod -R 0700 /etc/apache2/ssl/ | | chmod -R 0700 /etc/apache2/ssl/ |
| | apachectl graceful | | apachectl graceful |
| − |
| + | |
| | # Copy certs to cert home dir | | # Copy certs to cert home dir |
| − | mkdir -p /home/cert/$DOMAIN/ | + | mkdir -p /home/cert/$DOMAIN/ |
| − |
| + | |
| | cp $KEYFILE /home/cert/$DOMAIN/ | | cp $KEYFILE /home/cert/$DOMAIN/ |
| | cp $CERTFILE /home/cert/$DOMAIN/ | | cp $CERTFILE /home/cert/$DOMAIN/ |
| | cp $CHAINFILE /home/cert/$DOMAIN/ | | cp $CHAINFILE /home/cert/$DOMAIN/ |
| | | | |
| − | chmod 500 $(find /home/cert -mindepth 1 -type d ) | + | chmod 750 $(find /home/cert -mindepth 1 -type d ) |
| − | chmod 400 $(find /home/cert -mindepth 1 -type f ) | + | chmod 740 $(find /home/cert -mindepth 1 -type f ) |
| − | chown cert.cert -R /home/cert/* | + | chown root.cert -R /home/cert/* |
| | + | |
| | + | # cleanup unused cert files |
| | + | dehydrated -gc |
| | + | |
| | } | | } |
| | function unchanged_cert { | | function unchanged_cert { |
| Zeile 238: |
Zeile 262: |
| | # - CHAINFILE | | # - CHAINFILE |
| | # The path of the file containing the intermediate certificate(s). | | # The path of the file containing the intermediate certificate(s). |
| | + | |
| | + | # cleanup unused cert files |
| | + | dehydrated -gc |
| | + | |
| | } | | } |
| | HANDLER=$1; shift; $HANDLER $@ | | HANDLER=$1; shift; $HANDLER $@ |
| | </source> | | </source> |
| | | | |
| − | domains.txt: | + | '''domains.txt''': Hier werden die Domains (CNs) für die Zertifikate definiert. Der erste Eintrag ist dabei der CN = Common Name, jeder weitere wird als SAN = Subject Alternative Name eingetragen. Von diesen sind weitere 99 möglich (insgesamt also 100 Namen). Wir haben für jeden Host/jedes Gateway eigene Zertifikate um eine Angriffsfläche im Falle eines Zertifikatsverlusts zu minimieren. |
| | <source lang=bash> | | <source lang=bash> |
| | #Hosts | | #Hosts |
| | + | #Zuckerwatte |
| | zuckerwatte.freifunk-mwu.de dudel.freifunk-mwu.de einzugsgebiet.freifunk-mwu.de pad.freifunk-mwu.de rtfm.freifunk-mwu.de wiki.freifunk-mwu.de freifunk-mwu.de api.freifunk-mainz.de blog.freifunk-mainz.de einzugsgebiet.freifunk-mainz.de event.freifunk-mainz.de media.freifunk-mainz.de mitglieder.freifunk-mainz.de pad.freifunk-mainz.de wiki.freifunk-mainz.de www.freifunk-mainz.de freifunk-mainz.de mainz.freifunk.net api.wiesbaden.freifunk.net einzugsgebiet.wiesbaden.freifunk.net media.wiesbaden.freifunk.net photos.wiesbaden.freifunk.net www.wiesbaden.freifunk.net wiesbaden.freifunk.net | | zuckerwatte.freifunk-mwu.de dudel.freifunk-mwu.de einzugsgebiet.freifunk-mwu.de pad.freifunk-mwu.de rtfm.freifunk-mwu.de wiki.freifunk-mwu.de freifunk-mwu.de api.freifunk-mainz.de blog.freifunk-mainz.de einzugsgebiet.freifunk-mainz.de event.freifunk-mainz.de media.freifunk-mainz.de mitglieder.freifunk-mainz.de pad.freifunk-mainz.de wiki.freifunk-mainz.de www.freifunk-mainz.de freifunk-mainz.de mainz.freifunk.net api.wiesbaden.freifunk.net einzugsgebiet.wiesbaden.freifunk.net media.wiesbaden.freifunk.net photos.wiesbaden.freifunk.net www.wiesbaden.freifunk.net wiesbaden.freifunk.net |
| | + | #Glückskeks |
| | glueckskeks.freifunk-mwu.de autodiscover.freifunk-mwu.de autodiscover.freifunk-mainz.de autodiscover.freifunk-wiesbaden.de lists.freifunk-mwu.de mailadmin.freifunk-mwu.de webmail.freifunk-mwu.de mail.freifunk-mwu.de | | glueckskeks.freifunk-mwu.de autodiscover.freifunk-mwu.de autodiscover.freifunk-mainz.de autodiscover.freifunk-wiesbaden.de lists.freifunk-mwu.de mailadmin.freifunk-mwu.de webmail.freifunk-mwu.de mail.freifunk-mwu.de |
| | + | #Suesskartoffel |
| | suesskartoffel.freifunk-mwu.de map.freifunk-mwu.de map.freifunk-mainz.de map.wiesbaden.freifunk.net map.ffmwu.org map.ffmz.org map.ffwi.org | | suesskartoffel.freifunk-mwu.de map.freifunk-mwu.de map.freifunk-mainz.de map.wiesbaden.freifunk.net map.ffmwu.org map.ffmz.org map.ffwi.org |
| | | | |
| | #Gates | | #Gates |
| | + | #Spinat |
| | spinat.freifunk-mwu.de firmware.freifunk-mwu.de spinat.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net spinat.ffmwu.org firmware.ffmwu.org spinat.ffmz.org firmware.ffmz.org spinat.ffwi.org firmware.ffwi.org | | spinat.freifunk-mwu.de firmware.freifunk-mwu.de spinat.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net spinat.ffmwu.org firmware.ffmwu.org spinat.ffmz.org firmware.ffmz.org spinat.ffwi.org firmware.ffwi.org |
| | + | #Lotuswurzel |
| | lotuswurzel.freifunk-mwu.de firmware.freifunk-mwu.de lotuswurzel.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net lotuswurzel.ffmwu.org firmware.ffmwu.org lotuswurzel.ffmz.org firmware.ffmz.org ffmz.org lotuswurzel.ffwi.org firmware.ffwi.org | | lotuswurzel.freifunk-mwu.de firmware.freifunk-mwu.de lotuswurzel.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net lotuswurzel.ffmwu.org firmware.ffmwu.org lotuswurzel.ffmz.org firmware.ffmz.org ffmz.org lotuswurzel.ffwi.org firmware.ffwi.org |
| | + | #Wasserfloh |
| | wasserfloh.freifunk-mwu.de firmware.freifunk-mwu.de wasserfloh.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net wasserfloh.ffmwu.org firmware.ffmwu.org wasserfloh.ffmz.org firmware.ffmz.org wasserfloh.ffwi.org firmware.ffwi.org | | wasserfloh.freifunk-mwu.de firmware.freifunk-mwu.de wasserfloh.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net wasserfloh.ffmwu.org firmware.ffmwu.org wasserfloh.ffmz.org firmware.ffmz.org wasserfloh.ffwi.org firmware.ffwi.org |
| | + | #Ingwer |
| | ingwer.freifunk-mwu.de firmware.freifunk-mwu.de ingwer.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net ingwer.ffmwu.org firmware.ffmwu.org ingwer.ffmz.org firmware.ffmz.org ingwer.ffwi.org firmware.ffwi.org | | ingwer.freifunk-mwu.de firmware.freifunk-mwu.de ingwer.freifunk-mainz.de firmware.freifunk-mainz.de firmware.wiesbaden.freifunk.net ingwer.ffmwu.org firmware.ffmwu.org ingwer.ffmz.org firmware.ffmz.org ingwer.ffwi.org firmware.ffwi.org |
| | + | </source> |
| | + | |
| | + | ===Transferbenutzer anlegen=== |
| | + | |
| | + | Dieser Benutzer wird verwendet als Transferbenutzer zwischen cert_master und cert_client |
| | + | |
| | + | <source lang=bash inline> adduser --home /home/cert --disabled-login -gecos "" cert</source> |
| | + | |
| | + | ===SSH konfigurieren=== |
| | + | |
| | + | '''/etc/ssh/sshd_config''': Hier wird /etc/ssh/authorized_keys_local als zusätzliche Quelle für erlaubte public keys hinzugefügt. |
| | + | <source lang=bash> |
| | + | AuthorizedKeysFile %h/.ssh/authorized_keys /etc/ssh/authorized_keys_local |
| | + | </source> |
| | + | |
| | + | '''/etc/ssh/sshd_config''': Hier wird ein chroot jail für den Zertifikatsuser eingerichtet, so dass ein geleakter private key kein manipulieren des cert_master zulässt. Die Permissions von /home/cert (wie gesetzt in hooks.sh) verhindern ein überschreiben der Zertifikate, internal-sftp erlaubt nur sftp über die Verbindung. |
| | + | <source lang=bash> |
| | + | Match User cert |
| | + | ChrootDirectory /home/cert/ |
| | + | ForceCommand internal-sftp |
| | + | AllowTcpForwarding no |
| | + | PermitTunnel no |
| | + | X11Forwarding no |
| | + | </source> |
| | + | |
| | + | '''/etc/ssh/authorized_keys_local''': Hier kommen alle public keys von hosts rein, die Zertifikate abrufen wollen. |
| | + | |
| | + | ===Cron=== |
| | + | |
| | + | Das script in cron.daily läuft einmal täglich (wann wird bestimmt von Debian). Dann werden neue Zertifikate abgerufen und alte erneuert. |
| | + | |
| | + | '''/etc/cron.daily/ssl_certs''': dehydrated wird aufgerufen und stdout wird verworfen. Stderr wird über cron per mail weiter gegeben. |
| | + | <source lang=bash> |
| | + | #!/bin/bash |
| | + | |
| | + | dehydrated -c -g -f /etc/dehydrated/config > /dev/null |
| | + | </source> |
| | + | |
| | + | ==cert_client== |
| | + | |
| | + | ===apache reverse proxy konfigurieren=== |
| | + | |
| | + | '''/etc/apache2/conf-available/letsencrypt.conf''':Da die challenges von letsencrypt bei dem cert_client enden (http://$domain/.well-known/acme-challenge/), aber auf dem cert_master terminiert werden sollen, richten wir einen reverse proxy ein. |
| | + | <source lang=bash> |
| | + | SSLProxyEngine On |
| | + | ProxyPassMatch ^/(.well-known/acme-challenge/.*) https://freifunk-mwu.de:443/$1 |
| | + | ProxyPassReverse / https://freifunk-mwu.de:443/ |
| | + | </source> |
| | + | Jetzt noch config aktivieren und apache neustarten: |
| | + | <source lang=bash> |
| | + | a2enconf letsencrypt |
| | + | apachectl restart |
| | + | </source> |
| | + | Es ist noch notwendig ein paar weitere Apache module zu aktivieren <source lang=bash inline>a2enmod $mod</source>, welche ist der Fehlermeldung beim neu starten zu entnehmen. |
| | + | |
| | + | ===SSH konfigurieren=== |
| | + | |
| | + | '''/root/.ssh/config''':Cron läuft als root, deswegen brauchen wir die config hier. $Hostname gegen den cert_client ersetzen, $cert_master gegen hostname cert_master. |
| | + | <source lang=bash> |
| | + | Host $cert_master |
| | + | User cert |
| | + | Hostname $cert_master.freifunk-mwu.de |
| | + | Port 23 |
| | + | IdentityFile /home/admin/.ssh/$HOSTNAME_rsa |
| | + | </source> |
| | + | |
| | + | '''/home/admin/.ssh/$HOSTNAME_rsa.pub:''' Den public key auf dem cert_master in die zusätzliche authorized_keys Datei eintragen. |
| | + | |
| | + | <source lang=bash inline>sftp $cert_master</source> muss ohne Eingabe funktionieren. |
| | + | |
| | + | ===Cron=== |
| | + | '''/etc/cron.daily/ssl_certs''': Hier wird das Zertifikat des Hosts $cert_client abgerufen. Dann werden Permissions angepasst und Dienste neu gestartet. Andere Dienste erfordern hier Anpassung (z.B. mail). |
| | + | <source lang=bash> |
| | + | #!/bin/sh |
| | + | |
| | + | DOMAINS="$cert_client.freifunk-mwu.de" |
| | + | |
| | + | rm /etc/apache2/ssl/* -r |
| | + | for DOMAIN in $DOMAINS; |
| | + | do |
| | + | mkdir -p /etc/apache2/ssl/$DOMAIN |
| | + | sftp -q -r zuckerwatte:/$DOMAIN /etc/apache2/ssl/ > /dev/null |
| | + | |
| | + | chmod 0550 /etc/apache2/ssl/$DOMAIN |
| | + | chmod 0440 /etc/apache2/ssl/$DOMAIN/* |
| | + | done |
| | + | |
| | + | chown -R www-data.admin /etc/apache2/ssl/ |
| | + | apache2ctl restart |
| | </source> | | </source> |