infisical icon indicating copy to clipboard operation
infisical copied to clipboard

improve helm chart templating to dynamically create connection url for postgresql and redis from credential secrets

Open chakraborty29 opened this issue 9 months ago โ€ข 6 comments

Description ๐Ÿ“ฃ

#3408 This change addresses new improvements with the PostgreSQL and Redis connection configuration in the Infisical Helm chart:

  1. Added support for building PostgreSQL & Redis connection URI string from secrets
  2. Added SSL connection support with configurable SSL mode and root certificate path for Postgres
  3. Added documentation to the helm-chart which identifies the new configureable parameters

Type โœจ

  • [ ] Bug fix
  • [ ] New feature
  • [x] Improvement
  • [ ] Breaking change
  • [x] Documentation

Tests ๐Ÿ› ๏ธ

First test is to do a dry-run with the new values.yaml and inspect the deployment and the job variables to see if the postgres and redis URIs have been populated correctly

values.yaml
infisical:
  enabled: true # -- Enable Infisical chart deployment
  name: infisical # -- Sets the name of the deployment within this chart

  # -- Number of pod replicas for high availability
  replicaCount: 3

  image:
    repository: infisical/infisical
    # -- Specific version tag of the Infisical image. View the latest version here https://hub.docker.com/r/infisical/infisical
    tag: "v0.122.0-postgres"

  kubeSecretRef: "infisical-secrets"

  resources:
    limits:
      memory: 600Mi
    requests:
      cpu: 350m

  extraVolumes:
    - name: postgres-ca-cert
      secret:
        secretName: self-signed-ca-key-pair
        items:
          - key: ca.crt
            path: postgres-ca.crt
  
  extraVolumeMounts:
    - name: postgres-ca-cert
      mountPath: /etc/custom-certs
      readOnly: true

ingress:
  enabled: false
  nginx:
    enabled: false

postgresql:
  # -- Enables an in-cluster PostgreSQL deployment. To achieve HA for Postgres, we recommend deploying https://github.com/zalando/postgres-operator instead.
  enabled: false

  customURIParameters:
    enabled: true
    host: "pg-infisical-rw.infisical.svc.cluster.local"
    port: "5432"
    database: "pg-infisical"
    username:"pg-infisical-admin"
    passwordSecret:
      name: "infisical-pg-admin-credentials-secret"
      key: "password"
    ssl:
      enabled: true
      mode: "verify-ca"
      rootCertPath: "/etc/custom-certs/postgres-ca.crt"

redis:
  enabled: false
  
  # -- Build a custom Redis connection string from parameters
  customURIParameters:
  # -- Set to true if using custom URI parameters for Redis connection
    enabled: true
    # -- Redis host
    host: "redis-infisical-master.infisical.svc.cluster.local"
    # -- Port for Redis connection. Default is 6379
    port: 6379
    # -- Secret containing Redis password
    passwordSecret:
      # -- Kubernetes secret name containing the Redis password
      name: "infisical-redis-admin-credentials-secret"
      # -- Key name in the Kubernetes secret that holds the Redis password
      key: "redis-password"

Then run:

helm install infisical-test ./infisical-standalone --dry-run --debug -f values.yaml > rendered.yaml

Then inspect:

rendered.yaml - Deployment
# Source: infisical-standalone/templates/infisical.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: infisical-test-infisical-standalone-infisical
  ...
  labels:
    component: "infisical"
    app: infisical-standalone
    release: infisical-test
    chart: infisical-standalone-1.5.0
    heritage: Helm
spec:
  replicas: 3
  ...
  template:
    ...
    spec:
      serviceAccountName: infisical-test-infisical
      initContainers:
      - name: "migration-init"
        image: "ghcr.io/groundnuty/k8s-wait-for:no-root-v2.0"
        imagePullPolicy: IfNotPresent
        args: 
        - "job"
        - "infisical-test-schema-migration-1"
        volumeMounts:
          - mountPath: /etc/custom-certs
            name: postgres-ca-cert
            readOnly: true
      containers:
      - name: infisical-standalone-infisical
        image: "infisical/infisical:v0.122.0-postgres"
        ...
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: infisical-pg-admin-credentials-secret
              key: password
        - name: DB_CONNECTION_URI
          value: "postgresql://pg-infisical-admin:$(DB_PASSWORD)@pg-infisical-rw.infisical.svc.cluster.local:5432/pg-infisical?sslmode=verify-ca&sslrootcert=/etc/custom-certs/postgres-ca.crt"
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: infisical-redis-admin-credentials-secret
              key: redis-password
        - name: REDIS_URL
          value: "redis://default:$(REDIS_PASSWORD)@redis-infisical-master.infisical.svc.cluster.local:6379"
        envFrom:
        - secretRef:
            name: infisical-secrets
        ...
        volumeMounts:
          - mountPath: /etc/custom-certs
            name: postgres-ca-cert
            readOnly: true
      volumes:
        - name: postgres-ca-cert
          secret:
            items:
            - key: ca.crt
              path: postgres-ca.crt
            secretName: self-signed-ca-key-pair
rendered.yaml - Job
# Source: infisical-standalone/templates/schema-migration-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: "infisical-test-schema-migration-1"
  labels:
    helm.sh/chart: "infisical-standalone-1.5.0"
spec:
  ...
  template:
    metadata:
      name: "infisical-test-create-tables"
      ...
    spec:
      serviceAccountName: infisical-test-infisical
      restartPolicy: OnFailure
      volumes:
        - name: postgres-ca-cert
          secret:
            items:
            - key: ca.crt
              path: postgres-ca.crt
            secretName: self-signed-ca-key-pair
      containers:
        - name: infisical-schema-migration
          image: "infisical/infisical:v0.122.0-postgres"
          command: ["npm", "run", "migration:latest"]
          volumeMounts:
            - mountPath: /etc/custom-certs
              name: postgres-ca-cert
              readOnly: true
          env:
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: infisical-pg-admin-credentials-secret
                key: password
          - name: DB_CONNECTION_URI
            value: "postgresql://pg-infisical-admin:$(DB_PASSWORD)@pg-infisical-rw.infisical.svc.cluster.local:5432/pg-infisical?sslmode=verify-ca&sslrootcert=/etc/custom-certs/postgres-ca.crt"
          envFrom:
          - secretRef:
              name: infisical-secrets

Additional Tests

Follow my documentation on how to get Infisical up and running with cloudnative-pg with TLS support and proper secret management with the helm chart from this PR.

Following these steps yields me to be able to open Infisical in my browser: image

After creating an account: image


Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added customizable connection settings for PostgreSQL and Redis, including credential management, host/port, and SSL/TLS options.
    • Enabled mounting of additional volumes for enhanced security, such as custom CA certificates.
    • Enhanced environment variable configuration for deployment and migration jobs to support flexible connection strings.
  • Documentation

    • Updated Helm chart README with detailed instructions and examples for new database and cache configuration parameters.

chakraborty29 avatar Apr 13 '25 21:04 chakraborty29

Walkthrough

This pull request updates the Infisical Helm chart by introducing new customURIParameters configuration options for PostgreSQL and Redis. These options allow users to specify custom connection parameters such as username, password (via Kubernetes secrets), host, port, and database name. For PostgreSQL, SSL settings including enablement, SSL mode, and root certificate path are also configurable. The Helm chart templates are modified to conditionally set environment variables for database and Redis connection strings and passwords based on these custom parameters when enabled. Additionally, the schema migration job is enhanced with support for extra Kubernetes volumes and volume mounts to facilitate mounting custom CA certificates for PostgreSQL TLS verification. Two new Helm template helpers are added to generate connection strings from the custom URI parameters for PostgreSQL and Redis. New configuration options extraVolumes and extraVolumeMounts are introduced to allow mounting additional volumes into the Infisical pod.

[!TIP]

โšก๐Ÿ’ฌ Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

๐Ÿ“œ Recent review details

Configuration used: CodeRabbit UI Review profile: CHILL Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 04d434c354461d22f21fe4b9436040d7ce31236f and 11cecfc7adfd8757e7bbd76af29c75eff812074e.

๐Ÿ“’ Files selected for processing (1)
  • helm-charts/infisical-standalone-postgres/README.md (2 hunks)
๐Ÿšง Files skipped from review as they are similar to previous changes (1)
  • helm-charts/infisical-standalone-postgres/README.md

๐Ÿชง Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

coderabbitai[bot] avatar Apr 13 '25 21:04 coderabbitai[bot]

I want to be able to use the PostgreSQL sub-chart with an existing secret. Currently, when .Values.postgresql.enabled: true the helper method will be used to fill the environment variable. That one uses the .Values.portgresql.auth.password which is really confusing when using .Values.portgresql.auth.existingSecret instead, because it will still use "root" as password in the deployment and migrator.

philipsens avatar Apr 15 '25 14:04 philipsens

I want to be able to use the PostgreSQL sub-chart with an existing secret. Currently, when .Values.postgresql.enabled: true the helper method will be used to fill the environment variable. That one uses the .Values.portgresql.auth.password which is really confusing when using .Values.portgresql.auth.existingSecret instead, because it will still use "root" as password in the deployment and migrator.

I understand what you are saying, however there are limitation to this part. The Bitnami PostgreSQL chart expects configuration values under specific paths, .Values.postgresql.auth.username, .Values.postgresql.auth.password, and .Values.postgresql.auth.database are passed directly to create and configure the PostgreSQL instance. The sub-chart I believe should be used more for development purposes, so we can easily bootstrap a password to test.

For production, this is not the best practice, hence you should have an external postgres cluster, which is where I am trying to make improvements with this PR, so you can create a more secure connection with secrets, and be able to rotate those secrets in the future without having to deal with updating the DB URI.

chakraborty29 avatar Apr 16 '25 02:04 chakraborty29

Actionable comments posted: 1

๐Ÿงน Nitpick comments (1)

helm-charts/infisical-standalone-postgres/templates/_helpers.tpl (1)> 93-107: Well-structured PostgreSQL connection string helper with secure password handling.

The new helper effectively builds PostgreSQL connection strings from custom parameters with SSL support. Using the ${DB_PASSWORD} placeholder enables secure injection of credentials at runtime. Consider adding parameter validation to ensure all required fields are present before constructing the connection string. This would prevent potentially malformed connection strings if a user misconfigures values.

{{- define "infisical.customPostgresDBConnectionString" -}}
{{- if .Values.postgresql.customURIParameters.enabled -}}
{{- $pgParams := .Values.postgresql.customURIParameters -}}
+{{- if and $pgParams.username $pgParams.host $pgParams.port $pgParams.database -}}
{{- $sslParams := "" -}}
{{- if $pgParams.ssl.enabled -}}
+{{- if and $pgParams.ssl.mode $pgParams.ssl.rootCertPath -}}
{{- $sslParams = printf "?sslmode=%s&sslrootcert=%s" $pgParams.ssl.mode $pgParams.ssl.rootCertPath -}}
+{{- else -}}
+{{- $sslParams = printf "?sslmode=disable" -}}
+{{- end -}}
{{- end -}}
{{- printf "postgresql://%s:${DB_PASSWORD}@%s:%s/%s%s" $pgParams.username $pgParams.host $pgParams.port $pgParams.database $sslParams -}}
+{{- else -}}
+{{- fail "PostgreSQL custom URI parameters missing required fields (username, host, port, database)" -}}
+{{- end -}}
{{- else -}}
{{- print "" -}}
{{- end -}}
{{- end -}}

๐Ÿ“œ Review details

The logic to set the ssl disable was a really good catch, after testing this is the value when postgres.customURIParameters.ssl.enable is set to false.

- name: DB_CONNECTION_URI
  value: postgresql://pg-infisical-admin:${DB_PASSWORD}@pg-infisical-rw.infisical.svc.cluster.local:5432/pg-infisical?sslmode=disable

chakraborty29 avatar Apr 16 '25 03:04 chakraborty29

the {ENV_VAR} syntax is wrong, and is throwing errors when running the second test, actually deploying Infisical to a Kubernetes cluster. I will continue testing and fix any remaining bugs and make sure I am able to deploy using the new settings and original settings

chakraborty29 avatar Apr 16 '25 04:04 chakraborty29

After reviewing the bugs, and running both tests (Dry Run & Full Deployment), I have been able to successfully deploy Infisical in a Kubernetes Cluster with Custom URI Parameters. With the new updates I've moved the functionality of dynamically creating the URI to _helpers.tpl and kept the templates cleaner.

Along with the testing, I've Identified the following case where the redis username must be set to default, or else we get the following error thrown:

[ioredis] Unhandled error event: ReplyError: WRONGPASS invalid username-password pair or user is disabled.
    at parseError (/backend/node_modules/redis-parser/lib/parser.js:179:12)
    at parseType (/backend/node_modules/redis-parser/lib/parser.js:302:14)
[ioredis] Unhandled error event: ReplyError: WRONGPASS invalid username-password pair or user is disabled.
    at parseError (/backend/node_modules/redis-parser/lib/parser.js:179:12)
    at parseType (/backend/node_modules/redis-parser/lib/parser.js:302:14)
ReplyError: WRONGPASS invalid username-password pair or user is disabled.
    at parseError (/backend/node_modules/redis-parser/lib/parser.js:179:12)
    at parseType (/backend/node_modules/redis-parser/lib/parser.js:302:14) {
  command: { name: 'auth', args: [ 'joe', 'infisical-pg-admin' ] }
}

This is related to the following issue with bitnami/redis: https://github.com/bitnami/charts/issues/7709 - the bitnami/redis chart does not support any username, and default is the default username for redis instances. Unless someone has a use-case for custom redis username, I don't see the need to implement something we can't really test.

Below you will find screenshots from my deployment and screenshots of being able to access the infisical deployment in the browser to a domain name and create our superuser.

Lens: image

Super User Sign Up: image

Logged in: image

Let me know if there is anything else I can do to improve this PR!

chakraborty29 avatar Apr 16 '25 06:04 chakraborty29