Update netcup/update_tlsa_record.md

This commit is contained in:
2025-01-24 12:52:07 +00:00
parent d7f41b7ccc
commit 8a1dc75991

View File

@@ -1,21 +1,25 @@
# TLSA Records setzen über die API von NetCup # TLSA Records setzen über die API von NetCup
Mit diesem Script kann man automatisiert den TLSA Record setzen. Es wird zunächst geprüft ob er bereits vorhanden ist, wenn ja wird er nicht aktualisiert. Mit diesem Script kann man automatisiert den TLSA Record setzen. Es wird zunächst geprüft ob er bereits vorhanden ist, wenn ja wird er nicht aktualisiert.
Darüber hinaus wird auch das Rolloverscheme gesetzt. Hier wird die CA von Letsencrypt genutzt, da man vor dem Zertifikatswechsel das neue Zertifikat ja noch nicht kennt bzw. hat.
Optional sind nun auch Pushnachrichten per Gotify möglich, diese werden nur gesandt, wenn Änderungen erfolgt sind.
Die `netcup.env` Datei sollte dabei im gleichen Verzeichnis liegen und folgenden Inhalt haben: Die `netcup.env` Datei sollte dabei im gleichen Verzeichnis liegen und folgenden Inhalt haben:
```python ```python
CUSTOMER_NUMBER=DEINE_KUNDENNUMMER CUSTOMER_NUMBER=<- DEINE_KUNDENNUMMER ->
API_KEY=DEIN_API_KEY API_KEY=<- DEIN_API_KEY ->
API_PASSWORD=DEIN_API_PASSWORT API_PASSWORD=<- DEIN_API_PASSWORT ->
DOMAIN=deine-domain.de DOMAIN=<- deine-domain.de ->
MAIL_SERVICE=deine-mx-domain.de
CERTIFICATE_PATH=PFAD_ZUR_fullchain.pem GOTIFY_URL=<- https://deine-gotify-domain.de ->
GOTIFY_TOKEN=<- DEIN-APP-TOKEN ->
``` ```
```python ```python
#!/bin/bash #!/bin/bash
# .env Datei laden # .env Datei laden
if [ -f netcup.env ]; then if [ -f netcup.env ]; then
export $(grep -v '^#' netcup.env | xargs) export $(grep -v '^#' netcup.env | xargs)
@@ -23,41 +27,80 @@ else
echo "Fehler: .env Datei nicht gefunden!" echo "Fehler: .env Datei nicht gefunden!"
exit 1 exit 1
fi fi
# Pfade zu Zertifikaten
CA_CERTIFICATE_DIR="/etc/ssl/certs" # Verzeichnis, in dem CA-Zertifikate gespeichert werden
# URL der Netcup API # URL der Netcup API
API_URL="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" API_URL="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
# Prüfen, ob das Zertifikat existiert # Gotify-URL und Token für spezifische App
if [[ ! -f "$CERTIFICATE_PATH" ]]; then GOTIFY_URL="$GOTIFY_URL"
echo "Fehler: Zertifikat unter $CERTIFICATE_PATH nicht gefunden!" GOTIFY_TOKEN="$GOTIFY_TOKEN"
exit 1
fi # Funktion für Gotify-Benachrichtigungen
send_gotify_notification() {
echo "Zertifikat gefunden: $CERTIFICATE_PATH" local TITLE="$1"
local MESSAGE="$2"
# TLSA-Hash generieren mit Fallback-Mechanismus local PRIORITY=${3:-0}
TLSA_HASH=""
RETRY_COUNT=0 if [[ -n "$GOTIFY_URL" && -n "$GOTIFY_TOKEN" ]]; then
MAX_RETRIES=3 curl -s -X POST "$GOTIFY_URL/message?token=$GOTIFY_TOKEN" \
-F "title=$TITLE" \
while [[ -z "$TLSA_HASH" && $RETRY_COUNT -lt $MAX_RETRIES ]]; do -F "message=$MESSAGE" \
TLSA_HASH=$(openssl x509 -in "$CERTIFICATE_PATH" -pubkey -noout | \ -F "priority=$PRIORITY" > /dev/null
openssl pkey -pubin -outform DER | \ else
openssl dgst -sha256 -binary | hexdump -ve '1/1 "%.2x"') echo "Gotify-Konfiguration fehlt. Keine Benachrichtigung gesendet."
if [[ -z "$TLSA_HASH" ]]; then
((RETRY_COUNT++))
echo "Fehler beim Generieren des TLSA-Hashes! Versuche erneut ($RETRY_COUNT/$MAX_RETRIES)"
sleep 1
fi fi
done }
if [[ -z "$TLSA_HASH" ]]; then # Zertifikate prüfen
echo "Fehler beim Generieren des TLSA-Hashes nach $MAX_RETRIES Versuchen!" if [[ ! -f "$CERTIFICATE_PATH" ]]; then
ERROR_MSG="Fehler: Zertifikat unter $CERTIFICATE_PATH nicht gefunden!"
echo "$ERROR_MSG"
send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
exit 1 exit 1
fi fi
echo "TLSA-Record-Hash generiert: $TLSA_HASH" # Aktuelles CA-Zertifikat von Let's Encrypt finden
CA_ISSUER_URL=$(openssl x509 -in "$CERTIFICATE_PATH" -noout -text | grep -A1 "CA Issuers" | grep http | sed 's/.*URI://')
CA_CERTIFICATE_PATH="$CA_CERTIFICATE_DIR/$(basename "$CA_ISSUER_URL")"
if [[ ! -f "$CA_CERTIFICATE_PATH" ]]; then
echo "CA-Zertifikat wird von $CA_ISSUER_URL heruntergeladen..."
wget -q "$CA_ISSUER_URL" -O "$CA_CERTIFICATE_PATH"
if [[ $? -ne 0 ]]; then
ERROR_MSG="Fehler beim Herunterladen des CA-Zertifikats von $CA_ISSUER_URL"
echo "$ERROR_MSG"
send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
exit 1
fi
echo "CA-Zertifikat erfolgreich heruntergeladen: $CA_CERTIFICATE_PATH"
send_gotify_notification "TLSA Script Erfolg" "CA-Zertifikat erfolgreich heruntergeladen: $CA_CERTIFICATE_PATH" 0
else
echo "CA-Zertifikat gefunden: $CA_CERTIFICATE_PATH"
fi
# TLSA-Hashes generieren
TLSA_HASH_CURRENT=$(openssl x509 -in "$CERTIFICATE_PATH" -pubkey -noout | \
openssl pkey -pubin -outform DER | \
openssl dgst -sha256 -binary | hexdump -ve '1/1 "%.2x"')
TLSA_HASH_CA=$(openssl x509 -in "$CA_CERTIFICATE_PATH" -pubkey -noout | \
openssl pkey -pubin -outform DER | \
openssl dgst -sha256 -binary | hexdump -ve '1/1 "%.2x"')
if [[ -z "$TLSA_HASH_CURRENT" || -z "$TLSA_HASH_CA" ]]; then
ERROR_MSG="Fehler beim Generieren der TLSA-Hashes!"
echo "$ERROR_MSG"
send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
exit 1
fi
echo "TLSA-Hashes generiert:"
echo "Aktuelles Zertifikat (3 1 1): $TLSA_HASH_CURRENT"
echo "CA-Zertifikat (2 1 1): $TLSA_HASH_CA"
# Login zur Netcup API # Login zur Netcup API
LOGIN_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ LOGIN_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
-d '{ -d '{
@@ -68,17 +111,19 @@ LOGIN_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
"apipassword": "'"$API_PASSWORD"'" "apipassword": "'"$API_PASSWORD"'"
} }
}' "$API_URL") }' "$API_URL")
SESSION_ID=$(echo "$LOGIN_RESPONSE" | jq -r '.responsedata.apisessionid') SESSION_ID=$(echo "$LOGIN_RESPONSE" | jq -r '.responsedata.apisessionid')
if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" ]]; then if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" ]]; then
echo "Fehler beim Login!" ERROR_MSG="Fehler beim Login!"
echo "$ERROR_MSG"
echo "$LOGIN_RESPONSE" echo "$LOGIN_RESPONSE"
send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
exit 1 exit 1
fi fi
echo "Erfolgreich eingeloggt. Session-ID: $SESSION_ID" echo "Erfolgreich eingeloggt. Session-ID: $SESSION_ID"
# DNS Records abrufen # DNS Records abrufen
DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
-d '{ -d '{
@@ -90,80 +135,63 @@ DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
"domainname": "'"$DOMAIN"'" "domainname": "'"$DOMAIN"'"
} }
}' "$API_URL") }' "$API_URL")
# JSON komprimieren für grep-Verarbeitung RECORDS=$(echo "$DNS_RESPONSE" | jq -r '.responsedata.dnsrecords // []')
COMPACT_JSON=$(echo "$DNS_RESPONSE" | tr -d '\n' | tr -d '[:space:]')
# Prüfen und aktualisieren der TLSA-Records
# TLSA-Record prüfen update_tlsa_record() {
EXISTING_TLSA_RECORD=$(echo "$COMPACT_JSON" | grep -o '{"id":[^}]*"hostname":"_25._tcp.'"$MAIL_SERVICE"'"[^}]*"destination":"3[^}]*}') local HOSTNAME="$1"
local TYPE="$2"
if [[ -n "$EXISTING_TLSA_RECORD" ]]; then local HASH="$3"
RECORD_ID=$(echo "$EXISTING_TLSA_RECORD" | grep -o '"id":"[^"]*"' | cut -d '"' -f 4)
EXISTING_DESTINATION=$(echo "$EXISTING_TLSA_RECORD" | grep -o '"destination":"[^"]*"' | cut -d '"' -f 4 | tr -d ' ') EXISTING_RECORD=$(echo "$RECORDS" | jq -r ".[] | select(.hostname == \"$HOSTNAME\" and .type == \"TLSA\") | .destination // \"\"" | grep -E "^$TYPE.*$HASH")
# Entferne Leerzeichen aus TLSA_HASH für den Vergleich if [[ -n "$EXISTING_RECORD" ]]; then
TLSA_HASH_COMPACT=$(echo "3 1 1 $TLSA_HASH" | tr -d ' ') echo "TLSA-Record existiert bereits: $HOSTNAME $TYPE $HASH"
else
if [[ "$EXISTING_DESTINATION" == "$TLSA_HASH_COMPACT" ]]; then echo "TLSA-Record wird aktualisiert: $HOSTNAME $TYPE $HASH"
echo "Der bestehende TLSA-Record hat bereits den korrekten Wert. Keine Änderungen erforderlich." send_gotify_notification "TLSA Script Info" "TLSA-Record wird aktualisiert: $HOSTNAME $TYPE $HASH" 5
# Logout
curl -s -X POST -H "Content-Type: application/json" \ DNS_UPDATE_PAYLOAD='{
-d '{ "action": "updateDnsRecords",
"action": "logout", "param": {
"param": { "customernumber": "'"$CUSTOMER_NUMBER"'",
"customernumber": "'"$CUSTOMER_NUMBER"'", "apikey": "'"$API_KEY"'",
"apikey": "'"$API_KEY"'", "apisessionid": "'"$SESSION_ID"'",
"apisessionid": "'"$SESSION_ID"'" "domainname": "'"$DOMAIN"'",
"dnsrecordset": {
"dnsrecords": [
{
"hostname": "'"$HOSTNAME"'",
"type": "TLSA",
"destination": "'"$TYPE $HASH"'",
"state": "yes"
}
]
} }
}' "$API_URL" > /dev/null
echo "Logout abgeschlossen."
exit 0
else
echo "Der bestehende TLSA-Record unterscheidet sich vom neuen Wert. Aktualisierung wird durchgeführt."
fi
else
echo "Kein bestehender TLSA-Record mit Typ '3 1 1' gefunden. Ein neuer wird erstellt."
RECORD_ID=""
fi
# Neuer oder aktualisierter TLSA-Record erstellen
if [[ -z "$EXISTING_TLSA_RECORD" || "$EXISTING_DESTINATION" != "$TLSA_HASH_COMPACT" ]]; then
DNS_UPDATE_PAYLOAD='{
"action": "updateDnsRecords",
"param": {
"customernumber": "'"$CUSTOMER_NUMBER"'",
"apikey": "'"$API_KEY"'",
"apisessionid": "'"$SESSION_ID"'",
"domainname": "'"$DOMAIN"'",
"dnsrecordset": {
"dnsrecords": [
{
"id": "'"$RECORD_ID"'",
"hostname": "_25._tcp.'"$MAIL_SERVICE"'",
"type": "TLSA",
"destination": "3 1 1 '"$TLSA_HASH"'",
"state": "yes"
}
]
} }
} }'
}'
UPDATE_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
# DNS-Record aktualisieren -d "$DNS_UPDATE_PAYLOAD" "$API_URL")
UPDATE_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
-d "$DNS_UPDATE_PAYLOAD" "$API_URL") UPDATE_STATUS=$(echo "$UPDATE_RESPONSE" | jq -r '.status')
UPDATE_STATUS=$(echo "$UPDATE_RESPONSE" | jq -r '.status') if [[ "$UPDATE_STATUS" == "success" ]]; then
echo "TLSA-Record erfolgreich aktualisiert: $HOSTNAME $TYPE $HASH"
if [[ "$UPDATE_STATUS" == "success" ]]; then send_gotify_notification "TLSA Script Erfolg" "TLSA-Record erfolgreich aktualisiert: $HOSTNAME $TYPE $HASH" 0
echo "TLSA-Record erfolgreich aktualisiert." else
else ERROR_MSG="Fehler beim Aktualisieren des TLSA-Records: $HOSTNAME $TYPE $HASH"
echo "Fehler beim Aktualisieren des TLSA-Records!" echo "$ERROR_MSG"
echo "$UPDATE_RESPONSE" echo "$UPDATE_RESPONSE"
send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
fi
fi fi
fi }
update_tlsa_record "_25._tcp.mail" "3 1 1" "$TLSA_HASH_CURRENT"
update_tlsa_record "_25._tcp.mail" "2 1 1" "$TLSA_HASH_CA"
# Logout # Logout
curl -s -X POST -H "Content-Type: application/json" \ curl -s -X POST -H "Content-Type: application/json" \
-d '{ -d '{
@@ -174,6 +202,6 @@ curl -s -X POST -H "Content-Type: application/json" \
"apisessionid": "'"$SESSION_ID"'" "apisessionid": "'"$SESSION_ID"'"
} }
}' "$API_URL" > /dev/null }' "$API_URL" > /dev/null
echo "Logout abgeschlossen." echo "Logout abgeschlossen."
``` ```