From 84f5e27238542d5679b87041207a01632b7c5cee Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Fri, 4 Sep 2026 16:21:36 +0530 Subject: [PATCH] Add postgresql to appSpec and its Vault-backed credentials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One Vault path (secret/toolshed/postgres) into two namespaces: the server needs the credential to initialise, api needs it to connect. Kept in one file because it is one credential with two consumers — split, they drift, and drift surfaces as an authentication error that looks nothing like a config mistake. The api-side Secret also carries a composed libpq URL, so host, port and database name live in one place instead of across several environment variables that can disagree. Postgres gets its own namespace rather than living inside toolshed, so it is addressed over cluster DNS like any other platform component and outlives whatever consumes it. --- .../toolshed-postgres-credentials.yaml | 82 +++++++++++++++++++ ...bator-infra-k8s-admin-prd-ase1-values.yaml | 21 ++++- 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 secretstores/toolshed-postgres-credentials.yaml diff --git a/secretstores/toolshed-postgres-credentials.yaml b/secretstores/toolshed-postgres-credentials.yaml new file mode 100644 index 0000000..7d9c5fb --- /dev/null +++ b/secretstores/toolshed-postgres-credentials.yaml @@ -0,0 +1,82 @@ +# PostgreSQL credentials for toolshed, from one Vault path into two +# namespaces: the server needs them to initialise the database, and +# toolshed's api needs them to connect. Kept in one file because they are one +# credential with two consumers — splitting them invites the two drifting +# apart, which fails as an authentication error that looks nothing like a +# config mistake. +# +# Put the credential in Vault BEFORE syncing either of these. External +# Secrets cannot create a Secret for a path that does not exist, and the +# PostgreSQL pod will sit in CreateContainerConfigError until it can: +# +# kubectl -n vault exec -i vault-0 -- sh -lc ' +# vault login >/dev/null && +# vault kv put secret/toolshed/postgres \ +# username=toolshed \ +# password=' +# +# Use an alphanumeric password. It is interpolated into a libpq connection +# URL below, where @ : / ? # would need percent-encoding, and a password that +# silently truncates the URL is a genuinely unpleasant thing to debug. +# +# Remember that `kubectl exec` into Vault is unauthenticated by default — +# without the `vault login` the commands fail with a "preflight capability +# check" error that reads like a permissions bug rather than a missing login. +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postgresql-credentials + namespace: postgres +spec: + refreshInterval: 1h + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: postgresql-credentials + creationPolicy: Owner + data: + - secretKey: username + remoteRef: + key: toolshed/postgres + property: username + - secretKey: password + remoteRef: + key: toolshed/postgres + property: password +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: toolshed-db + namespace: toolshed +spec: + refreshInterval: 1h + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + target: + name: toolshed-db + creationPolicy: Owner + template: + data: + username: "{{ .username }}" + password: "{{ .password }}" + # Composed here rather than assembled in application code, so the + # host, port and database name live in one place instead of being + # spread across environment variables that can disagree. + # + # sslmode=disable is consistent with this cluster running plain HTTP + # throughout; traffic stays on the pod network. It is the first thing + # to change if this ever leaves the homelab. + url: "postgres://{{ .username }}:{{ .password }}@postgresql.postgres.svc.cluster.local:5432/toolshed?sslmode=disable" + data: + - secretKey: username + remoteRef: + key: toolshed/postgres + property: username + - secretKey: password + remoteRef: + key: toolshed/postgres + property: password diff --git a/values/incubator-infra-k8s-admin-prd-ase1-values.yaml b/values/incubator-infra-k8s-admin-prd-ase1-values.yaml index f1f8253..01a18d1 100644 --- a/values/incubator-infra-k8s-admin-prd-ase1-values.yaml +++ b/values/incubator-infra-k8s-admin-prd-ase1-values.yaml @@ -112,4 +112,23 @@ appSpec: nameOverride: harbor namespace: harbor chartDir: harbor - valuesDir: harbor \ No newline at end of file + valuesDir: harbor + - name: postgresql + # Backs toolshed's control plane. Own namespace rather than living + # inside toolshed, so it is addressed over cluster DNS like any other + # platform component and outlives whatever consumes it: + # postgresql.postgres.svc.cluster.local:5432 + # + # nameOverride pinned for the same reason as everything else here — + # without it the rendered Application (and therefore the Helm release + # name, and therefore every object name) becomes + # "postgresql-admin-prd-prd". + # + # Hand-written chart, not Bitnami's: that registry has been actively + # unstable (infra issue #4) and PostgreSQL ships no official chart. + # Requires secretstores/toolshed-postgres-credentials.yaml to have + # synced first — the pod cannot start without the Secret. + nameOverride: postgresql + namespace: postgres + chartDir: postgresql + valuesDir: postgresql \ No newline at end of file