Skip to content

feat(helm): add optional PostgreSQL backing store for gateway persistence #1599

@sauagarwa

Description

@sauagarwa

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:

  1. Create an Opaque Secret with the full postgresql:// connection string.
  2. Mount it into the gateway pod via secretKeyRef on the OPENSHELL_DB_URL env var.
  3. 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

  • postgres.enabled=false (default) preserves existing SQLite behavior with no changes
  • postgres.mode=internal deploys Bitnami PostgreSQL subchart with credentials in a Secret
  • postgres.mode=external creates a Secret from user-provided connection details
  • OPENSHELL_DB_URL env var is injected from the Secret, not from plaintext values
  • helm lint passes for default, internal, and external configurations
  • helm unittest covers all three configuration variants
  • Chart README documents the new postgres.* values

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions