# T05c — KeyCape (OIDC Orchestration Layer) KeyCape is the stateless OIDC server that ties the stack together. It orchestrates the full authentication flow: 1. User visits a registered application 2. Application redirects to KeyCape (`kc.coulomb.social`) for login 3. KeyCape redirects the browser to Authelia (`auth.coulomb.social`) for password auth 4. Authelia validates the password against LLDAP and returns an authorization code 5. KeyCape exchanges the code for user identity, then calls privacyIDEA for MFA 6. On success, KeyCape issues a signed OIDC token to the application KeyCape is stateless — all state lives in Authelia (sessions), LLDAP (users), and privacyIDEA (MFA tokens). No PVC is required. ## Prerequisites - T04 complete (privacyIDEA is Running and bootstrapped — admin account + enckey done) - T05a complete (LLDAP is Running) - T05b complete (Authelia is Running) - KeyCape container image built and available (see "Building the image" below) - `bootstrap/gen-secrets.sh` run - `kubectl` configured with cluster access ## Building the image KeyCape has no published image. Build it from the source repository and make it available to K3s before applying `deployment.yaml`. ### Option A — Local import into K3s (dev/single-node) ```bash cd ~/key-cape docker build -t keycape:v0.1 . # Import directly into the K3s containerd runtime (no registry needed) docker save keycape:v0.1 | sudo k3s ctr images import - # After import, set imagePullPolicy: Never in deployment.yaml # (the image is now in the K3s local store, not a registry) ``` ### Option B — Private registry (production) ```bash cd ~/key-cape docker build -t /keycape:v0.1 . docker push /keycape:v0.1 # Update the image field in deployment.yaml: # image: /keycape:v0.1 # imagePullPolicy: IfNotPresent (default) is correct for registry images. ``` After building, update `deployment.yaml` line: ```yaml image: keycape:v0.1 # replace with your actual tag ``` ## Apply order ```bash # 1. Create Secrets (config.yaml + key.pem) # Run this AFTER T04 bootstrap if you want the privacyIDEA token included. # If T04 is not yet done, run it now and re-run after create-pi-token.sh. cd sso-mfa/k8s/keycape chmod +x create-secrets.sh create-pi-token.sh ./create-secrets.sh # 2. Apply manifests kubectl apply -f deployment.yaml kubectl apply -f middleware.yaml kubectl apply -f ingress.yaml # 3. Wait for pod to be ready kubectl rollout status deployment/keycape -n sso --timeout=60s ``` ## Post-deploy: inject privacyIDEA admin token If T04 was not complete when you ran `create-secrets.sh`, the privacyIDEA admin token is a placeholder. After T04 bootstrap is done: ```bash # 1. Fetch the token from privacyIDEA and store it chmod +x create-pi-token.sh ./create-pi-token.sh # 2. Re-run create-secrets.sh to update keycape-config with the real token ./create-secrets.sh # 3. Restart KeyCape to pick up the new Secret kubectl rollout restart deployment/keycape -n sso ``` ## OIDC client registration Downstream applications are registered in the `clients:` block in `keycape/create-secrets.sh`. After editing: ```bash ./create-secrets.sh # regenerates keycape-config Secret kubectl rollout restart deployment/keycape -n sso ``` Example entry (public client, PKCE, for a SPA): ```yaml clients: - clientId: "my-app" displayName: "My Application" redirectUris: - "https://my-app.coulomb.social/callback" allowedScopes: ["openid", "profile", "email", "groups"] grantTypes: ["authorization_code"] clientType: "public" ``` ## Secrets managed | Secret name | Keys | Purpose | |-------------|------|---------| | `keycape-config` | `config.yaml` | Full KeyCape configuration (LLDAP URL + creds, Authelia URL + client secret, privacyIDEA URL + admin token, OIDC clients) | | | `key.pem` | RSA-2048 private key for signing OIDC tokens issued to downstream applications | | `keycape-pi-token` | `pi_admin_token` | privacyIDEA admin JWT — created by `create-pi-token.sh`, referenced in `config.yaml` | Store `key.pem` in KeePassXC as a binary attachment. If it is lost, all active sessions become invalid (tokens cannot be verified) and all applications must re-authenticate. ## Verify ```bash # Pod status kubectl get pod -n sso -l app.kubernetes.io/name=keycape # Health check kubectl run -n sso --rm -it kc-test --image=busybox --restart=Never \ -- wget -qO- http://keycape.sso.svc.cluster.local:8080/healthz # OIDC discovery (public endpoint) curl -s https://kc.coulomb.social/.well-known/openid-configuration | jq . # Check issuer matches CP-NK-004 curl -s https://kc.coulomb.social/.well-known/openid-configuration \ | jq -r .issuer # should be: https://kc.coulomb.social ```