Self-Signed TLS/SSL certs for connection to Postgres and Redis
I am trying to deploy a HA Infisical on-premise with K8s and looking to follow the reference architecture but I am struggling to find documentation on how to use my own self-signed certificates to secure the connection between the Infiscal app and my cloudnative-pg postgres instance.
My initial thoughts are with the useExistingPostgresSecret in the helm chart
useExistingPostgresSecret:
# -- Set to true if using an existing Kubernetes secret that contains PostgreSQL connection string
enabled: false
existingConnectionStringSecret:
# -- Kubernetes secret name containing the PostgreSQL connection string
name: ""
# -- Key name in the Kubernetes secret that holds the connection string
key: ""
Where the connection string can be set like this:
postgresql://${USERNAME}:${PASSWORD}@${DB_HOST}:5432/${DB_NAME}?ssl=true&sslmode=verify-full&sslrootcert=${SSL_ROOT_CERT_PATH}
But with cloudnative-pg the secret that hosts the username and password is already created, and you can't reference a secrete in a secret. Limiting the postgres connection to just a URI makes this customization much more difficult. Along with the fact that the helm chart doesn't provide anything on mounting volumes or extra secrets to allow extra parameters for postgres or redis.
Authentik's configuration does a good job with connections to posgres and redis with TLS. It would be nice to see something like this for Infiscal.
I am currently testing a solution which seems to be promising, as I refine it I will open a PR. The updated will entail the following changes to the helm chart templating to allow custom URI parameters to let helm construct the DB_CONNECTION_URI string based on passed in secrets to keep the DB username and passwords a secret, and to able to pass in custom sslrootcert from a kubernetes secret.
infisical.yaml
...
env:
{{- if and .Values.postgresql.useExistingPostgresSecret.enabled .Values.postgresql.useExistingPostgresSecret.customURIParameters.enabled }}
{{- $pgParams := .Values.postgresql.useExistingPostgresSecret.customURIParameters }}
- name: DB_USER
valueFrom:
secretKeyRef:
name: {{ $pgParams.usernameSecret.name }}
key: {{ $pgParams.usernameSecret.key }}
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $pgParams.passwordSecret.name }}
key: {{ $pgParams.passwordSecret.key }}
- name: DB_CONNECTION_URI
{{- $sslParams := "" }}
{{- if and $pgParams.ssl.enabled $pgParams.ssl.mode }}
{{- $sslParams = printf "?sslmode=%s&sslrootcert=%s" $pgParams.ssl.mode $pgParams.ssl.rootCertPath }}
{{- end }}
value: "postgresql://$(DB_USER):$(DB_PASSWORD)@{{ $pgParams.host }}:{{ $pgParams.port }}/{{ $pgParams.database }}{{ $sslParams }}"
{{- else if .Values.postgresql.useExistingPostgresSecret.enabled }}
...
Now to pass in custom parameters in values.yaml:
useExistingPostgresSecret:
...
customURIParameters:
# -- Set to true if using custom URI parameters for PostgreSQL connection
enabled: false
# -- Hostname for PostgreSQL connection
host: ""
# -- Port for PostgreSQL connection. Default is 5432
port: 5432
# -- Database name for PostgreSQL connection
database: ""
usernameSecret:
# -- Kubernetes secret name containing the PostgreSQL username
name: ""
# -- Key name in the Kubernetes secret that holds the PostgreSQL username
key: ""
passwordSecret:
# -- Kubernetes secret name containing the PostgreSQL password
name: ""
# -- Key name in the Kubernetes secret that holds the PostgreSQL password
key: ""
ssl:
# -- Set to true if using SSL for PostgreSQL connection
enabled: false
# -- SSL mode for PostgreSQL connection. Default is "verify-ca"
mode: "verify-ca"
# -- Path to the Root CA certificate file for SSL connection. Default is "/etc/postgres-certs/ca.crt"
rootCertPath: "/etc/postgres-certs/ca.crt"
To pass in the sslrootcert, we need to mount the cert:
infisical:
...
extraVolumes:
- name: postgres-ca-cert
secret:
secretName: custom-ca
items:
- key: ca.crt
path: ca.crt
extraVolumeMounts:
- name: postgres-ca-cert
mountPath: /etc/postgres-certs
readOnly: true
To test the change, I ran the following command:
helm install infisical-test ./infisical-standalone --dry-run --debug -f values.yaml > rendered.yaml
And the output of rendered.yaml to verify that this worked:
# Source: infisical-standalone/templates/infisical.yaml
apiVersion: apps/v1
kind: Deployment
...
spec:
...
template:
...
spec:
...
containers:
...
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: pg-infisical-admin-credentials-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: pg-infisical-admin-credentials-secret
key: password
- name: DB_CONNECTION_URI
value: "postgresql://$(DB_USER):$(DB_PASSWORD)@pg-infisical-rw.infisical.svc.cluster.local:5432/pg-infisical?sslmode=verify-ca&sslrootcert=/etc/postgres-certs/ca.crt"
We can implement similar updates to the template for read replicas and for redis.
Would love to hear your thoughts on this @maidul98 , I think this feature would make implementing the K8s HA reference architecture a lot more secure and managing the "secret zero" to the database that will hold the cluster secrets a lot more secure.
What's the proper URI to use for Redis using TLS with self-signed certs? I don't want my connections to Redis using cleartext either.