Let’s Encrypt Zertifikat für das Heim-Netz

Mit eini­gen Vor­keh­run­gen las­sen sich Let’s-Encrypt-Zertifikate auch für inter­ne Net­ze nut­zen, die nicht vom Inter­net erreich­bar sind.

Zertifikate von Let’s Encrypt

Let’s Encrypt [1] bie­tet schon seit eini­gen Jah­ren kos­ten­lo­se SSL-Zer­ti­fi­ka­te für ein­zel­ne Domains an. Seit kur­zem wer­den auch Wild­card-Zer­ti­fi­ka­te aus­ge­stellt, die für alle Sub­do­mains einer Domain gül­tig sind. Wird ein sol­ches Zer­ti­fi­kat zum Bei­spiel für *.home​.kunz​.de aus­ge­stellt, gilt es auch für alle Sub­do­mains, also zum Bei­spiel auch für hinz​.home​.kunz​.de.

Damit lässt sich rela­tiv ein­fach ein Zer­ti­fi­kat gene­rie­ren, dass für alle Ser­ver im Heim-Netz gül­tig ist und nicht - wie ein selbst­si­gnier­tes Zer­ti­fi­kat - von Web-Brow­sern als unsi­cher mar­kiert wird. Die Let’s-Encrypt-Zertifikate sind aller­dings nur jeweils 60 Tage gül­tig. Des­we­gen macht es Sinn, die Erneue­rung des Home-Zer­ti­fi­kats auto­ma­tisch ablau­fen zu las­sen.

Überprüfungs-Prozeduren (Challenges)

Wäh­rend der Bean­tra­gung oder Erneue­rung der Zer­ti­fi­ka­te muss der Let’s Encrypt Ser­ver über­prü­fen, dass  die Domain dem Bean­tra­ger gehört oder von ihm admi­nis­triert wird. Dafür gibt es meh­re­re Mög­lich­kei­ten, unter ande­rem die web­root- und die DNS-Pro­ze­dur.

Die web­root Pro­ze­dur erwar­tet eine Sei­te mit vor­ge­ge­be­nem Inhalt im Wur­zel-Ver­zeich­nis des Web­ser­vers. Das lässt sich zwar sehr leicht auto­ma­ti­sie­ren, aber zur Über­prü­fung muss der Ser­ver vom Inter­net aus erreich­barr sein, was im Heim­netz Port­wei­ter­lei­tun­gen auf dem Inter­net-Rou­ter erfor­der­lich macht.

Bei der DNS-Pro­ze­dur muss beim DNS-Ser­ver der Zone ein TXT-Record mit vor­ge­ge­be­nem Namen und Inhalt ein­ge­stellt wer­den. Die­ser Ein­trag wird bei der Bean­tra­gung vom Let’s Encrypt Ser­ver abge­ru­fen. Dafür muss die Domain selbst nicht erreich­bar sein, was die Nut­zung für Domains in pri­va­ten Net­zen sehr ver­ein­facht. Für Wild­card-Zer­ti­fi­ka­te ist die DNS-Chal­len­ge die ein­zig mög­li­che Über­prü­fungs-Pro­ze­dur.

Let’s Encrypt certbot installieren

Zunächst muss auf einem Ser­ver im Heim­netz das Let’s Encrypt cert­bot Paket instal­liert wer­den. Bei mir ist die­ser Ser­ver ein stän­dig lau­fen­der Raspber­ry­PI mit dem Debi­an-Stretch-basier­ten NAS-Sys­tem open­me­diavault 4 (omv).

Bei Debi­an Stretch befin­det sich das cert­bot-Paket im stretch-back­ports-Repo­sito­ry, das bei omv 4 bereits in den Paket­quel­len ein­ge­tra­gen ist.

$ sudo apt-get install certbot -t stretch-backports

Das Zertifikat manuell beantragen

Jetzt kön­nen wir cert­bot benut­zen, um das Zer­ti­fi­kat zu bean­tra­gen. Der certonly Schal­ter bewirkt, dass das Zer­ti­fi­kat nur abge­ru­fen, aber nicht instal­liert wird. Wild­card-Zer­ti­fi­ka­te wer­den nur vom acme-v02 Ser­ver aus­ge­stellt, der mit dem ser­ver Schal­ter ange­ge­ben wer­den muss. Unter -d wird die Wild­card-Domain ange­ge­ben, für die das Zer­ti­fi­kat aus­ge­stellt wer­den soll.

Da die ein­zi­ge unter­stütz­te Prü­fungs­art die DNS-Chal­len­ge ist, muss sie mit pre­fer­red-chal­len­ges dns aus­ge­wählt wer­den. Der manu­al Schal­ter gibt an, dass der TXT-Record manu­ell ein­ge­tra­gen wird. Zur Auto­ma­ti­sie­rung spä­ter mehr.

# certbot certonly --server https://acme-v02.api.letsencrypt.org/directory -d *.home.kunz.de --email webmaster@kunz.de --preferred-challenges dns --manual
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for home.kunz.de

-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: y

-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.home.kunz.de with the following value:

dhfjknfhuioOHoihHohoioioih568_nvihUGüj87ui87

Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue

Nach­dem man sein Ein­ver­ständ­nis mit der Auf­zeich­nung sei­ner IP-Adres­se erklärt hat, druckt der cert­bot Namen und Inhalt des TXT-Records aus, der nun beim zustän­di­gen DNS-Zonen­ver­wal­ter - bei mir FreeDNS - ein­ge­tra­gen wer­den muss. Dazu öff­nen wir ein zwei­tes Ter­mi­nal.

Die Heimnetz-Domain

Als Heim­netz-Domain wird eine Sub­do­main einer offi­zi­el­len Domain benutzt. Sie wird als Sub­do­main beim glei­chen Pro­vi­der ein­ge­tra­gen, der auch für die Basis-Domain ver­ant­wort­lich ist.

Wenn man vor­hat, auch vom Inter­net aus auf Ser­ver in der Heim-Domain zuzu­grei­fen, muss man auf die Diens­te eines dynDNS-Pro­vi­ders zurück­grei­fen. Ein­zel­hei­ten beschreibt der Arti­kel DynDNS für eine eige­ne Domain ein­rich­ten.

Im fol­gen­den arbei­ten wir mit dem DynDNS-Pro­vi­der FreeDNS, auf den die Namens­auf­lö­sung bei mei­nem Domain-Pro­vi­der dele­giert wur­de.

Den DNS TXT-Record erzeugen

Nach Anmel­dung bei FreeDNS wäh­len wir aus dem Menü links den Ein­trag Dyna­mic DNS aus und kli­cken im Titel der Tabel­le der DNS-Records auf Add. Als Typ wäh­len wir TXT aus. Die Domain bleibt bei home​.kunz​.de. Unter Sub­do­main wird der gefor­der­te Chal­len­ge-Name und unter Desti­na­ti­on der Text in dop­pel­ten Anfüh­rungs­zei­chen ein­ge­tra­gen.

Nach dem Kli­cken auf Save che­cken wir per nslook­up, ob der TXT-Record schon ver­füg­bar ist, Das kann je nach TTL eini­ge Zeit dau­ern. Bei FreeDNS steht die TTL fest auf 60 Sekun­den, so dass spä­tes­tens nach etwa ein bis zwei Minu­ten der TXT-Record abruf­bar sein soll­te.

$ nslookup
> set type=TXT
> _acme-challenge.home.kunz.de
Server: 192.168.1.1
Address: 192.168.1.1#53

Non-authoritative answer:
_acme-challenge.home.kunz.de text = "dhfjknfhuioOHoihHohoioioih568_nvihUGüj87ui87"

Weiter mit certbot

Jetzt kann im ers­ten Ter­mi­nal der cert­bot mit Return fort­ge­setzt wer­den:

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/home.kunz.de/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/home.kunz.de/privkey.pem
Your cert will expire on 2018-09-30. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

#

Geht alles gut, lie­gen am Ende Schlüs­sel­da­tei und Zer­ti­fi­kat unter /etc/letsencrypt/live/home.kunz.de und kön­nen direkt ver­wen­det wer­den.

Das Zertifikat in omv nutzen

Um das Zer­ti­fi­kat für open­me­diavault ver­füg­bar zu machen, wählt man im omv-Menü Zer­ti­fi­ka­te aus, klickt auf den SSL Tab und wählt unter Hin­zu­fü­gen den Ein­trag Impor­tie­ren aus. Unter Pri­va­ter Schlüs­sel wird der Inhalt von privkey.pem und unter Zer­ti­fi­kat der Inhalt von fullchain.pem ein­ge­tra­gen. In’s Kom­men­tar­feld gehört eine mög­lichst ein­deu­ti­ger Text, um das Zer­ti­fi­kat spä­ter iden­ti­fi­zie­ren zu kön­nen.

Zuletzt wählt man unter All­ge­mei­ne Ein­stel­lun­gen bei Siche­re Ver­bin­dung das neue Zer­ti­fi­kat aus und sichert die Ein­stel­lun­gen.

Ab jetzt soll­te der Brow­ser die omv-Sei­te als Sicher mar­kie­ren, wenn sie mit dem voll­stän­di­gen Namen, also zum Bei­spiel mit omv​.home​.kunz​.de,  auf­ge­ru­fen wird.

Die­ses Zer­ti­fi­kat kön­nen alle Ser­ver mit einer Sub­do­main unter home​.kunz​.de  benut­zen; sie wer­den dann eben­falls als Sicher ein­ge­stuft.

Automatisierung der DNS-Challenge

Das Über­prü­fungs­ver­fah­ren der DNS-Chal­len­ge kann mit einem Script auto­ma­ti­siert wer­den. Der manu­al-auth-hook [2.1] wird auf­ge­ru­fen, bevor die Über­prü­fung der Chal­len­ge statt­fin­det. In die­sem Script muss der gefor­der­te TXT-Record beim DNS-Pro­vi­der erzeugt wer­den.

Für eini­ge, vor­wie­gend ame­ri­ka­ni­sche DNS-Pro­vi­der exis­tie­ren vor­de­fi­nier­te auth-Scripts [2.2]. Für alle ande­ren muss man das Script selbst erzeu­gen. Die nöti­gen Wer­te wie Name und Inhalt des TXT-Records wer­den vom cert­bot als Umge­bungs­va­ria­blen über­ge­ben [2.1]. Uns inter­es­siert im Moment ledig­lich die Varia­ble CERTBOT_VALIDATION, in der der erfor­der­li­che Inhalt des TXT-Records über­ge­ben wird.

Bei FreeDNS [3] kann der Inhalt eines bestehen­den TXT-Records mit fol­gen­dem CURL-Kom­man­do geän­dert wer­den:

curl -b "dns_cookie=XXXXXXXXXX" -d "type=TXT" -d "subdomain=_acme-challenge" -d "domain_id=0000" -d "data_id=0000" -d "address=%22some_text%22" https://freedns.afraid.org/subdomain/save.php?step=2

Die Varia­blen data_id, domain_id und dns_cookie müs­sen aus der FreeDNS Web-Sei­te abge­le­sen wer­den:

  • Die data_id fin­det man unter dem Menu­ein­trag Sub­do­mains im Link zum edi­tie­ren des TXT-Records.
  • Die domain_id steckt auf der glei­chen Sei­te im add Link hin­ter der Basis-Domain.
  • Den Inhalt des DNS-Coo­kies kann man aus dem dns_cookie für freedns​.afraid​.org able­sen
    (Bei Chro­me: chrome://settings/cookies/detail?site=freedns.afraid.org).

Hat man alle Anga­ben zusam­men, kann man die Funk­ti­on zunächst auf der Kom­man­do­zei­le prü­fen. Im Erfolgs­fal­le erzeugt curl dabei kei­ne Aus­ga­be, son­dern kehrt Kom­men­tar­los zum Prompt zurück. Mit nslook­up kön­nen wir nach ein bis zwei Minu­ten prü­fen, ob der TXT-Record auch pro­pa­giert wird:

# nslookup -type=TXT _acme-challenge.home.kunz.de
Server: 192.168.2.1
Address: 192.168.2.1#53

Non-authoritative answer:
_acme-challenge.home.kunz.de text = "some_text"

Das curl Koman­do ste­cken wir nun in das Script freedns​-txt​.sh, dass der cert­bot dann als manu­al-auth-hook benut­zen kann:

#!/bin/bash
#
dns_cookie="xxxxxxxxxxxx"
domain_id="0000"
data_id="0000"
ttl=60
#
curl -S -b "dns_cookie=$dns_cookie" -d "type=TXT" -d "subdomain=_acme-challenge" -d "domain_id=$domain_id" -d "data_id=$data_id" -d "address=%22$CERTBOT_VALIDATION%22" https://freedns.afraid.org/subdomain/save.php?step=2
sleep $ttl

Der Schal­ter -S (oder --silent) bewirkt, dass curl kei­ne Fort­schritts­an­zei­ge, wohl aber Feh­ler­nach­rich­ten aus­gibt. Am Ende war­tet das Script, bis die TTL des (alten) DNS-Ein­trags abge­lau­fen ist, was bei FreeDNS nach 60 Sekun­den geschieht.

Automatische Zertifikats-Erneuerung

Das renew-Kom­man­do des cert­bot wird für einen Test mit dem Pfad zu obi­gem Script ergänzt und mit --dry-run getes­tet:

# certbot renew --manual-auth-hook=/root/freedns-txt.sh --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/home.kunz.de.conf
-------------------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator manual, Installer None
Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for home.kunz.de

Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/home.kunz.de/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/home.kunz.de/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
-------------------------------------------------------------------------------

Wenn alles wie hier funk­tio­niert, kann die­ses Kom­man­do nun in die geplan­ten Auf­ga­ben des omv ein­ge­tra­gen wer­den, damit täg­lich über­prüft wird, ob das  Zer­ti­fi­kat erneu­ert wer­den muss.

Die Ver­tei­lung und Instal­la­ti­on des Zer­ti­fi­kats kann man eben­falls auto­ma­ti­sie­ren. Mit dem deploy-hook kann man ein Shell-Script ange­ben, dass nach einer erfolg­rei­chen Zer­ti­fi­kats­er­neue­rung auf­ge­ru­fen wird. Da mein pri­va­ter Ser­ver-Park aber noch über­schau­bar ist, ver­zich­te ich im Moment dar­auf.

Fazit

Mit einem Let’s Encrypt Zer­ti­fi­kat las­sen sich mit wenig Auf­wand auch Ser­ver absi­chern, die nicht vom Inter­net erreich­bar sind. Die Zer­ti­fi­kats-Erneue­rung lässt sich auto­ma­ti­sie­ren. Damit soll­ten auch im Heim­netz die Zei­ten unver­schlüs­sel­ter Über­tra­gun­gen vor­bei sein.

Nachtrag: crontab und system trigger

Das Debi­an-Paket cert­bot ent­hält schon sowohl einen crontab-Job als auch einen Sys­tem Trig­ger, die zwei mal täg­lich ver­su­chen, das Zer­ti­fi­kat zu erneu­ern. In mei­nem Fal­le läuft das schief, weil cert­bot ledig­lich mit

certbot renew -q

auf­ge­ru­fen wird. Wegen des feh­len­den manu­al-auth-hook schei­tert die­ser Ver­such immer mit einer Feh­ler­mel­dung in /var/log/letsencrypt/letsencrypt.log.

Man kann jetzt ent­wder den Auf­ruf von cert­bot im Ser­vice cert­bot und im crontab ändern, oder bei­de stil­le­gen und wei­ter­hin den crontab-Ein­trag im omv benut­zen.

Ich habe mich für letz­te­res ent­schie­den, weil dann alle cron-Jobs an einer Stel­le über­sicht­lich über die omv Web-Ober­flä­che zu ver­wal­ten sind.

Um den crontab-Ein­trag zu ent­fer­nen, löscht man ein­fach die Datei /etc/cron.d/certbot. Ser­vice und Trig­ger wer­den mit fol­gen­den Kom­man­dos ent­fernt:

systemctl stop certbot
systemctl stop certbot.timer
systemctl disable certbot
systemctl disable certbot.timer​
systemctl daemon-reload

Jetzt soll­te letsencrypt.log sau­ber blei­ben.

Nachtrag 2: Umzug des certbot

[26.11.2018] Vor kur­zem war der Umzug des cert­bot auf einen ande­ren Ser­ver nötig. Dazu wird auf dem neu­en Ser­ver zunächst das cert­bot Paket instal­liert:

apt-get install certbot

Das manu­al-auth-hook Script wird vom alten Ser­ver an die glei­che Stel­le (bei mir: /root/freedns-txt.sh) auf dem neu­en Ser­ver kopiert. Zusätz­lich kopiert man die alten Zer­ti­fi­kats­da­ten aus /etc/letsencrypt des alten Ser­vers, am ein­fachs­ten per tar-Archiv:

cd /etc/letsencrypt
tar cfv trans.tar accounts archive csr keys live renewal

Das Archiv trans.tar wird in /etc/letsencrypt des neu­en Ser­vers kopiert und ent­packt:

​cd /etc/letsencrypt
tar xvf trans.tar

Falls nicht ohne­hin vor­han­den, muss noch das beim manu­al-auth-hook benutz­te curl Paket nach­in­stal­liert wer­den:

apt-get install curl

Jetzt kann man die Auto­ma­ti­sche Zer­ti­fi­kats-Erneue­rung wie oben beschrie­ben tes­ten und als cron-Job ein­tra­gen.


Quel­len und Links:

  1. Let’s Encrypt Home­page: let​sen​crypt​.org
  2. Cert­bot Doku­men­ta­ti­on: cert​bot​.eff​.org/​d​o​c​s​/​u​s​i​n​g​.​h​tml
    1. Pre- and Post-Vali­da­ti­on-Hooks
    2. DNS-Plugins
  3. FreeDNS Hom­a­pa­ge: freedns​.afraid​.org

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.