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