From d18b690a8fcf07617ac4fa6915548ebc0d8140dd Mon Sep 17 00:00:00 2001 From: "David Muto (pseudomuto)" Date: Wed, 9 Oct 2024 23:37:23 -0400 Subject: [PATCH] [Helm]: Generalize Password Lookup Generalizing the secret lookup functionality that was added in #753 to work for `admin_password`, `auth_query_password`, `server_password`, and really any other one. It works by creating a `pgcat.password` template which expects an object containing values for the `password` and `secret` keys. `password` is a literal value normally supplied via `.Values.xyz` value. `secret` is an object with a key and name property that effectively functions like a _secretKeyRef_. When the literal value is not blank, that is used. Otherwise an attempt is made to lookup to supplied key from the named secret and use that. This is exactly how the current implementation of `user_password` works, which avoids any breaking changes. See the function definition for more details. > Note: it seems like `user_passwordSecret` was added (camelCase name) while all the other ones are _snake_case_. I elected to use snake case for the new values, but left `user_passwordSecret` as is to avoid any breaking changes. --- charts/pgcat/Chart.yaml | 2 +- charts/pgcat/templates/_helpers.tpl | 31 +++++++++++++++ charts/pgcat/templates/secret.yaml | 24 +++++------- charts/pgcat/values.yaml | 59 +++++++++++++++++++++-------- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/charts/pgcat/Chart.yaml b/charts/pgcat/Chart.yaml index 49df3e11..bf04fbe1 100644 --- a/charts/pgcat/Chart.yaml +++ b/charts/pgcat/Chart.yaml @@ -5,4 +5,4 @@ maintainers: - name: Wildcard email: support@w6d.io appVersion: "1.2.0" -version: 0.2.1 +version: 0.3.0 diff --git a/charts/pgcat/templates/_helpers.tpl b/charts/pgcat/templates/_helpers.tpl index 07c2d25f..f9a404dc 100644 --- a/charts/pgcat/templates/_helpers.tpl +++ b/charts/pgcat/templates/_helpers.tpl @@ -60,3 +60,34 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Defines a password function which will assign the appropriate password to the supplied key. + +It will use the literal value from `.password` if it is present. Otherwise it will fetch the value from the +specified secret and use that. + +If the password is blank, and the secret object does not contain both name and key properties this returns `""`. +Similarly, if the secret lookup fails, this also returns `""`. + +NB: For this lookup to succeed, the secret must already be defined. Notably this means that it's not likely to be +managed directly by this chart. It also means that changes to the secret require an upgrade of the release, since the +value of the secret is effectively copied into this manifest. + +Args: + * password = The plaintext password + * secret = An object (key and name) to use as essentially as a secretKeyRef +*/}} +{{- define "pgcat.password" -}} +{{- if .password }} +{{- .password | quote }} +{{- else if and .secret.name .secret.key }} +{{- $secret := (lookup "v1" "Secret" $.Release.Namespace .secret.name) }} +{{- if $secret }} +{{- $password := index $secret.data .secret.key | b64dec }} +{{- $password | quote }} +{{- else }} +"" +{{- end }} +{{- end }} +{{- end -}} diff --git a/charts/pgcat/templates/secret.yaml b/charts/pgcat/templates/secret.yaml index 358f4e97..8d0d2ed5 100644 --- a/charts/pgcat/templates/secret.yaml +++ b/charts/pgcat/templates/secret.yaml @@ -31,11 +31,11 @@ stringData: tls_private_key = "{{ .Values.configuration.general.tls_private_key }}" {{- end }} admin_username = {{ .Values.configuration.general.admin_username | quote }} - admin_password = {{ .Values.configuration.general.admin_password | quote }} + admin_password = {{ include "pgcat.password" (dict "password" .Values.configuration.general.admin_password "secret" .Values.configuration.general.admin_password_secret) }} {{- if and .Values.configuration.general.auth_query_user .Values.configuration.general.auth_query_password .Values.configuration.general.auth_query }} auth_query = {{ .Values.configuration.general.auth_query | quote }} auth_query_user = {{ .Values.configuration.general.auth_query_user | quote }} - auth_query_password = {{ .Values.configuration.general.auth_query_password | quote }} + auth_query_password = {{ include "pgcat.password" (dict "password" .Values.configuration.general.auth_query_password "secret" .Values.configuration.general.auth_query_password_secret) }} {{- end }} {{- range $pool := .Values.configuration.pools }} @@ -59,26 +59,20 @@ stringData: ## [pools.{{ $pool.name | quote }}.users.{{ $index }}] username = {{ $user.username | quote }} - {{- if $user.password }} - password = {{ $user.password | quote }} - {{- else if and $user.passwordSecret.name $user.passwordSecret.key }} - {{- $secret := (lookup "v1" "Secret" $.Release.Namespace $user.passwordSecret.name) }} - {{- if $secret }} - {{- $password := index $secret.data $user.passwordSecret.key | b64dec }} - password = {{ $password | quote }} - {{- end }} - {{- end }} + password = {{ include "pgcat.password" (dict "password" $user.password "secret" $user.passwordSecret) }} pool_size = {{ $user.pool_size }} statement_timeout = {{ default 0 $user.statement_timeout }} min_pool_size = {{ default 3 $user.min_pool_size }} {{- if $user.server_lifetime }} server_lifetime = {{ $user.server_lifetime }} {{- end }} - {{- if and $user.server_username $user.server_password }} + {{- if $user.server_username }} server_username = {{ $user.server_username | quote }} - server_password = {{ $user.server_password | quote }} - {{- end }} - {{- end }} + server_password = {{ include "pgcat.password" (dict "password" $user.server_password "secret" $user.server_password_secret) }} + {{- end }} + + {{/* end range users */}} + {{- end }} {{- range $index, $shard := $pool.shards }} diff --git a/charts/pgcat/values.yaml b/charts/pgcat/values.yaml index 20a4e27b..a5ef2ca0 100644 --- a/charts/pgcat/values.yaml +++ b/charts/pgcat/values.yaml @@ -65,7 +65,8 @@ podAnnotations: {} ## @param podSecurityContext.enabled Enabled PgCat pods' Security Context ## @param podSecurityContext.fsGroup Set PgCat pod's Security Context fsGroup ## -podSecurityContext: {} +podSecurityContext: + {} # fsGroup: 2000 ## PgCat pods' Security Context @@ -75,7 +76,8 @@ podSecurityContext: {} ## @param containerSecurityContext.runAsUser Set PgCat container's Security Context runAsUser ## @param containerSecurityContext.runAsNonRoot Set PgCat container's Security Context runAsNonRoot ## -containerSecurityContext: {} +containerSecurityContext: + {} # capabilities: # drop: # - ALL @@ -94,7 +96,8 @@ service: ingress: enabled: false className: "" - annotations: {} + annotations: + {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: @@ -170,16 +173,16 @@ configuration: connect_timeout: 5000 # How long an idle connection with a server is left open (ms). - idle_timeout: 30000 # milliseconds + idle_timeout: 30000 # milliseconds # Max connection lifetime before it's closed, even if actively used. - server_lifetime: 86400000 # 24 hours + server_lifetime: 86400000 # 24 hours # Whether to use TLS for server connections or not. server_tls: false # How long a client is allowed to be idle while in a transaction (ms). - idle_client_in_transaction_timeout: 0 # milliseconds + idle_client_in_transaction_timeout: 0 # milliseconds # @param configuration.general.healthcheck_timeout How much time to give `SELECT 1` health check query to return with a result (ms). healthcheck_timeout: 1000 @@ -191,7 +194,7 @@ configuration: shutdown_timeout: 60000 # @param configuration.general.ban_time For how long to ban a server if it fails a health check (seconds). - ban_time: 60 # seconds + ban_time: 60 # seconds # @param configuration.general.log_client_connections If we should log client connections log_client_connections: false @@ -205,9 +208,15 @@ configuration: tls_certificate: "-" tls_private_key: "-" - # Credentials to access the virtual administrative database (pgbouncer or pgcat) + # Username used to access the virtual administrative database (pgbouncer or pgcat) # Connecting to that database allows running commands like `SHOW POOLS`, `SHOW DATABASES`, etc.. admin_username: "postgres" + + # Password to be used for administrative queries. + # + # @param configuration.general.admin_password + # @param configuration.general.admin_password_password_secret.name Name of the secret containing the password + # @param configuration.general.admin_password_password_secret.key Key in the secret containing the password admin_password: "postgres" # Query to be sent to servers to obtain the hash used for md5 authentication. The connection will be @@ -227,6 +236,8 @@ configuration: # in the pool. This parameter is inherited by every pool and can be redefined in pool configuration. # # @param configuration.general.auth_query_password + # @param configuration.general.auth_query_password_secret.name Name of the secret containing the password + # @param configuration.general.auth_query_password_secret.key Key in the secret containing the password auth_query_password: null # Number of seconds of connection idleness to wait before sending a keepalive packet to the server. @@ -244,14 +255,28 @@ configuration: ## For the example below a client can connect using "postgres://sharding_user:sharding_user@pgcat_host:pgcat_port/sharded" ## @param [object] pools: - [{ - name: "simple", pool_mode: "transaction", - users: [{username: "user", password: "pass", pool_size: 5, statement_timeout: 0}], - shards: [{ - servers: [{host: "postgres", port: 5432, role: "primary"}], - database: "postgres" - }] - }] + [ + { + name: "simple", + pool_mode: "transaction", + users: + [ + { + username: "user", + password: "pass", + pool_size: 5, + statement_timeout: 0, + }, + ], + shards: + [ + { + servers: [{ host: "postgres", port: 5432, role: "primary" }], + database: "postgres", + }, + ], + }, + ] # - ## default values # ## # ## @@ -322,6 +347,8 @@ configuration: # ## @param users[0].passwordSecret.name Name of the secret containing the password # ## @param users[0].passwordSecret.key Key in the secret containing the password # ## @param users[0].pool_size Maximum number of server connections that can be established for this user + # ## @param users[0].server_password_secret.name Name of the secret containing the server password + # ## @param users[0].server_password_secret.key Key in the secret containing the server password # ## @param users[0].statement_timeout Maximum query duration. Dangerous, but protects against DBs that died in a non-obvious way. # users: [] # # - username: "user"