Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: v1
name: pgdog
version: v0.90
version: v0.91
appVersion: "v0.1.60"
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,12 @@ externalSecrets:
The chart can inject values from existing Kubernetes Secrets into the PgDog
container's environment:

| Setting | Environment variable | Default Secret key |
| -------------------------- | ------------------------ | ------------------ |
| `control.endpointSecret` | `PGDOG_CONTROL_ENDPOINT` | `endpoint` |
| `control.tokenSecret` | `PGDOG_CONTROL_TOKEN` | `token` |
| `otel.datadogApiKeySecret` | `DD_API_KEY` | `dd-api-key` |
| Setting | Environment variable | Default Secret key |
| ----------------------------- | ------------------------ | ------------------ |
| `control.endpointSecret` | `PGDOG_CONTROL_ENDPOINT` | `endpoint` |
| `control.tokenSecret` | `PGDOG_CONTROL_TOKEN` | `token` |
| `otel.datadogApiKeySecret` | `DD_API_KEY` | `dd-api-key` |
| `vault.approleSecretIdSecret` | `VAULT_SECRET_ID` | `secret-id` |

#### Example

Expand Down
27 changes: 27 additions & 0 deletions templates/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,33 @@ data:
column = {{ .Values.multiTenant.column | quote }}
{{- end }}

{{- with .Values.vault }}
[vault]
url = {{ required "vault.url is required" .url | quote }}
auth_method = {{ required "vault.authMethod is required" .authMethod | quote }}
{{- if .authMount }}
auth_mount = {{ .authMount | quote }}
{{- end }}
{{- if .namespace }}
namespace = {{ .namespace | quote }}
{{- end }}
{{- if .kubernetesRole }}
kubernetes_role = {{ .kubernetesRole | quote }}
{{- end }}
{{- if .kubernetesJwtPath }}
kubernetes_jwt_path = {{ .kubernetesJwtPath | quote }}
{{- end }}
{{- if .approleRoleId }}
approle_role_id = {{ .approleRoleId | quote }}
{{- end }}
{{- if .approleSecretIdFile }}
approle_secret_id_file = {{ .approleSecretIdFile | quote }}
{{- end }}
{{- if hasKey . "clientTokenTtl" }}
client_token_ttl = {{ include "pgdog.intval" .clientTokenTtl }}
{{- end }}
{{- end }}

{{- if .Values.otel }}
[otel]
{{- if hasKey .Values.otel "endpoint" }}
Expand Down
11 changes: 11 additions & 0 deletions templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ spec:
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.vault }}
{{- with .approleSecretIdSecret }}
{{- if .name }}
- name: VAULT_SECRET_ID
valueFrom:
secretKeyRef:
name: {{ .name }}
key: {{ .key | default "secret-id" }}
{{- end }}
{{- end }}
{{- end }}
{{- range .Values.env }}
{{- if ne .name "NODE_ID" }}
- {{- toYaml . | nindent 14 }}
Expand Down
9 changes: 9 additions & 0 deletions templates/secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ server_iam_region = {{ .serverIamRegion | quote }}
{{- if .serverIamAssumeRole }}
server_iam_assume_role = {{ .serverIamAssumeRole | quote }}
{{- end }}
{{- if .serverVaultPath }}
server_vault_path = {{ .serverVaultPath | quote }}
{{- end }}
{{- if .vaultRefreshPercent }}
vault_refresh_percent = {{ .vaultRefreshPercent }}
{{- end }}
{{- if .vaultPath }}
vault_path = {{ .vaultPath | quote }}
{{- end }}
{{- end }}
{{- end -}}

Expand Down
51 changes: 51 additions & 0 deletions test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,57 @@ else
exit 1
fi

# Validate Vault settings render into pgdog.toml, users.toml and the env
echo ""
echo "==> Validating Vault settings..."
vault_manifests=$(helm template test-release "$CHART_DIR" -f "$TEST_DIR/values-vault.yaml")
vault_config=$(echo "$vault_manifests" \
| yq -r 'select(.kind == "ConfigMap" and .metadata.name == "test-release-pgdog") | .data["pgdog.toml"]')
vault_users=$(echo "$vault_manifests" \
| yq -r 'select(.kind == "Secret" and .metadata.name == "test-release-pgdog") | .data["users.toml"]' \
| base64 -d)
vault_env=$(echo "$vault_manifests" \
| yq -o=json -I=0 'select(.kind == "Deployment") | .spec.template.spec.containers[0].env[] | select(.name == "VAULT_SECRET_ID")')

for expected in \
'[vault]' \
'url = "https://vault.internal:8200"' \
'auth_method = "approle"' \
'auth_mount = "pgdog-approle"' \
'namespace = "team-a"' \
'approle_role_id = "4f8e2c1a-role-id"' \
'client_token_ttl = 120'; do
if ! echo "$vault_config" | grep -qF "$expected"; then
echo " FAIL: pgdog.toml is missing: $expected"
echo " Got: $vault_config"
exit 1
fi
done
echo " [vault] section rendered correctly"

for expected in \
'server_auth = "vault_dynamic"' \
'server_vault_path = "database/creds/pgdog-role"' \
'vault_refresh_percent = 75' \
'server_auth = "vault_static"' \
'server_vault_path = "database/static-creds/pgdog-static-role"' \
'vault_path = "database/static-creds/pgdog-static-role"'; do
if ! echo "$vault_users" | grep -qF "$expected"; then
echo " FAIL: users.toml is missing: $expected"
echo " Got: $vault_users"
exit 1
fi
done
echo " Vault user settings rendered correctly"

if [ "$vault_env" = '{"name":"VAULT_SECRET_ID","valueFrom":{"secretKeyRef":{"name":"pgdog-vault","key":"secret-id"}}}' ]; then
echo " VAULT_SECRET_ID injected from the Secret"
else
echo " FAIL: VAULT_SECRET_ID not injected correctly"
echo " Got: $vault_env"
exit 1
fi

# Validate zero values survive on the PodDisruptionBudget
echo ""
echo "==> Validating PodDisruptionBudget zero values..."
Expand Down
27 changes: 27 additions & 0 deletions test/values-vault.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Test HashiCorp Vault settings
databases:
- name: prod
host: 10.0.0.1

vault:
url: https://vault.internal:8200
authMethod: approle
authMount: pgdog-approle
namespace: team-a
approleRoleId: 4f8e2c1a-role-id
approleSecretIdSecret:
name: pgdog-vault
clientTokenTtl: 120

users:
- name: pgdog
database: prod
password: hunter2
serverAuth: vault_dynamic
serverVaultPath: database/creds/pgdog-role
vaultRefreshPercent: 75
- name: pgdog_static
database: prod
vaultPath: database/static-creds/pgdog-static-role
serverAuth: vault_static
serverVaultPath: database/static-creds/pgdog-static-role
27 changes: 27 additions & 0 deletions values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ databases: []
# when serverAuth is rds_iam.
# Set serverIamAssumeRole to an IAM role ARN to assume for RDS IAM authentication
# when serverAuth is rds_iam.
# Set serverVaultPath to the Vault credentials path when serverAuth is
# vault_dynamic or vault_static, and vaultRefreshPercent (1-80) to control
# when dynamic credentials are renewed. Set vaultPath to a static role path
# to authenticate clients against its Vault-managed password. These require
# the vault section below.
users: []

# mirrors contains a list of databases to replicate traffic from/to.
Expand Down Expand Up @@ -542,6 +547,28 @@ configSecret:
# name: "" # existing Secret name
# key: dd-api-key # key within that Secret holding the API key

# vault configures HashiCorp Vault, used by users with serverAuth set to
# vault_dynamic or vault_static, or with vaultPath set. Left unset by default
# so the [vault] section is omitted from pgdog.toml.
# vault:
# url: https://vault.internal:8200
# authMethod: kubernetes # kubernetes or approle
# authMount: "" # default: kubernetes or approle
# namespace: "" # Vault Enterprise namespace
# # Kubernetes auth
# kubernetesRole: pgdog
# kubernetesJwtPath: "" # default: the pod's service account token
# # AppRole auth
# approleRoleId: ""
# approleSecretIdFile: "" # file holding the secret ID, e.g. via extraVolumes
# # Alternatively, inject the secret ID from an existing Secret you created
# # as the VAULT_SECRET_ID env var, which pgdog reads when
# # approleSecretIdFile is not set.
# approleSecretIdSecret:
# name: "" # existing Secret name
# key: secret-id # key within that Secret holding the secret ID
# clientTokenTtl: 60 # seconds before token expiry to log in again

# ServiceMonitor for Prometheus metrics
serviceMonitor:
enabled: false
Expand Down