The deploy workflow does not have BACKUP_ENCRYPTION_KEY/BACKUP_BUCKET/OBS_ENDPOINT env vars. Redesigned to reference existing forgejo-cloud-credentials K8s secret and hardcode OBS endpoint, matching the pattern of forgejo-s3-backup-cronjob. Ref: IPCEICIS-9317
129 lines
4.2 KiB
YAML
129 lines
4.2 KiB
YAML
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: secrets-backup
|
|
namespace: gitea
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRole
|
|
metadata:
|
|
name: secrets-backup-reader
|
|
rules:
|
|
- apiGroups: [""]
|
|
resources: ["secrets"]
|
|
verbs: ["get", "list"]
|
|
- apiGroups: [""]
|
|
resources: ["namespaces"]
|
|
verbs: ["get", "list"]
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRoleBinding
|
|
metadata:
|
|
name: secrets-backup-reader
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: secrets-backup
|
|
namespace: gitea
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: secrets-backup-reader
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: secrets-backup-config
|
|
namespace: gitea
|
|
type: Opaque
|
|
stringData:
|
|
# IMPORTANT: Replace this placeholder with a strong passphrase per environment.
|
|
# This secret should be managed via external-secrets or manually set after initial deploy.
|
|
encryption-passphrase: "CHANGE-ME-SET-PER-ENVIRONMENT"
|
|
---
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: secrets-backup
|
|
namespace: gitea
|
|
spec:
|
|
schedule: "30 3 * * *"
|
|
concurrencyPolicy: "Forbid"
|
|
successfulJobsHistoryLimit: 5
|
|
failedJobsHistoryLimit: 5
|
|
startingDeadlineSeconds: 600 # 10 minutes
|
|
jobTemplate:
|
|
spec:
|
|
activeDeadlineSeconds: 900
|
|
backoffLimit: 2
|
|
ttlSecondsAfterFinished: 259200
|
|
template:
|
|
spec:
|
|
serviceAccountName: secrets-backup
|
|
containers:
|
|
- name: secrets-backup
|
|
image: alpine/k8s:1.28.0
|
|
imagePullPolicy: IfNotPresent
|
|
env:
|
|
- name: AWS_ACCESS_KEY_ID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: forgejo-cloud-credentials
|
|
key: access-key
|
|
- name: AWS_SECRET_ACCESS_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: forgejo-cloud-credentials
|
|
key: secret-key
|
|
- name: ENCRYPTION_PASSPHRASE
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: secrets-backup-config
|
|
key: encryption-passphrase
|
|
- name: SOURCE_BUCKET
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: forgejo-cloud-credentials
|
|
key: bucket-name
|
|
- name: OBS_ENDPOINT
|
|
value: "obs.eu-de.otc.t-systems.com"
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -euo pipefail
|
|
|
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
BACKUP_DIR="/tmp/secrets-backup-${TIMESTAMP}"
|
|
NAMESPACES="argocd cert-manager external-secrets"
|
|
|
|
mkdir -p "${BACKUP_DIR}"
|
|
|
|
echo "=== Exporting secrets from critical namespaces ==="
|
|
for NS in ${NAMESPACES}; do
|
|
echo "Exporting namespace: ${NS}"
|
|
kubectl get secrets -n "${NS}" \
|
|
-o json \
|
|
--field-selector type!=kubernetes.io/service-account-token \
|
|
> "${BACKUP_DIR}/${NS}-secrets.json"
|
|
done
|
|
|
|
echo "=== Encrypting backup with AES-256-CBC ==="
|
|
ARCHIVE="${BACKUP_DIR}/secrets-backup-${TIMESTAMP}.tar.gz"
|
|
tar -czf "${ARCHIVE}" -C "${BACKUP_DIR}" \
|
|
$(ls "${BACKUP_DIR}"/*.json 2>/dev/null | xargs -n1 basename)
|
|
|
|
ENCRYPTED="${BACKUP_DIR}/secrets-backup-${TIMESTAMP}.tar.gz.enc"
|
|
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
|
|
-in "${ARCHIVE}" \
|
|
-out "${ENCRYPTED}" \
|
|
-pass env:ENCRYPTION_PASSPHRASE
|
|
|
|
echo "=== Uploading to OBS ==="
|
|
aws s3 cp "${ENCRYPTED}" \
|
|
"s3://${SOURCE_BUCKET}/cluster-secrets-backup/${TIMESTAMP}/secrets-backup.tar.gz.enc" \
|
|
--endpoint-url "https://${OBS_ENDPOINT}"
|
|
|
|
echo "=== Cleanup ==="
|
|
rm -rf "${BACKUP_DIR}"
|
|
echo "Backup completed: ${TIMESTAMP}"
|
|
restartPolicy: OnFailure
|