Skip to content

feat(db-bootstrap): service DB credentials must be sealed in fuzeinfra namespace + bootstrap script #228

Description

@izzywdev

@claude

Priority: HIGH — production data loss risk. The fuzeinfra-namespace copies of the per-service DB password secrets (fuzesales-db-credentials, fuzecontact-db-credentials, fuzeservice-db-credentials) were created ad-hoc with kubectl create secret and are NOT in git. If the fuzeinfra namespace is ever deleted or re-provisioned from scratch, the provisioning Job will immediately wedge again (x26,000 CreateContainerConfigError — exactly what happened this week for ~4 days). Please consult Claude Opus 4.8 when deciding how to structure the long-term solution.


Context: the two-secret pattern

The provisioning Job (service-db-provisioning.yaml) reads ONE secret per service from the fuzeinfra namespace — the service's DB password (key: password). This is separate from the full credentials secret in the app namespace (DATABASE_URL, DB_HOST, etc.) which ArgoCD syncs from each app repo's deploy/sealed-secrets/.

Current state of the fuzeinfra-namespace secrets:

Secret Present in fuzeinfra ns Sealed in git
fuzesales-db-credentials ✓ (ad-hoc)
fuzecontact-db-credentials ✓ (ad-hoc)
fuzeservice-db-credentials ✓ (ad-hoc)
mendys-db-credentials ✓ (sealed, FuzeKeys #136 precedent)

Mendys is the reference implementation. Do exactly what was done for mendys for the other three.


What needs to be done

1. Add sealed secrets for the three services in this repo

For each of fuzesales, fuzecontact, fuzeservice: create a SealedSecret targeting the fuzeinfra namespace with just the password key, using the passwords currently live on the cluster:

fuzesales   password: Li1cTPDK5lj06rswzG6zzSHycNI9Mqx7
fuzecontact password: gCIh8rK7mcfJrOyNeSd707MHayVnm6r2
fuzeservice password: VJkk5y99q6K8hsfCW0EdzPoXDyGzutCp

Seal each with kubeseal --namespace fuzeinfra and commit to deploy/sealed-secrets/ (or wherever mendys-db-credentials.yaml lives — follow the same path). These must be applied before the provisioning Job runs on any fresh deployment.

2. Create scripts/seed-service-db.sh — the canonical bootstrap script

A reusable, idempotent script that does the full flow for any new service:

#!/usr/bin/env bash
# Usage: ./scripts/seed-service-db.sh <service-name> [<password>]
# If password is omitted, generates a 32-char random one.
# Creates:
#   1. SealedSecret for fuzeinfra namespace (password key only) → written to deploy/sealed-secrets/
#   2. Prints the password so the calling engineer can pass it to the app repo's own sealing step
# The calling engineer then runs the app repo's equivalent to seal the full DATABASE_URL secret.

The script should:

  • Accept SERVICE_NAME and optional PASSWORD args
  • Generate a secure 32-char password if none provided
  • Run kubeseal against the live cluster to produce deploy/sealed-secrets/<service>-db-credentials-fuzeinfra.yaml
  • Print clear instructions: "Now go to the repo and run ./scripts/seal-db-credentials.sh <password> to create the app-namespace sealed secret, then add the service to helm/fuzeinfra/values-contabo.yaml"
  • Be idempotent (check if secret already exists on cluster before creating)

3. Update ONBOARD-REPO.md / docs/ with the canonical DB provisioning flow

Add a "Database provisioning" section documenting:

  1. Run ./scripts/seed-service-db.sh <service> in FuzeInfra → get the password
  2. Run the equivalent sealing step in the app repo → get the app-namespace sealed secret
  3. Open a single PR that adds BOTH sealed secrets and flips enabled: true in values-contabo.yaml
  4. Merge → ArgoCD applies → provisioning Job runs → DB role + database created

The key invariant: never flip enabled: true without the fuzeinfra-namespace sealed secret in the same PR.

4. Reference: mendys precedent (FuzeKeys #136)

Check FuzeKeys PR #136 for the exact pattern used for mendys — the sealed secret structure, the values-contabo.yaml change, and the commit order. Mirror that for fuzesales/fuzecontact/fuzeservice.


Out of scope for this issue

  • Creating the app-namespace sealed secrets for fuzesales/fuzecontact (already exist in their repos)
  • Creating the app-namespace sealed secret for fuzeservice (tracked in FuzeService issue)

STATE:

  • Ad-hoc secrets currently live on cluster (will survive until namespace is deleted)
  • provisioning Job ran successfully after ad-hoc fix — all roles/DBs now exist
  • This issue seals the fix permanently into git

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions