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"