Howto/SSL Zertifikate mit Let's Encrypt
Terminologie: cert_master: Rechner, auf dem die Zertifikate angefordert und gesammelt sind. cert_client: Rechner, auf den die Zertifikate übertragen werden.
Vorbereitungen für Cert_master:
apache, openssl installieren
Dehydrated besorgen:
git clone https://github.com/lukas2511/dehydrated
an passende stelle kopieren, /etc/dehydrated erstellen
cp dehydrated/dehydrated /usr/local/sbin/dehydrated
folgende Dateien unter /etc/dehydrated erstellen:
config: Hier werden die Optionen von dehydrated eingestellt.
########################################################
# This is the main config file for dehydrated #
# #
# This file is looked for in the following locations: #
# $SCRIPTDIR/config (next to this script) #
# /usr/local/etc/dehydrated/config #
# /etc/dehydrated/config #
# ${PWD}/config (in current working-directory) #
# #
# Default values of this config are in comments #
########################################################
# Resolve names to addresses of IP version only. (curl)
# supported values: 4, 6
# default:
#IP_VERSION=
# Path to certificate authority (default:
# https://acme-v01.api.letsencrypt.org/directory)
#CA="https://acme-v01.api.letsencrypt.org/directory"
# Path to license agreement (default:
# https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf)
#LICENSE="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
# Which challenge should be used? Currently http-01 and dns-01 are supported
CHALLENGETYPE="http-01"
# Path to a directory containing additional config files, allowing to
# override
# the defaults found in the main configuration file. Additional config files
# in this directory needs to be named with a '.sh' ending.
# default:
#CONFIG_D=
# Base directory for account key, generated certificates and list of domains
# (default: $SCRIPTDIR -- uses config directory if undefined)
BASEDIR=/etc/dehydrated
# File containing the list of domains to request certificates for (default:
# $BASEDIR/domains.txt)
DOMAINS_TXT="${BASEDIR}/domains.txt"
# Output directory for generated certificates
CERTDIR="${BASEDIR}/certs"
# Directory for account keys and registration information
ACCOUNTDIR="${BASEDIR}/accounts"
# Output directory for challenge-tokens to be served by webserver or
# deployed in HOOK (default: /var/www/dehydrated)
WELLKNOWN="/var/www/dehydrated"
# Default keysize for private keys (default: 4096)
#KEYSIZE="4096"
# Path to openssl config file (default: - tries to figure out system
# default)
#OPENSSL_CNF=
# Program or function called in certain situations
#
# After generating the challenge-response, or after failed challenge (in
# this case altname is empty)
# Given arguments: clean_challenge|deploy_challenge altname token-filename
# token-content
#
# After successfully signing certificate
# Given arguments: deploy_cert domain path/to/privkey.pem path/to/cert.pem
# path/to/fullchain.pem
#
# BASEDIR and WELLKNOWN variables are exported and can be used in an
# external program
# default:
HOOK=/etc/dehydrated/hook.sh
# Chain clean_challenge|deploy_challenge arguments together into one hook
# call per certificate (default: no)
#HOOK_CHAIN="no"
# Minimum days before expiration to automatically renew certificate
# (default: 30)
#RENEW_DAYS="30"
# Regenerate private keys instead of just signing new certificates on
# renewal (default: 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"
# Minimum days before expiration to automatically renew certificate
# (default: 30)
#RENEW_DAYS="30"
# Regenerate private keys instead of just signing new certificates on
# renewal (default: yes)
#PRIVATE_KEY_RENEW="yes"
# Option to add CSR-flag indicating OCSP stapling to be mandatory (default:
# no)
#OCSP_MUST_STAPLE="no"
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).
#!/usr/bin/env bash
function deploy_challenge {
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
# This hook is called once for every domain that needs to be
# validated, including any alternative names you may have listed.
#
# Parameters:
# - DOMAIN
# The domain name (CN or subject alternative name) being
# validated.
# - TOKEN_FILENAME
# The name of the file containing the token to be served for HTTP
# validation. Should be served by your web server as
# /.well-known/acme-challenge/${TOKEN_FILENAME}.
# - TOKEN_VALUE
# The token value that needs to be served for validation. For DNS
# validation, this is what you want to put in the _acme-challenge
# TXT record. For HTTP validation it is the value that is expected
# be found in the $TOKEN_FILENAME file.
}
function clean_challenge {
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
# This hook is called after attempting to validate each domain,
# whether or not validation was successful. Here you can delete
# files or DNS records that are no longer needed.
#
# The parameters are the same as for deploy_challenge.
}
function deploy_cert {
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}" TIMESTAMP="${6}"
# This hook is called once for each certificate that has been
# produced. Here you might, for instance, copy your new certificates
# to service-specific locations and reload the service.
#
# Parameters:
# - DOMAIN
# The primary domain name, i.e. the certificate common
# name (CN).
# - KEYFILE
# The path of the file containing the private key.
# - CERTFILE
# The path of the file containing the signed certificate.
# - FULLCHAINFILE
# The path of the file containing the full certificate chain.
# - CHAINFILE
# The path of the file containing the intermediate certificate(s).
# - TIMESTAMP
# Timestamp when the specified certificate was created.
#systemctl reload nginx
#if [ "$DOMAIN" = "smtp.xxx.xxx" ]
# then
# systemctl restart postfix dovecot
#fi
echo "Renewed/Created: $DOMAIN at `date -d @$TIMESTAMP`" >&2
# Copy local Certificates
if [[ "$DOMAIN" == "zuckerwatte.freifunk-mwu.de" ]]
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/
chmod -R 0700 /etc/apache2/ssl/
apachectl graceful
# Copy certs to cert home dir
mkdir -p /home/cert/$DOMAIN/
cp $KEYFILE /home/cert/$DOMAIN/
cp $CERTFILE /home/cert/$DOMAIN/
cp $CHAINFILE /home/cert/$DOMAIN/
chmod 500 $(find /home/cert -mindepth 1 -type d )
chmod 400 $(find /home/cert -mindepth 1 -type f )
chown cert.cert -R /home/cert/*
# cleanup unused cert files
dehydrated -gc
}
function unchanged_cert {
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}"
# This hook is called once for each certificate that is still
# valid and therefore wasn't reissued.
#
# Parameters:
# - DOMAIN
# The primary domain name, i.e. the certificate common
# name (CN).
# - KEYFILE
# The path of the file containing the private key.
# - CERTFILE
# The path of the file containing the signed certificate.
# - FULLCHAINFILE
# The path of the file containing the full certificate chain.
# - CHAINFILE
# The path of the file containing the intermediate certificate(s).
# cleanup unused cert files
dehydrated -gc
}
HANDLER=$1; shift; $HANDLER $@
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.
#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
#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
#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
#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
#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
#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
#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