cluster

Infrastructure files for Nordgedanken and Midnightthoughts.
git clone git://archive.git.mtrnord.blog/MTRNord/cluster.git
Log | Files | Refs | README

tlsa-updater.yaml (5818B)


      1 apiVersion: v1
      2 kind: ServiceAccount
      3 metadata:
      4   name: tlsa-updater
      5   namespace: stalwart
      6 ---
      7 apiVersion: rbac.authorization.k8s.io/v1
      8 kind: Role
      9 metadata:
     10   name: tlsa-updater
     11   namespace: stalwart
     12 rules:
     13   - apiGroups: [""]
     14     resources: ["secrets"]
     15     resourceNames: ["stalwart-mail-cert"]
     16     verbs: ["get"]
     17 ---
     18 apiVersion: rbac.authorization.k8s.io/v1
     19 kind: RoleBinding
     20 metadata:
     21   name: tlsa-updater
     22   namespace: stalwart
     23 subjects:
     24   - kind: ServiceAccount
     25     name: tlsa-updater
     26     namespace: stalwart
     27 roleRef:
     28   kind: Role
     29   apiGroup: rbac.authorization.k8s.io
     30   name: tlsa-updater
     31 ---
     32 apiVersion: batch/v1
     33 kind: CronJob
     34 metadata:
     35   name: tlsa-updater
     36   namespace: stalwart
     37 spec:
     38   schedule: "17 * * * *"
     39   concurrencyPolicy: Forbid
     40   successfulJobsHistoryLimit: 3
     41   failedJobsHistoryLimit: 3
     42   jobTemplate:
     43     spec:
     44       template:
     45         spec:
     46           serviceAccountName: tlsa-updater
     47           restartPolicy: OnFailure
     48           containers:
     49             - name: tlsa-updater
     50               image: alpine:3
     51               env:
     52                 - name: PDNS_URL
     53                   value: "http://10.0.64.129:8081"
     54                 - name: PDNS_ZONE
     55                   value: "midnightthoughts.space."
     56                 - name: MAIL_HOST
     57                   value: "mail.midnightthoughts.space."
     58                 - name: PDNS_API_KEY
     59                   valueFrom:
     60                     secretKeyRef:
     61                       name: tlsa-updater-pdns
     62                       key: api-key
     63               command:
     64                 - /bin/sh
     65                 - -c
     66                 - |
     67                   set -e
     68                   apk add -q --no-cache openssl curl jq
     69 
     70                   TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
     71                   CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
     72 
     73                   SECRET=$(curl -sf --cacert "$CA" \
     74                     -H "Authorization: Bearer $TOKEN" \
     75                     "https://kubernetes.default.svc/api/v1/namespaces/stalwart/secrets/stalwart-mail-cert")
     76 
     77                   # Full cert chain (leaf + intermediates)
     78                   CERT_CHAIN=$(echo "$SECRET" | jq -r '.data["tls.crt"]' | base64 -d)
     79 
     80                   # Split full chain into individual cert files
     81                   echo "$CERT_CHAIN" | awk '
     82                     /-----BEGIN CERTIFICATE-----/ { n++ }
     83                     { print > "/tmp/cert-" n ".pem" }
     84                   '
     85 
     86                   RECORDS_JSON="[]"
     87                   IDX=1
     88                   while [ -f "/tmp/cert-${IDX}.pem" ]; do
     89                     openssl x509 -in "/tmp/cert-${IDX}.pem" -outform DER -out "/tmp/cert-${IDX}.der" 2>/dev/null
     90                     openssl x509 -in "/tmp/cert-${IDX}.pem" -pubkey -noout 2>/dev/null \
     91                       | openssl pkey -pubin -outform DER -out "/tmp/cert-${IDX}.spki.der" 2>/dev/null
     92 
     93                     H01=$(openssl dgst -sha256 "/tmp/cert-${IDX}.der" | awk '{print $2}')
     94                     H02=$(openssl dgst -sha512 "/tmp/cert-${IDX}.der" | awk '{print $2}')
     95                     H11=$(openssl dgst -sha256 "/tmp/cert-${IDX}.spki.der" | awk '{print $2}')
     96                     H12=$(openssl dgst -sha512 "/tmp/cert-${IDX}.spki.der" | awk '{print $2}')
     97 
     98                     echo "Cert $IDX: 3/2 0 1=$H01"
     99 
    100                     if [ "$IDX" -eq 1 ]; then
    101                       # Leaf cert: DANE-EE (3 x x) + PKIX-EE (2 x x)
    102                       NEW=$(jq -n \
    103                         --arg h01 "$H01" --arg h02 "$H02" \
    104                         --arg h11 "$H11" --arg h12 "$H12" \
    105                         '[
    106                           {content: ("3 0 1 " + $h01), disabled: false},
    107                           {content: ("3 0 2 " + $h02), disabled: false},
    108                           {content: ("3 1 1 " + $h11), disabled: false},
    109                           {content: ("3 1 2 " + $h12), disabled: false},
    110                           {content: ("2 0 1 " + $h01), disabled: false},
    111                           {content: ("2 0 2 " + $h02), disabled: false},
    112                           {content: ("2 1 1 " + $h11), disabled: false},
    113                           {content: ("2 1 2 " + $h12), disabled: false}
    114                         ]')
    115                     else
    116                       # Intermediate certs: PKIX-EE (2 x x) only
    117                       NEW=$(jq -n \
    118                         --arg h01 "$H01" --arg h02 "$H02" \
    119                         --arg h11 "$H11" --arg h12 "$H12" \
    120                         '[
    121                           {content: ("2 0 1 " + $h01), disabled: false},
    122                           {content: ("2 0 2 " + $h02), disabled: false},
    123                           {content: ("2 1 1 " + $h11), disabled: false},
    124                           {content: ("2 1 2 " + $h12), disabled: false}
    125                         ]')
    126                     fi
    127 
    128                     RECORDS_JSON=$(printf '%s\n%s' "$RECORDS_JSON" "$NEW" | jq -s '.[0] + .[1]')
    129                     IDX=$((IDX + 1))
    130                   done
    131 
    132                   echo "Total TLSA records: $(echo "$RECORDS_JSON" | jq 'length')"
    133 
    134                   for PORT in 25 465 587 143 993; do
    135                     NAME="_${PORT}._tcp.${MAIL_HOST}"
    136                     echo "Updating $NAME ..."
    137                     BODY=$(jq -n \
    138                       --arg name "$NAME" \
    139                       --argjson records "$RECORDS_JSON" \
    140                       '{rrsets: [{name: $name, type: "TLSA", ttl: 300, changetype: "REPLACE", records: $records}]}')
    141                     curl -sf -X PATCH \
    142                       -H "X-API-Key: $PDNS_API_KEY" \
    143                       -H "Content-Type: application/json" \
    144                       -d "$BODY" \
    145                       "${PDNS_URL}/api/v1/servers/localhost/zones/${PDNS_ZONE}" > /dev/null
    146                     echo "  OK"
    147                   done
    148 
    149                   echo "TLSA update complete"