Files
sbbb/scripts/local-seed-secrets.sh

192 lines
8.1 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Seed all secrets for the local dev stack.
# - Initializes OpenBao (if needed) and stores root token + unseal key
# - Sets postgres user passwords
# - Creates K8s secrets consumed by each service
# - Stores all secrets in OpenBao as source of truth
#
# Idempotent: safe to run multiple times.
set -euo pipefail
CTX="--context=sunbeam"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Deterministic local-dev passwords (simple, memorable, not for production)
DB_PASSWORD="localdev"
S3_ACCESS_KEY="minioadmin"
S3_SECRET_KEY="minioadmin"
HYDRA_SYSTEM_SECRET="local-hydra-system-secret-at-least-16"
HYDRA_COOKIE_SECRET="local-hydra-cookie-secret-at-least-16"
HYDRA_PAIRWISE_SALT="local-hydra-pairwise-salt-value-1"
LIVEKIT_API_KEY="devkey"
LIVEKIT_API_SECRET="secret-placeholder"
# ---------------------------------------------------------------------------
# Helper
# ---------------------------------------------------------------------------
ensure_ns() {
kubectl $CTX create namespace "$1" --dry-run=client -o yaml | kubectl $CTX apply -f - 2>/dev/null
}
create_secret() {
local ns="$1"; shift
local name="$1"; shift
# remaining args are --from-literal=key=value
kubectl $CTX create secret generic "$name" -n "$ns" "$@" \
--dry-run=client -o yaml | kubectl $CTX apply -f -
}
# ---------------------------------------------------------------------------
# 1. Wait for postgres to be ready
# ---------------------------------------------------------------------------
echo "==> Waiting for postgres cluster..."
for i in $(seq 1 60); do
PHASE=$(kubectl $CTX -n data get cluster postgres -o jsonpath='{.status.phase}' 2>/dev/null || echo "")
if [[ "$PHASE" == "Cluster in healthy state" ]]; then
echo " Postgres is ready."
break
fi
if [[ $i -eq 60 ]]; then
echo "WARN: Postgres not ready after 5 min, continuing anyway..."
fi
sleep 5
done
# ---------------------------------------------------------------------------
# 2. Set postgres user passwords
# ---------------------------------------------------------------------------
echo "==> Setting postgres user passwords..."
PG_POD=$(kubectl $CTX -n data get pods -l cnpg.io/cluster=postgres,role=primary -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [[ -n "$PG_POD" ]]; then
for user in kratos hydra gitea hive docs meet drive messages conversations people find; do
kubectl $CTX -n data exec "$PG_POD" -c postgres -- \
psql -U postgres -c "ALTER USER $user WITH PASSWORD '$DB_PASSWORD';" 2>/dev/null || true
done
echo " Done."
else
echo "WARN: No postgres primary pod found, skipping password setup."
fi
# ---------------------------------------------------------------------------
# 3. Create K8s secrets for each service
# ---------------------------------------------------------------------------
echo "==> Creating K8s secrets..."
# Ory namespace
ensure_ns ory
# Secret name must match chart release name (secret.enabled: false means chart uses release name)
create_secret ory hydra \
--from-literal=dsn="postgresql://hydra:${DB_PASSWORD}@postgres-rw.data.svc.cluster.local:5432/hydra_db?sslmode=disable" \
--from-literal=secretsSystem="$HYDRA_SYSTEM_SECRET" \
--from-literal=secretsCookie="$HYDRA_COOKIE_SECRET" \
--from-literal=pairwise-salt="$HYDRA_PAIRWISE_SALT"
# Kratos chart (secret.enabled: true, nameOverride: kratos-secrets) creates kratos-secrets
# from Helm values — DSN is in kratos-values.yaml, random secrets generated by chart.
# This create is a no-op placeholder; chart apply overwrites with Helm-generated values.
# Devtools namespace
ensure_ns devtools
create_secret devtools gitea-db-credentials \
--from-literal=password="$DB_PASSWORD"
create_secret devtools gitea-s3-credentials \
--from-literal=access-key="$S3_ACCESS_KEY" \
--from-literal=secret-key="$S3_SECRET_KEY"
# Storage namespace
ensure_ns storage
create_secret storage seaweedfs-s3-credentials \
--from-literal=S3_ACCESS_KEY="$S3_ACCESS_KEY" \
--from-literal=S3_SECRET_KEY="$S3_SECRET_KEY"
# La Suite namespace
ensure_ns lasuite
create_secret lasuite seaweedfs-s3-credentials \
--from-literal=S3_ACCESS_KEY="$S3_ACCESS_KEY" \
--from-literal=S3_SECRET_KEY="$S3_SECRET_KEY"
create_secret lasuite hive-db-url \
--from-literal=url="postgresql://hive:${DB_PASSWORD}@postgres-rw.data.svc.cluster.local:5432/hive_db"
create_secret lasuite hive-oidc \
--from-literal=client-id="hive-local" \
--from-literal=client-secret="hive-local-secret"
# People (desk)
create_secret lasuite people-db-credentials \
--from-literal=password="$DB_PASSWORD"
create_secret lasuite people-django-secret \
--from-literal=DJANGO_SECRET_KEY="local-dev-people-django-secret-key-not-for-production"
# Media namespace
ensure_ns media
echo " Done."
# ---------------------------------------------------------------------------
# 4. Initialize and unseal OpenBao (if deployed)
# ---------------------------------------------------------------------------
echo "==> Checking OpenBao..."
OB_POD=$(kubectl $CTX -n data get pods -l app.kubernetes.io/name=openbao,component=server -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [[ -z "$OB_POD" ]]; then
echo " OpenBao pod not found, skipping."
else
# Wait for pod to be running (not necessarily ready — it won't be ready until unsealed)
kubectl $CTX -n data wait pod "$OB_POD" --for=jsonpath='{.status.phase}'=Running --timeout=120s 2>/dev/null || true
# Check if initialized
INIT_STATUS=$(kubectl $CTX -n data exec "$OB_POD" -c openbao -- bao status -format=json 2>/dev/null | grep '"initialized"' | grep -c 'true' || echo "0")
if [[ "$INIT_STATUS" != "1" ]]; then
echo "==> Initializing OpenBao..."
INIT_OUTPUT=$(kubectl $CTX -n data exec "$OB_POD" -c openbao -- bao operator init -key-shares=1 -key-threshold=1 -format=json 2>/dev/null)
UNSEAL_KEY=$(echo "$INIT_OUTPUT" | jq -r '.unseal_keys_b64[0]')
ROOT_TOKEN=$(echo "$INIT_OUTPUT" | jq -r '.root_token')
# Store keys in K8s secret
create_secret data openbao-keys \
--from-literal=key="$UNSEAL_KEY" \
--from-literal=root-token="$ROOT_TOKEN"
echo " Initialized. Keys stored in secret/openbao-keys."
else
echo " Already initialized."
# Read unseal key from existing secret
UNSEAL_KEY=$(kubectl $CTX -n data get secret openbao-keys -o jsonpath='{.data.key}' 2>/dev/null | base64 -d || echo "")
ROOT_TOKEN=$(kubectl $CTX -n data get secret openbao-keys -o jsonpath='{.data.root-token}' 2>/dev/null | base64 -d || echo "")
fi
# Unseal if sealed
SEALED=$(kubectl $CTX -n data exec "$OB_POD" -c openbao -- bao status -format=json 2>/dev/null | grep '"sealed"' | grep -c 'true' || echo "0")
if [[ "$SEALED" == "1" && -n "$UNSEAL_KEY" ]]; then
echo "==> Unsealing OpenBao..."
kubectl $CTX -n data exec "$OB_POD" -c openbao -- bao operator unseal "$UNSEAL_KEY"
echo " Unsealed."
fi
# Seed secrets into OpenBao
if [[ -n "$ROOT_TOKEN" ]]; then
echo "==> Seeding secrets into OpenBao..."
kubectl $CTX -n data exec "$OB_POD" -c openbao -- sh -c "
export BAO_ADDR=http://127.0.0.1:8200
export BAO_TOKEN='$ROOT_TOKEN'
bao secrets enable -path=secret -version=2 kv 2>/dev/null || true
bao kv put secret/postgres password='$DB_PASSWORD'
bao kv put secret/hydra db-password='$DB_PASSWORD' system-secret='$HYDRA_SYSTEM_SECRET' cookie-secret='$HYDRA_COOKIE_SECRET' pairwise-salt='$HYDRA_PAIRWISE_SALT'
bao kv put secret/kratos db-password='$DB_PASSWORD'
bao kv put secret/gitea db-password='$DB_PASSWORD' s3-access-key='$S3_ACCESS_KEY' s3-secret-key='$S3_SECRET_KEY'
bao kv put secret/seaweedfs access-key='$S3_ACCESS_KEY' secret-key='$S3_SECRET_KEY'
bao kv put secret/hive db-url='postgresql://hive:${DB_PASSWORD}@postgres-rw.data.svc.cluster.local:5432/hive_db' oidc-client-id='hive-local' oidc-client-secret='hive-local-secret'
bao kv put secret/people db-password='$DB_PASSWORD' django-secret-key='local-dev-people-django-secret-key-not-for-production'
bao kv put secret/livekit api-key='$LIVEKIT_API_KEY' api-secret='$LIVEKIT_API_SECRET'
" 2>/dev/null
echo " Done."
fi
fi
echo ""
echo "==> All secrets seeded."