Reconcile development provider secrets
This commit is contained in:
parent
9e0d41eadf
commit
67747813cb
|
|
@ -669,6 +669,14 @@ that dump. After a successful rollout it also removes the obsolete chart Secret
|
||||||
and only the local Helm history revisions that stored the former inline
|
and only the local Helm history revisions that stored the former inline
|
||||||
credential fields.
|
credential fields.
|
||||||
|
|
||||||
|
When the ignored mode-`0600` `.env` exists, every `kind-up.sh` run also
|
||||||
|
reconciles a fixed allowlist of development provider settings into that same
|
||||||
|
Secret: Google/GitHub sign-in, browser push, FCM delivery, Android App Links,
|
||||||
|
sender identity, and support routing. It never prints their values and does not
|
||||||
|
replace the independently generated database or application secrets. Empty
|
||||||
|
allowlisted values remove stale provider settings so `.env` remains the single
|
||||||
|
development source of truth.
|
||||||
|
|
||||||
Exercise the verified local rolling-update path without recreating PostGIS or
|
Exercise the verified local rolling-update path without recreating PostGIS or
|
||||||
the Secret:
|
the Secret:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,16 @@ elif [ -z "$(kube --namespace "$NAMESPACE" get secret "$SECRET_NAME" -o jsonpath
|
||||||
unset metrics_token
|
unset metrics_token
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -f "$ROOT/.env" ]; then
|
||||||
|
KUBECTL_BIN="$ROOT/.tools/bin/kubectl" \
|
||||||
|
KUBE_CONTEXT="kind-${CLUSTER}" \
|
||||||
|
KUBE_NAMESPACE="$NAMESPACE" \
|
||||||
|
KUBE_SECRET_NAME="$SECRET_NAME" \
|
||||||
|
"$ROOT/scripts/sync-kind-runtime-secret.sh" "$ROOT/.env"
|
||||||
|
else
|
||||||
|
echo "No .env found; retained the existing optional kind runtime keys."
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$legacy_backup" ]; then
|
if [ -n "$legacy_backup" ]; then
|
||||||
kube --namespace "$NAMESPACE" delete deployment postgis --wait=true
|
kube --namespace "$NAMESPACE" delete deployment postgis --wait=true
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,39 @@ scan_image() {
|
||||||
|
|
||||||
scan_image_sequence=0
|
scan_image_sequence=0
|
||||||
|
|
||||||
|
echo "Checking the development kind runtime Secret allowlist"
|
||||||
|
kind_runtime_env="$scan_dir/kind-runtime.env"
|
||||||
|
kind_runtime_rendered="$scan_dir/kind-runtime.rendered"
|
||||||
|
cat >"$kind_runtime_env" <<'EOF'
|
||||||
|
DATABASE_URL=must-not-be-copied
|
||||||
|
GOOGLE_OAUTH_CLIENT_ID=quality-google-id
|
||||||
|
GOOGLE_OAUTH_CLIENT_SECRET="quality-google-secret"
|
||||||
|
GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-android-id
|
||||||
|
WEB_PUSH_VAPID_PUBLIC_KEY=quality-vapid-public
|
||||||
|
FCM_PROJECT_ID=
|
||||||
|
EOF
|
||||||
|
chmod 600 "$kind_runtime_env"
|
||||||
|
./scripts/sync-kind-runtime-secret.sh \
|
||||||
|
"$kind_runtime_env" --render-only "$kind_runtime_rendered" >/dev/null
|
||||||
|
grep -Fx 'GOOGLE_OAUTH_CLIENT_ID=quality-google-id' \
|
||||||
|
"$kind_runtime_rendered" >/dev/null
|
||||||
|
grep -Fx 'GOOGLE_OAUTH_CLIENT_SECRET=quality-google-secret' \
|
||||||
|
"$kind_runtime_rendered" >/dev/null
|
||||||
|
grep -Fx 'GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-android-id' \
|
||||||
|
"$kind_runtime_rendered" >/dev/null
|
||||||
|
grep -Fx 'WEB_PUSH_VAPID_PUBLIC_KEY=quality-vapid-public' \
|
||||||
|
"$kind_runtime_rendered" >/dev/null
|
||||||
|
if grep -Eq '^(DATABASE_URL|FCM_PROJECT_ID)=' "$kind_runtime_rendered"; then
|
||||||
|
echo "Kind runtime Secret renderer copied an unmanaged or empty value." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf '%s\n' 'GOOGLE_OAUTH_CLIENT_ID=duplicate' >>"$kind_runtime_env"
|
||||||
|
if ./scripts/sync-kind-runtime-secret.sh \
|
||||||
|
"$kind_runtime_env" --render-only "$kind_runtime_rendered" >/dev/null 2>&1; then
|
||||||
|
echo "Kind runtime Secret renderer accepted a duplicate managed key." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Checking shell scripts with ShellCheck 0.11.0"
|
echo "Checking shell scripts with ShellCheck 0.11.0"
|
||||||
# Word splitting is intentional: find emits repository-controlled paths and
|
# Word splitting is intentional: find emits repository-controlled paths and
|
||||||
# ShellCheck expects each file as a separate argument.
|
# ShellCheck expects each file as a separate argument.
|
||||||
|
|
|
||||||
160
scripts/sync-kind-runtime-secret.sh
Executable file
160
scripts/sync-kind-runtime-secret.sh
Executable file
|
|
@ -0,0 +1,160 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||||
|
env_file=${1:-"$ROOT/.env"}
|
||||||
|
mode=${2:-}
|
||||||
|
render_target=${3:-}
|
||||||
|
|
||||||
|
if [[ "$env_file" != /* ]]; then
|
||||||
|
env_file="$ROOT/$env_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$mode" && "$mode" != "--render-only" ]]; then
|
||||||
|
echo "Usage: $0 [ENV_FILE] [--render-only OUTPUT_FILE]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$mode" == "--render-only" && -z "$render_target" ]]; then
|
||||||
|
echo "Usage: $0 [ENV_FILE] [--render-only OUTPUT_FILE]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -f "$env_file" ]] || {
|
||||||
|
echo "Development environment does not exist: $env_file" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$(stat -c '%a' "$env_file")" == 600 ]] || {
|
||||||
|
echo "Development environment must have mode 0600: $env_file" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ "$(stat -c '%u' "$env_file")" == "$(id -u)" ]] || {
|
||||||
|
echo "Development environment must be owned by the current user: $env_file" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
managed_keys=(
|
||||||
|
ANDROID_APP_LINKS_PACKAGE_NAME
|
||||||
|
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS
|
||||||
|
EMAIL_FROM_ADDRESS
|
||||||
|
EMAIL_FROM_NAME
|
||||||
|
FCM_PROJECT_ID
|
||||||
|
FCM_SERVICE_ACCOUNT_JSON_BASE64
|
||||||
|
GITHUB_OAUTH_CLIENT_ID
|
||||||
|
GITHUB_OAUTH_CLIENT_SECRET
|
||||||
|
GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS
|
||||||
|
GOOGLE_OAUTH_CLIENT_ID
|
||||||
|
GOOGLE_OAUTH_CLIENT_SECRET
|
||||||
|
SUPPORT_INBOX_ADDRESS
|
||||||
|
SUPPORT_OPERATOR_EMAIL_MODE
|
||||||
|
WEB_PUSH_VAPID_PRIVATE_KEY
|
||||||
|
WEB_PUSH_VAPID_PUBLIC_KEY
|
||||||
|
WEB_PUSH_VAPID_SUBJECT
|
||||||
|
)
|
||||||
|
|
||||||
|
runtime_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-kind-runtime-secret.XXXXXX")
|
||||||
|
cleanup() {
|
||||||
|
status=$?
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
find "$runtime_dir" -xdev -depth -delete 2>/dev/null || true
|
||||||
|
exit "$status"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT HUP INT TERM
|
||||||
|
|
||||||
|
keys_file="$runtime_dir/managed-keys"
|
||||||
|
printf '%s\n' "${managed_keys[@]}" >"$keys_file"
|
||||||
|
filtered_env="$runtime_dir/runtime.env"
|
||||||
|
|
||||||
|
awk -F= '
|
||||||
|
NR == FNR {
|
||||||
|
managed[$1] = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = $1
|
||||||
|
if (!(key in managed)) next
|
||||||
|
seen[key]++
|
||||||
|
if (seen[key] > 1) {
|
||||||
|
printf "Managed development key occurs more than once: %s\n", key > "/dev/stderr"
|
||||||
|
invalid = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
value = substr($0, length(key) + 2)
|
||||||
|
if ((value ~ /^".*"$/) || (value ~ /^\047.*\047$/)) {
|
||||||
|
value = substr(value, 2, length(value) - 2)
|
||||||
|
}
|
||||||
|
if (length(value) > 0) print key "=" value
|
||||||
|
}
|
||||||
|
END { if (invalid) exit 1 }
|
||||||
|
' "$keys_file" "$env_file" >"$filtered_env"
|
||||||
|
chmod 600 "$filtered_env"
|
||||||
|
|
||||||
|
if [[ "$mode" == "--render-only" ]]; then
|
||||||
|
case "$render_target" in
|
||||||
|
/*) ;;
|
||||||
|
*) render_target="$ROOT/$render_target" ;;
|
||||||
|
esac
|
||||||
|
install -m 600 "$filtered_env" "$render_target"
|
||||||
|
echo "Rendered managed development runtime keys without printing their values."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
KUBECTL_BIN=${KUBECTL_BIN:-kubectl}
|
||||||
|
KUBE_CONTEXT=${KUBE_CONTEXT:-kind-who-need-help}
|
||||||
|
KUBE_NAMESPACE=${KUBE_NAMESPACE:-who-need-help}
|
||||||
|
KUBE_SECRET_NAME=${KUBE_SECRET_NAME:-who-need-help-local}
|
||||||
|
|
||||||
|
existing_json="$runtime_dir/existing.json"
|
||||||
|
extra_json="$runtime_dir/extra.json"
|
||||||
|
desired_json="$runtime_dir/desired.json"
|
||||||
|
observed_json="$runtime_dir/observed.json"
|
||||||
|
|
||||||
|
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||||
|
get secret "$KUBE_SECRET_NAME" --output json >"$existing_json"
|
||||||
|
|
||||||
|
if [[ -s "$filtered_env" ]]; then
|
||||||
|
"$KUBECTL_BIN" create secret generic "$KUBE_SECRET_NAME" \
|
||||||
|
--namespace "$KUBE_NAMESPACE" \
|
||||||
|
--from-env-file="$filtered_env" \
|
||||||
|
--dry-run=client \
|
||||||
|
--output json >"$extra_json"
|
||||||
|
else
|
||||||
|
printf '%s\n' '{"data":{}}' >"$extra_json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq --slurpfile extra "$extra_json" --rawfile managed "$keys_file" '
|
||||||
|
($managed | split("\n") | map(select(length > 0))) as $managed_keys
|
||||||
|
| .data = (
|
||||||
|
((.data // {})
|
||||||
|
| with_entries(select(.key as $key | ($managed_keys | index($key) | not))))
|
||||||
|
+ ($extra[0].data // {})
|
||||||
|
)
|
||||||
|
| {
|
||||||
|
apiVersion: "v1",
|
||||||
|
kind: "Secret",
|
||||||
|
metadata: {
|
||||||
|
name: .metadata.name,
|
||||||
|
namespace: .metadata.namespace,
|
||||||
|
resourceVersion: .metadata.resourceVersion
|
||||||
|
},
|
||||||
|
type: (.type // "Opaque"),
|
||||||
|
data: .data
|
||||||
|
}
|
||||||
|
' "$existing_json" >"$desired_json"
|
||||||
|
|
||||||
|
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||||
|
replace --filename "$desired_json" >/dev/null
|
||||||
|
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||||
|
get secret "$KUBE_SECRET_NAME" --output json >"$observed_json"
|
||||||
|
|
||||||
|
jq --exit-status --slurpfile desired "$desired_json" \
|
||||||
|
'.data == $desired[0].data' "$observed_json" >/dev/null || {
|
||||||
|
echo "Kubernetes Secret verification did not match the desired key set." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
synced_count=$(wc -l <"$filtered_env" | tr -d '[:space:]')
|
||||||
|
echo "Synchronized $synced_count managed development runtime keys without printing their values."
|
||||||
Loading…
Reference in New Issue
Block a user