From 8a1dc759910b1b7fe78637b42c93fa3e6efeb65a Mon Sep 17 00:00:00 2001 From: admManuel Date: Fri, 24 Jan 2025 12:52:07 +0000 Subject: [PATCH] Update netcup/update_tlsa_record.md --- netcup/update_tlsa_record.md | 256 +++++++++++++++++++---------------- 1 file changed, 142 insertions(+), 114 deletions(-) diff --git a/netcup/update_tlsa_record.md b/netcup/update_tlsa_record.md index 1a26d70..1dc3ce4 100644 --- a/netcup/update_tlsa_record.md +++ b/netcup/update_tlsa_record.md @@ -1,21 +1,25 @@ # 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. +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: ```python -CUSTOMER_NUMBER=DEINE_KUNDENNUMMER -API_KEY=DEIN_API_KEY -API_PASSWORD=DEIN_API_PASSWORT -DOMAIN=deine-domain.de -MAIL_SERVICE=deine-mx-domain.de -CERTIFICATE_PATH=PFAD_ZUR_fullchain.pem +CUSTOMER_NUMBER=<- DEINE_KUNDENNUMMER -> +API_KEY=<- DEIN_API_KEY -> +API_PASSWORD=<- DEIN_API_PASSWORT -> +DOMAIN=<- deine-domain.de -> + +GOTIFY_URL=<- https://deine-gotify-domain.de -> +GOTIFY_TOKEN=<- DEIN-APP-TOKEN -> ``` ```python #!/bin/bash - + # .env Datei laden if [ -f netcup.env ]; then export $(grep -v '^#' netcup.env | xargs) @@ -23,41 +27,80 @@ else echo "Fehler: .env Datei nicht gefunden!" exit 1 fi - + +# Pfade zu Zertifikaten +CA_CERTIFICATE_DIR="/etc/ssl/certs" # Verzeichnis, in dem CA-Zertifikate gespeichert werden + # URL der Netcup API API_URL="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON" - -# Prüfen, ob das Zertifikat existiert -if [[ ! -f "$CERTIFICATE_PATH" ]]; then - echo "Fehler: Zertifikat unter $CERTIFICATE_PATH nicht gefunden!" - exit 1 -fi - -echo "Zertifikat gefunden: $CERTIFICATE_PATH" - -# TLSA-Hash generieren mit Fallback-Mechanismus -TLSA_HASH="" -RETRY_COUNT=0 -MAX_RETRIES=3 - -while [[ -z "$TLSA_HASH" && $RETRY_COUNT -lt $MAX_RETRIES ]]; do - TLSA_HASH=$(openssl x509 -in "$CERTIFICATE_PATH" -pubkey -noout | \ - openssl pkey -pubin -outform DER | \ - openssl dgst -sha256 -binary | hexdump -ve '1/1 "%.2x"') - if [[ -z "$TLSA_HASH" ]]; then - ((RETRY_COUNT++)) - echo "Fehler beim Generieren des TLSA-Hashes! Versuche erneut ($RETRY_COUNT/$MAX_RETRIES)" - sleep 1 + +# Gotify-URL und Token für spezifische App +GOTIFY_URL="$GOTIFY_URL" +GOTIFY_TOKEN="$GOTIFY_TOKEN" + +# Funktion für Gotify-Benachrichtigungen +send_gotify_notification() { + local TITLE="$1" + local MESSAGE="$2" + local PRIORITY=${3:-0} + + if [[ -n "$GOTIFY_URL" && -n "$GOTIFY_TOKEN" ]]; then + curl -s -X POST "$GOTIFY_URL/message?token=$GOTIFY_TOKEN" \ + -F "title=$TITLE" \ + -F "message=$MESSAGE" \ + -F "priority=$PRIORITY" > /dev/null + else + echo "Gotify-Konfiguration fehlt. Keine Benachrichtigung gesendet." fi -done - -if [[ -z "$TLSA_HASH" ]]; then - echo "Fehler beim Generieren des TLSA-Hashes nach $MAX_RETRIES Versuchen!" +} + +# Zertifikate prüfen +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 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_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ -d '{ @@ -68,17 +111,19 @@ LOGIN_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ "apipassword": "'"$API_PASSWORD"'" } }' "$API_URL") - + SESSION_ID=$(echo "$LOGIN_RESPONSE" | jq -r '.responsedata.apisessionid') - + if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" ]]; then - echo "Fehler beim Login!" + ERROR_MSG="Fehler beim Login!" + echo "$ERROR_MSG" echo "$LOGIN_RESPONSE" + send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10 exit 1 fi - + echo "Erfolgreich eingeloggt. Session-ID: $SESSION_ID" - + # DNS Records abrufen DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ -d '{ @@ -90,80 +135,63 @@ DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \ "domainname": "'"$DOMAIN"'" } }' "$API_URL") - -# JSON komprimieren für grep-Verarbeitung -COMPACT_JSON=$(echo "$DNS_RESPONSE" | tr -d '\n' | tr -d '[:space:]') - -# TLSA-Record prüfen -EXISTING_TLSA_RECORD=$(echo "$COMPACT_JSON" | grep -o '{"id":[^}]*"hostname":"_25._tcp.'"$MAIL_SERVICE"'"[^}]*"destination":"3[^}]*}') - -if [[ -n "$EXISTING_TLSA_RECORD" ]]; then - 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 ' ') - - # Entferne Leerzeichen aus TLSA_HASH für den Vergleich - TLSA_HASH_COMPACT=$(echo "3 1 1 $TLSA_HASH" | tr -d ' ') - - if [[ "$EXISTING_DESTINATION" == "$TLSA_HASH_COMPACT" ]]; then - echo "Der bestehende TLSA-Record hat bereits den korrekten Wert. Keine Änderungen erforderlich." - # Logout - curl -s -X POST -H "Content-Type: application/json" \ - -d '{ - "action": "logout", - "param": { - "customernumber": "'"$CUSTOMER_NUMBER"'", - "apikey": "'"$API_KEY"'", - "apisessionid": "'"$SESSION_ID"'" + +RECORDS=$(echo "$DNS_RESPONSE" | jq -r '.responsedata.dnsrecords // []') + +# Prüfen und aktualisieren der TLSA-Records +update_tlsa_record() { + local HOSTNAME="$1" + local TYPE="$2" + local HASH="$3" + + EXISTING_RECORD=$(echo "$RECORDS" | jq -r ".[] | select(.hostname == \"$HOSTNAME\" and .type == \"TLSA\") | .destination // \"\"" | grep -E "^$TYPE.*$HASH") + + if [[ -n "$EXISTING_RECORD" ]]; then + echo "TLSA-Record existiert bereits: $HOSTNAME $TYPE $HASH" + else + echo "TLSA-Record wird aktualisiert: $HOSTNAME $TYPE $HASH" + send_gotify_notification "TLSA Script Info" "TLSA-Record wird aktualisiert: $HOSTNAME $TYPE $HASH" 5 + + DNS_UPDATE_PAYLOAD='{ + "action": "updateDnsRecords", + "param": { + "customernumber": "'"$CUSTOMER_NUMBER"'", + "apikey": "'"$API_KEY"'", + "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" - } - ] } - } - }' - - # DNS-Record aktualisieren - 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') - - if [[ "$UPDATE_STATUS" == "success" ]]; then - echo "TLSA-Record erfolgreich aktualisiert." - else - echo "Fehler beim Aktualisieren des TLSA-Records!" - echo "$UPDATE_RESPONSE" + }' + + 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') + + if [[ "$UPDATE_STATUS" == "success" ]]; then + echo "TLSA-Record erfolgreich aktualisiert: $HOSTNAME $TYPE $HASH" + send_gotify_notification "TLSA Script Erfolg" "TLSA-Record erfolgreich aktualisiert: $HOSTNAME $TYPE $HASH" 0 + else + ERROR_MSG="Fehler beim Aktualisieren des TLSA-Records: $HOSTNAME $TYPE $HASH" + echo "$ERROR_MSG" + echo "$UPDATE_RESPONSE" + send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10 + 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 curl -s -X POST -H "Content-Type: application/json" \ -d '{ @@ -174,6 +202,6 @@ curl -s -X POST -H "Content-Type: application/json" \ "apisessionid": "'"$SESSION_ID"'" } }' "$API_URL" > /dev/null - + echo "Logout abgeschlossen." ``` \ No newline at end of file