generated from coulomb/repo-seed
fix(privacyidea): bootstrap-realm scope fixes + netpol for PI→LLDAP
bootstrap-realm.sh: - Remove Content-Type header from GET requests (Werkzeug 3.x BadRequest fix) - Fix resolver type check — result path is result.value.<name>.type, not .data - Fix self-enrollment policy scope: 'user' not 'enrollment' (PI 3.12) NetworkPolicies: - allow-egress-to-lldap (mfa ns): privacyIDEA → LLDAP :3890 - allow-privacyidea-to-lldap (sso ns): ingress from mfa/privacyIDEA → LLDAP :3890 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
# INGRESS: Traefik (kube-system) → privacyIDEA :8080 (user-facing portal)
|
# INGRESS: Traefik (kube-system) → privacyIDEA :8080 (user-facing portal)
|
||||||
# INGRESS: KeyCape (sso) → privacyIDEA :8080 (Provider API calls)
|
# INGRESS: KeyCape (sso) → privacyIDEA :8080 (Provider API calls)
|
||||||
# EGRESS: privacyIDEA → databases :5432 (PostgreSQL)
|
# EGRESS: privacyIDEA → databases :5432 (PostgreSQL)
|
||||||
|
# EGRESS: privacyIDEA → sso/lldap :3890 (LDAP resolver for realm)
|
||||||
# EGRESS: all pods → kube-dns :53 (UDP+TCP)
|
# EGRESS: all pods → kube-dns :53 (UDP+TCP)
|
||||||
#
|
#
|
||||||
# Everything else is denied.
|
# Everything else is denied.
|
||||||
@@ -90,6 +91,33 @@ spec:
|
|||||||
- port: 5432
|
- port: 5432
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
|
# ── privacyIDEA → LLDAP :3890 ────────────────────────────────────────────────
|
||||||
|
# privacyIDEA's LDAP resolver binds to LLDAP to resolve users in the coulomb realm.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-egress-to-lldap
|
||||||
|
namespace: mfa
|
||||||
|
labels:
|
||||||
|
net-kingdom/component: mfa
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: privacyidea
|
||||||
|
policyTypes:
|
||||||
|
- Egress
|
||||||
|
egress:
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
net-kingdom/component: sso
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: lldap
|
||||||
|
ports:
|
||||||
|
- port: 3890
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
# ── Traefik → ACME HTTP-01 solver pods :8089 ─────────────────────────────────
|
# ── Traefik → ACME HTTP-01 solver pods :8089 ─────────────────────────────────
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
|
|||||||
@@ -173,6 +173,33 @@ spec:
|
|||||||
- port: 3890
|
- port: 3890
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
|
# ── privacyIDEA (mfa ns) → LLDAP :3890 ──────────────────────────────────────
|
||||||
|
# privacyIDEA's LDAP resolver binds to LLDAP to resolve users in the coulomb realm.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: allow-privacyidea-to-lldap
|
||||||
|
namespace: sso
|
||||||
|
labels:
|
||||||
|
net-kingdom/component: sso
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: lldap
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
net-kingdom/component: mfa
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: privacyidea
|
||||||
|
ports:
|
||||||
|
- port: 3890
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
# ── KeyCape egress → Authelia + LLDAP (within sso namespace) ─────────────────
|
# ── KeyCape egress → Authelia + LLDAP (within sso namespace) ─────────────────
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ info "Authenticated as pi-admin (token obtained)"
|
|||||||
|
|
||||||
pi_api() {
|
pi_api() {
|
||||||
# pi_api <method> <path> [json-body]
|
# pi_api <method> <path> [json-body]
|
||||||
|
# Content-Type is only set on requests with a body — Werkzeug 3.x raises
|
||||||
|
# BadRequest if Content-Type: application/json is sent on a bodyless GET.
|
||||||
local method="$1"; local path="$2"; local body="${3:-}"
|
local method="$1"; local path="$2"; local body="${3:-}"
|
||||||
if [[ -n "$body" ]]; then
|
if [[ -n "$body" ]]; then
|
||||||
curl -sf -X "$method" "$PI_URL$path" \
|
curl -sf -X "$method" "$PI_URL$path" \
|
||||||
@@ -99,7 +101,6 @@ pi_api() {
|
|||||||
else
|
else
|
||||||
curl -sf -X "$method" "$PI_URL$path" \
|
curl -sf -X "$method" "$PI_URL$path" \
|
||||||
-H "Authorization: $PI_TOKEN" \
|
-H "Authorization: $PI_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
2>/dev/null || echo "CURL_FAILED"
|
2>/dev/null || echo "CURL_FAILED"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -163,7 +164,7 @@ echo "Step 2: Testing resolver '$RESOLVER_NAME' ..."
|
|||||||
TEST_RESP=$(pi_api GET "/resolver/$RESOLVER_NAME")
|
TEST_RESP=$(pi_api GET "/resolver/$RESOLVER_NAME")
|
||||||
if [[ "$TEST_RESP" != "CURL_FAILED" ]]; then
|
if [[ "$TEST_RESP" != "CURL_FAILED" ]]; then
|
||||||
RESOLVER_TYPE=$(echo "$TEST_RESP" | python3 -c \
|
RESOLVER_TYPE=$(echo "$TEST_RESP" | python3 -c \
|
||||||
"import sys,json; d=json.load(sys.stdin); r=d.get('result',{}).get('value',{}).get('data',{}); print(list(r.values())[0].get('type','') if r else '')" \
|
"import sys,json; d=json.load(sys.stdin); r=d.get('result',{}).get('value',{}); print(list(r.values())[0].get('type','') if r else '')" \
|
||||||
2>/dev/null || echo "")
|
2>/dev/null || echo "")
|
||||||
if [[ "$RESOLVER_TYPE" == "ldapresolver" ]]; then
|
if [[ "$RESOLVER_TYPE" == "ldapresolver" ]]; then
|
||||||
ok "Resolver '$RESOLVER_NAME' exists and is type ldapresolver"
|
ok "Resolver '$RESOLVER_NAME' exists and is type ldapresolver"
|
||||||
@@ -217,12 +218,13 @@ check_result "Default realm set to '$REALM_NAME'" "$RESP" || true
|
|||||||
# ── 6. Create self-enrollment policy ─────────────────────────────────────────
|
# ── 6. Create self-enrollment policy ─────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "Step 6: Creating self-enrollment policy ..."
|
echo "Step 6: Creating self-enrollment policy ..."
|
||||||
# Allows users in the coulomb realm to self-enroll TOTP tokens.
|
# Allows users in the coulomb realm to self-enroll TOTP tokens via the self-service portal.
|
||||||
|
# Scope must be 'user' (not 'enrollment') — self-service actions live in the user scope.
|
||||||
# The WebUI self-service portal is at pink-account.coulomb.social.
|
# The WebUI self-service portal is at pink-account.coulomb.social.
|
||||||
ENROLL_POLICY=$(python3 -c "
|
ENROLL_POLICY=$(python3 -c "
|
||||||
import json
|
import json
|
||||||
body = {
|
body = {
|
||||||
'scope': 'enrollment',
|
'scope': 'user',
|
||||||
'action': 'enrollTOTP, delete, disable',
|
'action': 'enrollTOTP, delete, disable',
|
||||||
'realm': '$REALM_NAME',
|
'realm': '$REALM_NAME',
|
||||||
'user': '*',
|
'user': '*',
|
||||||
|
|||||||
Reference in New Issue
Block a user