Verify railiance01 identity dependencies
This commit is contained in:
parent
d674d7f33a
commit
43045cbaf5
4 changed files with 170 additions and 7 deletions
|
|
@ -44,7 +44,7 @@
|
||||||
| task | NK-WP-0022-T01 | progress | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T01 | progress | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T02 | done | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T02 | done | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T03 | done | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T03 | done | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T04 | wait | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T04 | done | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T05 | wait | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T05 | wait | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T06 | progress | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T06 | progress | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
| task | NK-WP-0022-T07 | wait | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
| task | NK-WP-0022-T07 | wait | — | workplans/NK-WP-0022-railiance01-identity-cutover-and-coulombcore-retirement.md |
|
||||||
|
|
|
||||||
|
|
@ -165,11 +165,30 @@ logs were removed. CoulombCore identity writers remain scaled to zero to
|
||||||
prevent divergence while the railiance01 direct-resolution conformance gates
|
prevent divergence while the railiance01 direct-resolution conformance gates
|
||||||
run; no PVC, Secret, database, or workload declaration was deleted.
|
run; no PVC, Secret, database, or workload declaration was deleted.
|
||||||
|
|
||||||
|
## Runtime dependency reconciliation
|
||||||
|
|
||||||
|
`sso-mfa/k8s/verify-identity-cutover-dependencies.sh` now provides the
|
||||||
|
repeatable T04 negative search. It decodes Kubernetes Secret values only in
|
||||||
|
process memory and reports resource/key locators rather than values.
|
||||||
|
|
||||||
|
The live railiance01 run passed all gates:
|
||||||
|
|
||||||
|
- no Secret, ConfigMap, Deployment, or StatefulSet in `sso`, `mfa`,
|
||||||
|
`user-engine`, or `databases` references CoulombCore, its IP, or the public
|
||||||
|
LLDAP/privacyIDEA endpoints;
|
||||||
|
- KeyCape resolves LLDAP, Authelia, and privacyIDEA through cluster-local
|
||||||
|
service names and retains both user-engine and rapp-qonto client declarations;
|
||||||
|
- privacyIDEA's migrated LLDAP resolver is cluster-local;
|
||||||
|
- the KeyCape signing-key fingerprint matches CoulombCore;
|
||||||
|
- LLDAP, Authelia, KeyCape, privacyIDEA, and user-engine deployments are Ready.
|
||||||
|
|
||||||
|
TLS-preserving direct resolution to `92.205.62.239` returned HTTP 200 with
|
||||||
|
successful certificate verification for `auth`, `login`, `lldap`, `pink`,
|
||||||
|
and `pink-account` under `coulomb.social`.
|
||||||
|
|
||||||
## Required next evidence
|
## Required next evidence
|
||||||
|
|
||||||
1. Reconcile cluster-local configuration and prove that railiance01 has no
|
1. Exercise platform-root and Binky login/MFA using TLS-preserving direct
|
||||||
runtime dependency on CoulombCore.
|
|
||||||
2. Exercise platform-root and Binky login/MFA using TLS-preserving direct
|
|
||||||
resolution to railiance01.
|
resolution to railiance01.
|
||||||
3. Verify KeyCape service-client flows and negative authorization probes.
|
2. Verify KeyCape service-client flows and negative authorization probes.
|
||||||
4. Move LLDAP and privacyIDEA DNS only after those gates pass.
|
3. Move LLDAP and privacyIDEA DNS only after those gates pass.
|
||||||
|
|
|
||||||
135
sso-mfa/k8s/verify-identity-cutover-dependencies.sh
Executable file
135
sso-mfa/k8s/verify-identity-cutover-dependencies.sh
Executable file
|
|
@ -0,0 +1,135 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Verify that the active identity stack has no runtime dependency on the
|
||||||
|
# retired/source host. Secret values are decoded only in process memory and
|
||||||
|
# never printed; failures report resource and key locators only.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
KUBECTL="${KUBECTL:-kubectl}"
|
||||||
|
SOURCE_HOST_MARKER="${SOURCE_HOST_MARKER:-coulombcore}"
|
||||||
|
SOURCE_IP="${SOURCE_IP:-92.205.130.254}"
|
||||||
|
NAMESPACES="${NAMESPACES:-sso mfa user-engine databases}"
|
||||||
|
|
||||||
|
tmp="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
|
|
||||||
|
for namespace in $NAMESPACES; do
|
||||||
|
for kind in configmap secret deployment statefulset; do
|
||||||
|
"$KUBECTL" -n "$namespace" get "$kind" -o json \
|
||||||
|
>"$tmp/${namespace}-${kind}.json"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
python3 - "$tmp" "$SOURCE_HOST_MARKER" "$SOURCE_IP" <<'PY'
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
root = pathlib.Path(sys.argv[1])
|
||||||
|
patterns = {
|
||||||
|
"source-host": sys.argv[2].lower(),
|
||||||
|
"source-ip": sys.argv[3].lower(),
|
||||||
|
"public-lldap": "lldap.coulomb.social",
|
||||||
|
"public-privacyidea": "pink.coulomb.social",
|
||||||
|
"public-privacyidea-account": "pink-account.coulomb.social",
|
||||||
|
}
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
for path in sorted(root.glob("*.json")):
|
||||||
|
namespace, kind = path.stem.rsplit("-", 1)
|
||||||
|
for item in json.loads(path.read_text()).get("items", []):
|
||||||
|
name = item["metadata"]["name"]
|
||||||
|
if kind in {"configmap", "secret"}:
|
||||||
|
for key, raw in (item.get("data") or {}).items():
|
||||||
|
try:
|
||||||
|
value = (
|
||||||
|
base64.b64decode(raw).decode("utf-8", "replace")
|
||||||
|
if kind == "secret"
|
||||||
|
else raw
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
lowered = value.lower()
|
||||||
|
hits = [label for label, needle in patterns.items() if needle in lowered]
|
||||||
|
if hits:
|
||||||
|
failures.append(
|
||||||
|
f"{kind}/{namespace}/{name}:{key} matches={','.join(hits)}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
lowered = json.dumps(item.get("spec", {}), sort_keys=True).lower()
|
||||||
|
hits = [label for label, needle in patterns.items() if needle in lowered]
|
||||||
|
if hits:
|
||||||
|
failures.append(
|
||||||
|
f"{kind}/{namespace}/{name} matches={','.join(hits)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if failures:
|
||||||
|
print("stale_dependencies=found")
|
||||||
|
for failure in failures:
|
||||||
|
print(failure)
|
||||||
|
raise SystemExit(1)
|
||||||
|
print("stale_dependencies=absent")
|
||||||
|
PY
|
||||||
|
|
||||||
|
keycape_config="$(
|
||||||
|
"$KUBECTL" -n sso get secret keycape-config \
|
||||||
|
-o jsonpath='{.data.config\.yaml}' | base64 -d
|
||||||
|
)"
|
||||||
|
|
||||||
|
for expected in \
|
||||||
|
lldap.sso.svc.cluster.local \
|
||||||
|
authelia.sso.svc.cluster.local \
|
||||||
|
privacyidea.mfa.svc.cluster.local \
|
||||||
|
user-engine \
|
||||||
|
rapp-qonto
|
||||||
|
do
|
||||||
|
if [[ "$keycape_config" != *"$expected"* ]]; then
|
||||||
|
echo "keycape_expected_dependency_missing=$expected" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset keycape_config
|
||||||
|
echo "keycape_dependencies=cluster-local-and-complete"
|
||||||
|
|
||||||
|
pg_pod="$(
|
||||||
|
"$KUBECTL" -n databases get pod \
|
||||||
|
-l 'cnpg.io/cluster=net-kingdom-pg,role=primary' \
|
||||||
|
-o jsonpath='{.items[0].metadata.name}'
|
||||||
|
)"
|
||||||
|
resolver_class="$(
|
||||||
|
"$KUBECTL" -n databases exec "$pg_pod" -- \
|
||||||
|
psql -X -A -t -U postgres -d privacyidea_db -c \
|
||||||
|
"select case
|
||||||
|
when lower(\"Value\") like '%lldap.sso.svc.cluster.local%'
|
||||||
|
then 'cluster-local'
|
||||||
|
else 'other'
|
||||||
|
end
|
||||||
|
from resolverconfig
|
||||||
|
where \"Key\"='LDAPURI';" 2>/dev/null
|
||||||
|
)"
|
||||||
|
if [[ "$resolver_class" != "cluster-local" ]]; then
|
||||||
|
echo "privacyidea_lldap_resolver=$resolver_class" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "privacyidea_lldap_resolver=cluster-local"
|
||||||
|
|
||||||
|
for target in \
|
||||||
|
sso/lldap \
|
||||||
|
sso/authelia \
|
||||||
|
sso/keycape \
|
||||||
|
mfa/privacyidea \
|
||||||
|
user-engine/user-engine
|
||||||
|
do
|
||||||
|
namespace="${target%/*}"
|
||||||
|
name="${target#*/}"
|
||||||
|
ready="$(
|
||||||
|
"$KUBECTL" -n "$namespace" get deployment "$name" \
|
||||||
|
-o jsonpath='{.status.readyReplicas}'
|
||||||
|
)"
|
||||||
|
if [[ "${ready:-0}" -lt 1 ]]; then
|
||||||
|
echo "deployment_not_ready=$target" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "identity_deployments=ready"
|
||||||
|
echo "identity_cutover_dependencies=PASS"
|
||||||
|
|
@ -141,7 +141,7 @@ CoulombCore writers remain frozen against divergence.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: NK-WP-0022-T04
|
id: NK-WP-0022-T04
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "33591ee3-586e-4ac6-82e6-0ab4642cea5e"
|
state_hub_task_id: "33591ee3-586e-4ac6-82e6-0ab4642cea5e"
|
||||||
```
|
```
|
||||||
|
|
@ -155,6 +155,15 @@ points back to CoulombCore.
|
||||||
Done when an automated dependency graph and negative search prove there are
|
Done when an automated dependency graph and negative search prove there are
|
||||||
no hidden CoulombCore runtime dependencies.
|
no hidden CoulombCore runtime dependencies.
|
||||||
|
|
||||||
|
2026-07-28: added
|
||||||
|
`sso-mfa/k8s/verify-identity-cutover-dependencies.sh`. Its live railiance01
|
||||||
|
run found no CoulombCore IP/host or public cross-cluster endpoint in decoded
|
||||||
|
identity Secrets, ConfigMaps, Deployments, or StatefulSets. It verified
|
||||||
|
cluster-local KeyCape and privacyIDEA dependencies, retained user-engine and
|
||||||
|
rapp-qonto clients, and Ready deployments. KeyCape signing fingerprints
|
||||||
|
match. TLS-preserving direct resolution returned HTTP 200 with valid
|
||||||
|
certificates for `auth`, `login`, `lldap`, `pink`, and `pink-account`.
|
||||||
|
|
||||||
## T05 - Run full pre-cutover identity conformance
|
## T05 - Run full pre-cutover identity conformance
|
||||||
|
|
||||||
```task
|
```task
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue