# 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 ->

GOTIFY_URL=<- https://deine-gotify-domain.de ->
GOTIFY_TOKEN=<- DEIN-APP-TOKEN ->
```

```python
#!/bin/bash

# netcup.env Datei laden
if [ -f netcup.env ]; then
  export $(grep -v '^#' netcup.env | xargs)
else
  echo "Fehler: netcup.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"

# 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
}

# 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

# 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 '{
    "action": "login",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apipassword": "'"$API_PASSWORD"'"
    }
  }' "$API_URL")

SESSION_ID=$(echo "$LOGIN_RESPONSE" | jq -r '.responsedata.apisessionid')

if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" ]]; then
  ERROR_MSG="Fehler beim Login!"
  echo "$ERROR_MSG"
  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 '{
    "action": "infoDnsRecords",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apisessionid": "'"$SESSION_ID"'",
      "domainname": "'"$DOMAIN"'"
    }
  }' "$API_URL")

RECORDS=$(echo "$DNS_RESPONSE" | jq -r '.responsedata.dnsrecords // []')

# Spezifische TLSA-Records überprüfen und aktualisieren oder erstellen
update_tlsa_record() {
  local HOSTNAME="$1"
  local TYPE="$2"
  local HASH="$3"

  EXISTING_RECORD=$(echo "$RECORDS" | jq -r ".[] | select(.hostname == \"$HOSTNAME\" and .type == \"TLSA\" and (.destination | tostring | startswith(\"$TYPE\")))")

  if [[ -n "$EXISTING_RECORD" ]]; then
    RECORD_ID=$(echo "$EXISTING_RECORD" | jq -r '.id')
    OLD_DESTINATION=$(echo "$EXISTING_RECORD" | jq -r '.destination')

    if [[ "$OLD_DESTINATION" == "$TYPE $HASH" ]]; then
      echo "TLSA-Record ist identisch: $HOSTNAME $TYPE $HASH"
    else
      echo "Aktualisiere bestehenden TLSA-Record: $HOSTNAME"
      echo "Von: $OLD_DESTINATION"
      echo "Nach: $TYPE $HASH"
      send_gotify_notification "TLSA Script Update" "TLSA-Record alt: $OLD_DESTINATION" 5

      DNS_UPDATE_PAYLOAD='{
        "action": "updateDnsRecords",
        "param": {
          "customernumber": "'"$CUSTOMER_NUMBER"'",
          "apikey": "'"$API_KEY"'",
          "apisessionid": "'"$SESSION_ID"'",
          "domainname": "'"$DOMAIN"'",
          "dnsrecordset": {
            "dnsrecords": [
              {
                "id": "'"$RECORD_ID"'",
                "hostname": "'"$HOSTNAME"'",
                "type": "TLSA",
                "destination": "'"$TYPE $HASH"'",
                "state": "yes"
              }
            ]
          }
        }
      }'

      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 neu: $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
  else
    echo "Erstelle neuen TLSA-Record: $HOSTNAME $TYPE $HASH"

    DNS_CREATE_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"
            }
          ]
        }
      }
    }'

    CREATE_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
      -d "$DNS_CREATE_PAYLOAD" "$API_URL")

    CREATE_STATUS=$(echo "$CREATE_RESPONSE" | jq -r '.status')

    if [[ "$CREATE_STATUS" == "success" ]]; then
      echo "TLSA-Record erfolgreich erstellt: $HOSTNAME $TYPE $HASH"
      send_gotify_notification "TLSA Script Erfolg" "TLSA-Record erfolgreich erstellt: $HOSTNAME $TYPE $HASH" 0
    else
      ERROR_MSG="Fehler beim Erstellen des TLSA-Records: $HOSTNAME $TYPE $HASH"
      echo "$ERROR_MSG"
      echo "$CREATE_RESPONSE"
      send_gotify_notification "TLSA Script Fehler" "$ERROR_MSG" 10
    fi
  fi
}

# Aktualisieren oder Erstellen der TLSA-Records
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 '{
    "action": "logout",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apisessionid": "'"$SESSION_ID"'"
    }
  }' "$API_URL" > /dev/null

echo "Logout abgeschlossen."
```