Problem Statement
The OpenShell gateway defaults to SQLite for persistence (sqlite:/var/openshell/openshell.db). While SQLite works well for single-replica development and testing, it is not suitable for production or high-availability deployments where multiple gateway replicas need shared, durable storage with concurrent write support.
Operators deploying OpenShell in production need the option to use PostgreSQL as the backing database.
Proposed Design
Add an optional postgres section to the Helm chart values that lets operators enable PostgreSQL and choose between two modes:
Values schema
postgres:
enabled: false # Toggle SQLite → PostgreSQL
mode: "internal" # "internal" (Bitnami subchart) or "external" (bring your own)
host: "" # External mode: PostgreSQL hostname
port: 5432
database: "openshell"
username: "openshell"
password: "" # Used to populate the Kubernetes Secret
sslmode: "prefer"
Internal mode (postgres.mode: internal)
- Add the Bitnami PostgreSQL chart as an optional subchart dependency (condition:
postgres.enabled).
- Credentials flow through a generated Kubernetes Secret, not plaintext values.
External mode (postgres.mode: external)
- Operators provide
host, port, database, username, and password.
- The chart creates a Secret containing the assembled
db-url connection string.
- No subchart is deployed.
Template changes
db-secret.yaml (new): Opaque Secret containing the fully assembled postgresql:// connection string under the db-url key.
_helpers.tpl: Helper to construct the connection string from postgres values, selecting the correct host for internal vs external mode.
statefulset.yaml: When postgres.enabled, inject OPENSHELL_DB_URL from the Secret via secretKeyRef and omit the --db-url CLI flag. When disabled, pass --db-url with the SQLite path as before.
gateway-config.yaml: Conditionally omit the db_url field from the TOML config when PostgreSQL is enabled (the env var takes precedence).
Chart.yaml: Add Bitnami PostgreSQL as an optional dependency with condition: postgres.enabled.
.gitignore: Ignore deploy/helm/openshell/charts/ (subchart tarballs regenerated by helm dependency build).
tasks/helm.toml: Add helm dependency build before lint and unittest tasks so the subchart is present.
Credential management
Credentials must never appear as plaintext in rendered manifests. The chart should:
- Create an Opaque Secret with the full
postgresql:// connection string.
- Mount it into the gateway pod via
secretKeyRef on the OPENSHELL_DB_URL env var.
- Roll the StatefulSet on Secret content changes via a
checksum/db-secret pod annotation.
Alternatives Considered
- Direct
--db-url flag with PostgreSQL URL: Simpler but exposes credentials in pod spec and kubectl describe.
- External secret management only (e.g., External Secrets Operator): Too opinionated; the chart should provide a baseline Secret and allow operators to override with their own.
- ConfigMap for connection string: ConfigMaps are not suited for credential storage.
Agent Investigation
Explored the current Helm chart structure:
statefulset.yaml passes --db-url as a CLI arg with the SQLite default.
gateway-config.yaml renders a TOML config mounted at /etc/openshell/gateway.toml.
- The gateway binary accepts
OPENSHELL_DB_URL as an env var override for the database connection string.
- Existing patterns for Secret-based injection (TLS certs, JWT keys) can be followed for the database credential Secret.
Definition of Done
Problem Statement
The OpenShell gateway defaults to SQLite for persistence (
sqlite:/var/openshell/openshell.db). While SQLite works well for single-replica development and testing, it is not suitable for production or high-availability deployments where multiple gateway replicas need shared, durable storage with concurrent write support.Operators deploying OpenShell in production need the option to use PostgreSQL as the backing database.
Proposed Design
Add an optional
postgressection to the Helm chart values that lets operators enable PostgreSQL and choose between two modes:Values schema
Internal mode (
postgres.mode: internal)postgres.enabled).External mode (
postgres.mode: external)host,port,database,username, andpassword.db-urlconnection string.Template changes
db-secret.yaml(new): Opaque Secret containing the fully assembledpostgresql://connection string under thedb-urlkey._helpers.tpl: Helper to construct the connection string from postgres values, selecting the correct host for internal vs external mode.statefulset.yaml: Whenpostgres.enabled, injectOPENSHELL_DB_URLfrom the Secret viasecretKeyRefand omit the--db-urlCLI flag. When disabled, pass--db-urlwith the SQLite path as before.gateway-config.yaml: Conditionally omit thedb_urlfield from the TOML config when PostgreSQL is enabled (the env var takes precedence).Chart.yaml: Add Bitnami PostgreSQL as an optional dependency withcondition: postgres.enabled..gitignore: Ignoredeploy/helm/openshell/charts/(subchart tarballs regenerated byhelm dependency build).tasks/helm.toml: Addhelm dependency buildbefore lint and unittest tasks so the subchart is present.Credential management
Credentials must never appear as plaintext in rendered manifests. The chart should:
postgresql://connection string.secretKeyRefon theOPENSHELL_DB_URLenv var.checksum/db-secretpod annotation.Alternatives Considered
--db-urlflag with PostgreSQL URL: Simpler but exposes credentials in pod spec andkubectl describe.Agent Investigation
Explored the current Helm chart structure:
statefulset.yamlpasses--db-urlas a CLI arg with the SQLite default.gateway-config.yamlrenders a TOML config mounted at/etc/openshell/gateway.toml.OPENSHELL_DB_URLas an env var override for the database connection string.Definition of Done
postgres.enabled=false(default) preserves existing SQLite behavior with no changespostgres.mode=internaldeploys Bitnami PostgreSQL subchart with credentials in a Secretpostgres.mode=externalcreates a Secret from user-provided connection detailsOPENSHELL_DB_URLenv var is injected from the Secret, not from plaintext valueshelm lintpasses for default, internal, and external configurationshelm unittestcovers all three configuration variantspostgres.*values