Files
marktvogt.de/scripts/k8s-secrets-sync.sh
vikingowl d3982c1d73 feat(helm): add monolithic marktvogt chart + secrets sync script
New unified helm chart at helm/marktvogt/ that combines backend (Go API,
Postgres, Dragonfly, migrate hook, discovery cron) and web (SvelteKit SSR)
into a single release. Replaces the per-service charts at backend/deploy/helm
and web/deploy/helm — kept in place until the live migration is verified
(see helm/marktvogt/MIGRATION.md).

Selector labels and resource names match the existing per-service charts
exactly so migration is by re-annotation rather than recreate; CNPG cluster
and Dragonfly survive the cutover with no data loss.

Adds scripts/k8s-secrets-sync.sh + .env.helm.example for reproducible
out-of-band secret creation. .env.helm itself is gitignored.
2026-04-28 15:57:30 +02:00

93 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Sync Kubernetes secrets to tenant-2 from a local .env.helm file.
# Idempotent — safe to run repeatedly. Uses dry-run | apply pattern so existing
# secrets get updated in place rather than recreated.
#
# Usage: ./scripts/k8s-secrets-sync.sh [path/to/.env.helm]
# Default env file is .env.helm at repo root. Override namespace via NAMESPACE env.
set -euo pipefail
ENV_FILE="${1:-.env.helm}"
NS="${NAMESPACE:-tenant-2}"
if [[ ! -f "$ENV_FILE" ]]; then
echo "Missing $ENV_FILE"
echo "Copy .env.helm.example to .env.helm and fill in values."
exit 1
fi
# Parse line by line — no shell interpretation of values. Avoids `source`
# choking on unquoted spaces, $, %, etc. that are legitimate in secrets.
while IFS= read -r line || [[ -n "$line" ]]; do
# Skip blanks + comments
[[ -z "${line//[[:space:]]/}" ]] && continue
[[ "${line#"${line%%[![:space:]]*}"}" =~ ^# ]] && continue
# Split on first =
key="${line%%=*}"
value="${line#*=}"
# Trim whitespace from key
key="${key//[[:space:]]/}"
[[ -z "$key" ]] && continue
export "$key=$value"
done < "$ENV_FILE"
apply_secret() {
local name=$1
shift
local args=()
local missing=()
for kv in "$@"; do
local key="${kv%%=*}"
local var="${kv#*=}"
local val="${!var:-}"
if [[ -z "$val" ]]; then
missing+=("$var")
continue
fi
args+=(--from-literal="$key=$val")
done
if [[ ${#args[@]} -eq 0 ]]; then
echo "skip $name — no values set in $ENV_FILE"
return
fi
if [[ ${#missing[@]} -gt 0 ]]; then
echo "apply secret/$name in $NS (omitting unset: ${missing[*]})"
else
echo "apply secret/$name in $NS"
fi
kubectl create secret generic "$name" \
--namespace="$NS" \
"${args[@]}" \
--dry-run=client -o yaml | kubectl apply -f -
}
# App-level secrets the backend reads via envFrom: secretRef
apply_secret marktvogt-backend-secrets \
"APP_SECRET=APP_SECRET" \
"SENTRY_DSN=SENTRY_DSN" \
"OAUTH_GOOGLE_CLIENT_ID=OAUTH_GOOGLE_CLIENT_ID" \
"OAUTH_GOOGLE_CLIENT_SECRET=OAUTH_GOOGLE_CLIENT_SECRET" \
"OAUTH_APPLE_CLIENT_ID=OAUTH_APPLE_CLIENT_ID" \
"OAUTH_APPLE_CLIENT_SECRET=OAUTH_APPLE_CLIENT_SECRET" \
"OAUTH_FACEBOOK_CLIENT_ID=OAUTH_FACEBOOK_CLIENT_ID" \
"OAUTH_FACEBOOK_CLIENT_SECRET=OAUTH_FACEBOOK_CLIENT_SECRET" \
"OAUTH_GITHUB_CLIENT_ID=OAUTH_GITHUB_CLIENT_ID" \
"OAUTH_GITHUB_CLIENT_SECRET=OAUTH_GITHUB_CLIENT_SECRET"
# SMTP credentials
apply_secret marktvogt-backend-smtp \
"SMTP_HOST=SMTP_HOST" \
"SMTP_USER=SMTP_USER" \
"SMTP_PASSWORD=SMTP_PASSWORD"
# Turnstile + discovery + AI bootstrap
apply_secret marktvogt-backend-ci-secrets \
"TURNSTILE_SECRET_KEY=TURNSTILE_SECRET_KEY" \
"DISCOVERY_TOKEN=DISCOVERY_TOKEN" \
"AI_API_KEY=AI_API_KEY" \
"AI_AGENT_SIMPLE=AI_AGENT_SIMPLE" \
"AI_AGENT_DISCOVERY=AI_AGENT_DISCOVERY"
echo "done"