generated from coulomb/repo-seed
feat(sso-mfa): T05 SSO stack pivot — Keycloak → Authelia + LLDAP + KeyCape (NK-WP-0001-T05)
Replaces the Keycloak+privacyIDEA SSO tier with the lightweight stack built during KEY-WP-0001: Authelia (password frontend), LLDAP (directory), and KeyCape (OIDC orchestration). privacyIDEA is retained as the MFA engine. Stack: kc.coulomb.social — KeyCape OIDC server (stateless, custom Go) auth.coulomb.social — Authelia login portal (password auth → Authelia OIDC → KeyCape) lldap.coulomb.social — LLDAP admin UI (IP-restricted) pink.coulomb.social — privacyIDEA MFA engine (unchanged) Changes: - Remove sso-mfa/k8s/keycloak/ (7 files) - Add sso-mfa/k8s/lldap/ (pvc, deployment, middleware, ingress, create-secrets, README) - Add sso-mfa/k8s/authelia/ (pvc, configmap, deployment, ingress, create-secrets, README) - Add sso-mfa/k8s/keycape/ (deployment, middleware, ingress, create-secrets, create-pi-token, README) - Update network-policies/netpol-sso.yaml for new component topology - Update verify-t05.sh: checks LLDAP + Authelia + KeyCape (23 checks) - Update CONFIG.md: fix CP-NK-004 (KeyCape), add CP-NK-005 (Authelia), CP-NK-006 (LLDAP) - Update bootstrap/gen-secrets.sh: add LLDAP/Authelia/KeyCape sections, remove Keycloak - Update k8s/README.md: network policy table reflects new traffic paths - Add sso-mfa/WORKPLAN.md: resumable task checklist Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,24 @@
|
||||
# NetworkPolicies for the sso namespace (Keycloak)
|
||||
# NetworkPolicies for the sso namespace (KeyCape + Authelia + LLDAP)
|
||||
#
|
||||
# Allowed paths:
|
||||
# INGRESS: Traefik (kube-system) → Keycloak :8080
|
||||
# EGRESS: Keycloak → databases :5432 (PostgreSQL)
|
||||
# EGRESS: Keycloak → mfa :8080 (privacyIDEA API)
|
||||
# EGRESS: all pods → kube-dns :53 (UDP+TCP)
|
||||
# Components in this namespace:
|
||||
# keycape — OIDC orchestration layer (port 8080)
|
||||
# authelia — authentication frontend (port 9091)
|
||||
# lldap — LDAP directory (port 3890 LDAP, port 17170 Web UI)
|
||||
#
|
||||
# Everything else is denied.
|
||||
# Allowed ingress paths:
|
||||
# Traefik → keycape :8080 (OIDC endpoints, user-facing)
|
||||
# Traefik → authelia :9091 (login portal, user-facing)
|
||||
# Traefik → lldap :17170 (admin web UI; IP-restricted at Traefik layer)
|
||||
#
|
||||
# Allowed egress paths:
|
||||
# keycape → authelia :9091 (OIDC callback orchestration)
|
||||
# keycape → lldap :3890 (LDAP user lookups)
|
||||
# keycape → mfa :8080 (privacyIDEA MFA check and token validation)
|
||||
# authelia → lldap :3890 (LDAP authentication backend)
|
||||
# all pods → kube-dns :53 (DNS resolution)
|
||||
#
|
||||
# No egress to databases namespace — KeyCape is stateless;
|
||||
# LLDAP uses SQLite on a PVC (no external DB needed in lightweight mode).
|
||||
|
||||
# ── Default deny all ingress and egress ──────────────────────────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
@@ -20,18 +32,16 @@ spec:
|
||||
- Ingress
|
||||
- Egress
|
||||
---
|
||||
# ── Allow ingress from Traefik (K3s ingress controller) ─────────────────────
|
||||
# Traefik terminates TLS; Keycloak listens on HTTP :8080 internally.
|
||||
# Traefik pods are in kube-system with label app.kubernetes.io/name=traefik.
|
||||
# ── Traefik → KeyCape :8080 ───────────────────────────────────────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-from-traefik
|
||||
name: allow-traefik-to-keycape
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycloak
|
||||
app.kubernetes.io/name: keycape
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
@@ -46,38 +56,162 @@ spec:
|
||||
- port: 8080
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Allow egress to PostgreSQL ───────────────────────────────────────────────
|
||||
# ── Traefik → Authelia :9091 ──────────────────────────────────────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-egress-to-postgres
|
||||
name: allow-traefik-to-authelia
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycloak
|
||||
app.kubernetes.io/name: authelia
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: traefik
|
||||
ports:
|
||||
- port: 9091
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Traefik → LLDAP :17170 (admin web UI) ────────────────────────────────────
|
||||
# IP-based restriction is enforced at the Traefik layer (lldap-admin-allowlist
|
||||
# middleware in lldap/middleware.yaml). This NetworkPolicy opens the port;
|
||||
# Traefik enforces the IP allowlist before traffic reaches LLDAP.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-traefik-to-lldap-ui
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lldap
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: traefik
|
||||
ports:
|
||||
- port: 17170
|
||||
protocol: TCP
|
||||
---
|
||||
# ── KeyCape → Authelia :9091 ──────────────────────────────────────────────────
|
||||
# KeyCape redirects the browser to Authelia and exchanges auth codes at /token.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-keycape-to-authelia
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: authelia
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycape
|
||||
ports:
|
||||
- port: 9091
|
||||
protocol: TCP
|
||||
---
|
||||
# ── KeyCape → LLDAP :3890 ────────────────────────────────────────────────────
|
||||
# KeyCape queries LLDAP for user attributes after authentication.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-keycape-to-lldap
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lldap
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycape
|
||||
ports:
|
||||
- port: 3890
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Authelia → LLDAP :3890 ───────────────────────────────────────────────────
|
||||
# Authelia binds to LLDAP to validate credentials and resolve group membership.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-authelia-to-lldap
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lldap
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: authelia
|
||||
ports:
|
||||
- port: 3890
|
||||
protocol: TCP
|
||||
---
|
||||
# ── KeyCape egress → Authelia + LLDAP (within sso namespace) ─────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-keycape-egress-internal
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycape
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- to:
|
||||
- namespaceSelector:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
net-kingdom/component: databases
|
||||
app.kubernetes.io/name: authelia
|
||||
ports:
|
||||
- port: 5432
|
||||
- port: 9091
|
||||
protocol: TCP
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lldap
|
||||
ports:
|
||||
- port: 3890
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Allow egress to privacyIDEA ──────────────────────────────────────────────
|
||||
# Keycloak calls the privacyIDEA REST API via the privacyIDEA Keycloak Provider.
|
||||
# ── KeyCape egress → privacyIDEA (mfa namespace) :8080 ───────────────────────
|
||||
# KeyCape calls privacyIDEA to check and validate MFA tokens.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-egress-to-privacyidea
|
||||
name: allow-keycape-egress-to-privacyidea
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: keycloak
|
||||
app.kubernetes.io/name: keycape
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
@@ -89,6 +223,27 @@ spec:
|
||||
- port: 8080
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Authelia egress → LLDAP (within sso namespace) ───────────────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-authelia-egress-to-lldap
|
||||
namespace: sso
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: authelia
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: lldap
|
||||
ports:
|
||||
- port: 3890
|
||||
protocol: TCP
|
||||
---
|
||||
# ── Allow egress DNS (all pods) ──────────────────────────────────────────────
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
|
||||
Reference in New Issue
Block a user