Files
jarvis-selfhost/kubernetes/01-secret.example.yaml
T
2026-10-21 12:12:12 +02:00

84 lines
5.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# The secrets an operator writes. Minted ONCE, mounted by every pod.
#
# ─── READ THIS BEFORE YOU GENERATE ANYTHING ───────────────────────────────────────────────────
#
# There are two Secrets, and the split is not filing: `jarvis-generated` holds the values that are
# random bytes and `jarvis-secrets` — this file — holds the ones that are facts about your estate.
# One of those can be regenerated safely and the other cannot, so they do not share an object.
#
# The three keys below are here as the MANUAL path. If you would rather have them minted for you,
# apply `01-secret-job.yaml` instead and leave the `VAULT_*`/`JWT_*` lines out of this file
# entirely. Do not do both: `04-api.yaml` reads this Secret last on purpose, so a value typed here
# wins over a generated one, and the two quietly disagreeing is the shape of the accident.
#
# `jarvis init-secrets` is the Compose generator, and it must NEVER become an initContainer
# here. Its guarantee that a key is minted exactly once is every writer sharing one filesystem.
# Per-pod, on an `emptyDir`, each replica generates its own — and the consequence is not a crash.
# Pod A seals a vault credential under a key pod B does not have; pod B reports that credential as
# corrupt; both pods log nothing at boot, because from each one's point of view everything is fine.
# By the time anybody notices, there are several keys in circulation and no way to tell which
# entries belong to which. `jarvis mint-k8s-secret` is the same one-shot done correctly, with
# the API server's 409 standing in for the filesystem's exclusion.
#
# Either way, keep the output. The vault key in particular is the thing every stored credential is
# encrypted under — a database backup that travelled with its own key would be a backup that
# decrypts itself, which is why this lives apart from the database.
#
# VAULT_MASTER_KEY openssl rand -base64 32
# JWT_ACCESS_SECRET openssl rand -base64 48
# JWT_REFRESH_SECRET openssl rand -base64 48
#
# In anything beyond a trial, do not commit this file with values in it. Use SealedSecrets,
# ExternalSecrets, or `kubectl create secret generic` from a password manager.
# ──────────────────────────────────────────────────────────────────────────────────────────────
apiVersion: v1
kind: Secret
metadata:
name: jarvis-secrets
namespace: jarvis
type: Opaque
stringData:
# Everything in the vault is sealed under this. Lose it and the credentials are unreadable;
# leak it and a database dump is enough to read them all.
VAULT_MASTER_KEY: "REPLACE_ME"
JWT_ACCESS_SECRET: "REPLACE_ME"
JWT_REFRESH_SECRET: "REPLACE_ME"
# WHEN THE VAULT KEY WAS CREATED, bound to that key. Manual path only: if `01-secret-job.yaml`
# mints your key, delete this line with the other `VAULT_*` ones — left here, even as
# "REPLACE_ME", it overrides the value the Job wrote beside its key.
#
# The value is the moment you generate the key and the key's fingerprint, one space apart:
#
# FP=$(printf %s "$VAULT_MASTER_KEY" | sha256sum | cut -c1-16)
# echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) sha256:$FP"
#
# Restoring a key you backed up? Restore the value saved with it, word for word, and never compute
# a new one: today's date bound to an old key is the one mistake this line can make dangerous. A
# date without the fingerprint, or bound to another key, is ignored.
#
# On Compose this is inferred from the key file's modification time. Here there is no file: the
# api receives the key through `envFrom`, so this line is the only evidence of the key's age.
# (Mounting the Secret as a file would not do better — the kubelet writes it into every pod at
# start, so its mtime is the POD's age.)
#
# What that number decides is narrow and serious. An instance with no accounts can have its first
# super-admin claimed by whoever reaches the install screen — unless the vault key is old, which
# means the database has gone missing from an instance that already existed (a bad restore, a PVC
# pointed at the wrong volume) and the claim needs proof of possession instead. Without this line
# the age is unknown and the claim always asks for the key, which costs you nothing but its last
# characters.
VAULT_KEY_CREATED_AT: "REPLACE_ME"
# `connection_limit` is not optional here, and it is the reason this URL is in the Secret rather
# than assembled from parts. The api's pool is per-process: N pods times its default will
# exhaust `max_connections` long before the application is under any real load. Size it as
# (max_connections − reserve) ÷ (replicas + maxSurge + jobs).
DATABASE_URL: "postgresql://jarvis:REPLACE_ME@postgres.jarvis.svc.cluster.local:5432/jarvis?schema=public&connection_limit=10&pool_timeout=20"
# Required to create new organizations, users or agents. Without it an instance keeps running
# everything it already has and creates nothing new. See the project README.
JARVIS_LICENSE_KEY: ""
OPENAI_API_KEY: "REPLACE_ME"