Skip to main content

Secrets

No chart contains a credential. Every one is referenced by name. This page is explains what must exist, with which keys, before the platform starts.

The secrets you create

SecretNamespaceKeysCreated in
gen0sec-registryBoth.dockerconfigjsonInstall step 2
gen0sec-object-storegen0sec-systemRUSTFS_ACCESS_KEY, RUSTFS_SECRET_KEYInstall step 2
gen0sec-download-proxygen0secDOWNLOAD_PROXY_API_KEYInstall step 2

The pull secret is needed in both namespaces. The application runs in gen0sec; the operators, object store and cache run in gen0sec-system.

The twenty the script creates

make-db-secrets.sh composes one secret per service from the passwords the Postgres operator generated.

SecretContainsRole it usesEndpoint
g0s-db-<service>DATABASE_URL, plus object store keys for services that use itIts own per-service role, read-only where it only readsThe connection pooler
gen0sec-db-migrateDATABASE_URLpostgres, superuserThe primary, unpooled
g0s-db-uiDATABASE_URL, BETTER_AUTH_SECRET, object store keysfrontendThe connection pooler

Every service connects as its own role. The migration job needs a superuser on the primary because it runs CREATE EXTENSION, which an owner role cannot do.

The session signing key is preserved

g0s-db-ui carries the dashboard's session signing secret. Re-running the script keeps the existing value, so sessions and invite links stay valid across a re-run. Nothing else regenerates it.

Four services need no database connection and get no DATABASE_URL: the GeoIP updater, the GeoIP database updater, the model publisher and the rules validator.

Where the database passwords come from

The Postgres operator creates a credentials secret per role it provisions, named after the role:

<role>.core.credentials.postgresql.acid.zalan.do

Underscores in the role become dashes in the secret name.

Compose each connection string from that role's password:

postgres://<role>:<password>@core-pooler.gen0sec-system.svc.cluster.local:5432/ax_prod?sslmode=require
ConsumerRoleEndpoint
Each serviceIts own per-service rolecore-pooler
Migration jobpostgrescore, the primary, with the on-prem marker appended
Dashboardfrontendcore-pooler
One deliberate exception

The dashboard's connection string uses sslmode=no-verify. Its client library verifies the certificate chain for sslmode=require and rejects the pooler's self-signed certificate; the Go library every other service uses reads the same value as encrypt-without-verify.

Do not copy no-verify onto the other services. Their driver rejects it outright.

For production: use your secret manager

make-db-secrets.sh is fine for evaluation. In production, treat its output as a specification rather than a tool, and have your secret manager produce secrets of the same shape.

Two reasons:

  1. The script writes plain Kubernetes secrets from operator-generated passwords. Your manager should be the source of truth, with the cluster holding copies.
  2. Rotation is then a manager operation rather than a re-run plus a rollout.

An external secret can template the connection string from the operator-generated password, so nothing is copied by hand:

# shape, not a working manifest: adapt to your operator
data:
- secretKey: DATABASE_URL
remoteRef:
key: g0s-auth-api-ro.core.credentials.postgresql.acid.zalan.do
property: password
# then template: postgres://<role>:{{ .password }}@core-pooler...:5432/ax_prod?sslmode=require

To see the exact list your install needs, read it out of the values file rather than from this page:

grep -oE 'secretRef:\s*\{?\s*name:\s*[a-z0-9-]+' \
$B/values/gen0sec-platform-values-onprem.yaml | sort -u

Or inspect your live installation inside your cluster.

Rotation

CredentialHow
Database role passwordsRotate through the Postgres operator, then restart the consumers
Object store keysUpdate both gen0sec-object-store and every g0s-db-<service> that carries them, then restart the consumers
Registry pull credentialsRecreate gen0sec-registry in both namespaces. Existing pods keep running; new pulls use the new value
Your Gen0Sec API keyRecreate gen0sec-download-proxy, then restart the relay
Dashboard session keyRotating invalidates every session and every outstanding invite link
One credential pair, surfaced two ways

The object store keys appear as RUSTFS_ACCESS_KEY and RUSTFS_SECRET_KEY to the object store itself, and as AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to the services that read it. Same values, two naming conventions. Rotating means updating both places.

Verifying

Nothing should be missing before you install the platform:

$KIT/scripts/preflight.sh

After install, confirm the count:

kubectl -n gen0sec get secret | wc -l # ~20 service secrets plus the ones you created
kubectl -n gen0sec-system get secret | grep credentials | wc -l # expect 6

What is never in a secret

Where it is instead
The registry host and namespaceThe values file
The relay upstream URLThe values file
The cache connection stringThe values file, deliberately with no credential in it

If you enable authentication on the cache, remove that line from the values file and put the connection string in each service's secret instead.