Skip to content

Commit e12c45e

Browse files
authored
fix(self-managed): align Cassandra application credentials (#1177)
1 parent bd89567 commit e12c45e

3 files changed

Lines changed: 140 additions & 2 deletions

File tree

deploy/stacks/self-managed/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ test:
1111
@tests/grpc-proxy-nats-endpoint.sh
1212
@tests/llm-pki-openbao-migration.sh
1313
@tests/api-keys-startup-probe.sh
14+
@tests/cassandra-openbao-credential-wiring.sh
1415
@tests/llm-pki-release.sh
1516
@tests/check-llm-pki-issuer.sh
1617
@tests/pdb-value-wiring.sh

deploy/stacks/self-managed/secrets/secrets.yaml.template

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
# Notes:
66
# Cassandra:
7-
# The password should match the value set in the cassandra keyspace migrations
7+
# This password is shared by the Cassandra keyspace migrations that create
8+
# application roles and the OpenBao migrations that publish those credentials.
89
#
910
# API:
1011
# The value for the registry will be used in three places, as it is
@@ -22,12 +23,15 @@
2223
# The wrong encoding makes "function create" return
2324
# 400 "must be base64 encoded username:password format".
2425

26+
cassandra:
27+
serviceRolePassword: &cassandra_service_role_password "ch@ng3m3"
28+
2529
openbao:
2630
migrations:
2731
env:
2832
# Stored in OpenBao shared secrets (written by migration job)
2933
- name: DEFAULT_CASSANDRA_PASSWORD
30-
value: "ch@ng3m3"
34+
value: *cassandra_service_role_password
3135
# Stored in OpenBao KV for nvcf-api AND nvct-api (written by migration job)
3236
- name: NVCF_API_SIDECARS_IMAGE_PULL_SECRET
3337
value: REPLACE_WITH_BASE64_DOCKER_CREDENTIAL
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env bash
2+
# Verify that the self-managed secrets template gives Cassandra migrations and
3+
# OpenBao migrations the same non-empty application-role password.
4+
set -euo pipefail
5+
6+
stack_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
7+
stacks_dir="$(cd "$stack_dir/.." && pwd)"
8+
helm_dir="$(cd "$stack_dir/../../helm" && pwd)"
9+
work_dir="$(mktemp -d)"
10+
test_stacks_dir="$work_dir/stacks"
11+
test_stack_dir="$test_stacks_dir/self-managed"
12+
environment_name="cassandra-openbao-credential-wiring-test"
13+
secrets_file="$test_stack_dir/secrets/$environment_name-secrets.yaml"
14+
trap 'rm -rf "$work_dir"' EXIT
15+
16+
fail() {
17+
echo "cassandra-openbao-credential-wiring: $*" >&2
18+
exit 1
19+
}
20+
21+
# Exercise the real stack and its shipped secrets template from an isolated
22+
# copy. The sibling stacks are needed because helmfile.d references them.
23+
mkdir -p "$test_stacks_dir"
24+
cp -R "$stacks_dir"/. "$test_stacks_dir"
25+
cp "$test_stack_dir/secrets/secrets.yaml.template" "$secrets_file"
26+
27+
for stack_environments in "$test_stacks_dir"/*/environments; do
28+
test -d "$stack_environments" || continue
29+
test -e "$stack_environments/$environment_name.yaml" ||
30+
printf '{}\n' >"$stack_environments/$environment_name.yaml"
31+
done
32+
33+
helmfile_common=(
34+
--file "$test_stack_dir/helmfile.d"
35+
--environment default
36+
--state-values-set ingress.gatewayApi.controllerNamespace=envoy-gateway-system
37+
--state-values-set ingress.gatewayApi.gateways.shared.name=shared-gw
38+
--state-values-set ingress.gatewayApi.gateways.shared.namespace=envoy-gateway-system
39+
--state-values-set ingress.gatewayApi.gateways.grpc.name=grpc-gw
40+
--state-values-set ingress.gatewayApi.gateways.grpc.namespace=envoy-gateway-system
41+
)
42+
43+
render_chart_values() {
44+
local release="$1"
45+
local output_file="$2"
46+
local render_log="$work_dir/$release-write-values.log"
47+
48+
if ! HELMFILE_ENV="$environment_name" \
49+
HELMFILE_CACHE_HOME="$work_dir/helmfile-cache" \
50+
helmfile "${helmfile_common[@]}" \
51+
--selector "name=$release" \
52+
write-values \
53+
--output-file-template "$output_file" 2>"$render_log"; then
54+
cat "$render_log" >&2
55+
fail "$release: helmfile could not render the stack"
56+
fi
57+
58+
test -s "$output_file" || fail "$release: helmfile wrote no values"
59+
}
60+
61+
cassandra_values="$work_dir/cassandra-values.yaml"
62+
openbao_values="$work_dir/openbao-values.yaml"
63+
render_chart_values cassandra "$cassandra_values"
64+
render_chart_values openbao-server "$openbao_values"
65+
66+
cassandra_password="$(yq -r '.cassandra.serviceRolePassword // ""' "$cassandra_values")"
67+
test -n "$cassandra_password" ||
68+
fail "Cassandra migrations received no application-role password"
69+
70+
cassandra_manifest="$work_dir/cassandra-manifest.yaml"
71+
helm template cassandra "$helm_dir/cassandra/helm" \
72+
--namespace cassandra-system \
73+
--values "$cassandra_values" >"$cassandra_manifest" ||
74+
fail "Cassandra chart did not render"
75+
cassandra_job_password="$(yq -r '
76+
select(.kind == "Job" and .metadata.name == "cassandra-migrations") |
77+
.spec.template.spec.containers[].env[] |
78+
select(.name == "SERVICE_ROLE_PASSWORD") |
79+
.value
80+
' "$cassandra_manifest")"
81+
82+
test -n "$cassandra_job_password" ||
83+
fail "Cassandra migration Job received no application-role password"
84+
test "$cassandra_job_password" = "$cassandra_password" ||
85+
fail "Cassandra migration Job did not receive the rendered stack password"
86+
87+
# The wrapper chart's migration Job does not depend on upstream OpenBao
88+
# templates. Supply an empty dependency chart in the isolated copy so this
89+
# focused render stays offline while exercising the real wrapper template.
90+
openbao_chart="$work_dir/openbao-chart"
91+
cp -R "$helm_dir/openbao/helm" "$openbao_chart"
92+
mkdir -p "$openbao_chart/charts/openbao"
93+
openbao_dependency_version="$(yq -r '
94+
.dependencies[] |
95+
select(.name == "openbao") |
96+
.version
97+
' "$openbao_chart/Chart.yaml")"
98+
test -n "$openbao_dependency_version" ||
99+
fail "OpenBao wrapper chart has no OpenBao dependency version"
100+
printf '%s\n' \
101+
'apiVersion: v2' \
102+
'name: openbao' \
103+
"version: $openbao_dependency_version" >"$openbao_chart/charts/openbao/Chart.yaml"
104+
105+
openbao_manifest="$work_dir/openbao-manifest.yaml"
106+
helm template openbao-server "$openbao_chart" \
107+
--namespace vault-system \
108+
--values "$openbao_values" \
109+
--show-only templates/hook-post-02-migrations.yaml >"$openbao_manifest" ||
110+
fail "OpenBao migration Job did not render"
111+
openbao_job_password_count="$(yq -r '
112+
[.spec.template.spec.containers[] |
113+
select(.name == "bao-migrations") |
114+
.env[] |
115+
select(.name == "DEFAULT_CASSANDRA_PASSWORD")] |
116+
length
117+
' "$openbao_manifest")"
118+
test "$openbao_job_password_count" = "1" ||
119+
fail "OpenBao migration Job must receive exactly one application-role password"
120+
openbao_job_password="$(yq -r '
121+
.spec.template.spec.containers[] |
122+
select(.name == "bao-migrations") |
123+
.env[] |
124+
select(.name == "DEFAULT_CASSANDRA_PASSWORD") |
125+
.value
126+
' "$openbao_manifest")"
127+
128+
test -n "$openbao_job_password" ||
129+
fail "OpenBao migration Job received no application-role password"
130+
test "$cassandra_job_password" = "$openbao_job_password" ||
131+
fail "Cassandra and OpenBao migrations received different application-role passwords"
132+
133+
echo "cassandra-openbao-credential-wiring: all checks passed"

0 commit comments

Comments
 (0)