Update docs for RBAC, OIDC, and user management
Some checks failed
CI / build (push) Successful in 1m2s
CI / docker (push) Successful in 15s
CI / deploy (push) Has been cancelled

Add RBAC role table, OIDC login flow, user admin API examples, and
new configuration properties to HOWTO.md. Update CLAUDE.md with RBAC
roles, OIDC support, and user persistence. Add user repository to
ARCHITECTURE.md component table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-14 12:41:41 +01:00
parent a4de2a7b79
commit 3438216fd9
3 changed files with 63 additions and 5 deletions

View File

@@ -43,7 +43,8 @@ Agents (50+) Users / UI
| **SSE Channel Manager** | core (interface) + app (impl) | Manage SSE connections, push config/commands | Agent Registry | | **SSE Channel Manager** | core (interface) + app (impl) | Manage SSE connections, push config/commands | Agent Registry |
| **Diagram Service** | core | Version diagrams, link to transactions, trigger rendering | Diagram Store | | **Diagram Service** | core | Version diagrams, link to transactions, trigger rendering | Diagram Store |
| **Diagram Renderer** | core | Server-side rendering of route definitions to visual output | Diagram Service | | **Diagram Renderer** | core | Server-side rendering of route definitions to visual output | Diagram Service |
| **Auth Service** | core | JWT validation, Ed25519 signing, bootstrap token flow | All controllers | | **Auth Service** | core | JWT validation with RBAC (AGENT/VIEWER/OPERATOR/ADMIN), Ed25519 signing, bootstrap token flow, OIDC token exchange | All controllers |
| **User Repository** | core (interface) + app (ClickHouse) | Persist users from local login and OIDC, role management | Auth controllers, admin API |
| **REST Controllers** | app | HTTP endpoints for transactions, agents, diagrams, config | All core services | | **REST Controllers** | app | HTTP endpoints for transactions, agents, diagrams, config | All core services |
| **SSE Controller** | app | SSE endpoint, connection lifecycle | SSE Channel Manager | | **SSE Controller** | app | SSE endpoint, connection lifecycle | SSE Channel Manager |
| **Config Controller** | app | Config CRUD, push triggers | SSE Channel Manager, Config store | | **Config Controller** | app | Config CRUD, push triggers | SSE Channel Manager, Config store |

View File

@@ -39,7 +39,9 @@ java -jar cameleer3-server-app/target/cameleer3-server-app-1.0-SNAPSHOT.jar
- Communication: receives HTTP POST data from agents, serves SSE event streams for config push/commands - Communication: receives HTTP POST data from agents, serves SSE event streams for config push/commands
- Maintains agent instance registry with states: LIVE → STALE → DEAD - Maintains agent instance registry with states: LIVE → STALE → DEAD
- Storage: ClickHouse for structured data, text index for full-text search - Storage: ClickHouse for structured data, text index for full-text search
- Security: JWT auth, Ed25519 config signing, bootstrap token for registration - Security: JWT auth with RBAC (AGENT/VIEWER/OPERATOR/ADMIN roles), Ed25519 config signing, bootstrap token for registration
- OIDC: Optional external identity provider support (token exchange pattern). Configured via `CAMELEER_OIDC_*` env vars
- User persistence: ClickHouse `users` table, admin CRUD at `/api/v1/admin/users`
## CI/CD & Deployment ## CI/CD & Deployment
@@ -50,6 +52,6 @@ java -jar cameleer3-server-app/target/cameleer3-server-app-1.0-SNAPSHOT.jar
- Registry: `gitea.siegeln.net/cameleer/cameleer3-server` (container images) - Registry: `gitea.siegeln.net/cameleer/cameleer3-server` (container images)
- K8s manifests in `deploy/` — ClickHouse StatefulSet + server Deployment + NodePort Service (30081) - K8s manifests in `deploy/` — ClickHouse StatefulSet + server Deployment + NodePort Service (30081)
- Deployment target: k3s at 192.168.50.86, namespace `cameleer` - Deployment target: k3s at 192.168.50.86, namespace `cameleer`
- Secrets managed in CI deploy step (idempotent `--dry-run=client | kubectl apply`): `cameleer-auth`, `clickhouse-credentials` - Secrets managed in CI deploy step (idempotent `--dry-run=client | kubectl apply`): `cameleer-auth`, `clickhouse-credentials`, `CAMELEER_JWT_SECRET`
- K8s probes: server uses `/api/v1/health`, ClickHouse uses `/ping` - K8s probes: server uses `/api/v1/health`, ClickHouse uses `/ping`
- Docker build uses buildx registry cache + `--provenance=false` for Gitea compatibility - Docker build uses buildx registry cache + `--provenance=false` for Gitea compatibility

View File

@@ -27,7 +27,7 @@ Start ClickHouse:
docker compose up -d docker compose up -d
``` ```
This starts ClickHouse 25.3 and automatically runs the schema init scripts (`clickhouse/init/01-schema.sql`, `clickhouse/init/02-search-columns.sql`). This starts ClickHouse 25.3 and automatically runs the schema init scripts (`clickhouse/init/01-schema.sql`, `clickhouse/init/02-search-columns.sql`, `clickhouse/init/03-users.sql`).
| Service | Port | Purpose | | Service | Port | Purpose |
|------------|------|------------------| |------------|------|------------------|
@@ -94,6 +94,54 @@ UI credentials are configured via `CAMELEER_UI_USER` / `CAMELEER_UI_PASSWORD` en
**Ed25519 signatures:** All SSE command payloads (config-update, deep-trace, replay) include a `signature` field. Agents verify payload integrity using the `serverPublicKey` received during registration. The server generates a new ephemeral keypair on each startup — agents must re-register to get the new key. **Ed25519 signatures:** All SSE command payloads (config-update, deep-trace, replay) include a `signature` field. Agents verify payload integrity using the `serverPublicKey` received during registration. The server generates a new ephemeral keypair on each startup — agents must re-register to get the new key.
### RBAC (Role-Based Access Control)
JWTs carry a `roles` claim. Endpoints are restricted by role:
| Role | Access |
|------|--------|
| `AGENT` | Data ingestion (`/data/**`), heartbeat, SSE events, command ack |
| `VIEWER` | Search, execution detail, diagrams, agent list |
| `OPERATOR` | VIEWER + send commands to agents |
| `ADMIN` | OPERATOR + user management (`/admin/**`) |
The env-var local user gets `ADMIN` role. Agents get `AGENT` role at registration.
### OIDC Login (Optional)
When `CAMELEER_OIDC_ENABLED=true`, the server supports external identity providers (e.g. Authentik, Keycloak):
```bash
# 1. SPA checks if OIDC is available
curl -s http://localhost:8081/api/v1/auth/oidc/config
# Returns: { "issuer": "...", "clientId": "...", "authorizationEndpoint": "..." }
# 2. After OIDC redirect, SPA sends the authorization code
curl -s -X POST http://localhost:8081/api/v1/auth/oidc/callback \
-H "Content-Type: application/json" \
-d '{"code":"auth-code-from-provider","redirectUri":"http://localhost:5173/callback"}'
# Returns: { "accessToken": "...", "refreshToken": "..." }
```
Local login remains available as fallback even when OIDC is enabled.
### User Management (ADMIN only)
```bash
# List all users
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8081/api/v1/admin/users
# Update user roles
curl -s -X PUT http://localhost:8081/api/v1/admin/users/{userId}/roles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"roles":["VIEWER","OPERATOR"]}'
# Delete user
curl -s -X DELETE http://localhost:8081/api/v1/admin/users/{userId} \
-H "Authorization: Bearer $TOKEN"
```
### Ingestion (POST, returns 202 Accepted) ### Ingestion (POST, returns 202 Accepted)
```bash ```bash
@@ -252,6 +300,13 @@ Key settings in `cameleer3-server-app/src/main/resources/application.yml`:
| `security.ui-user` | `admin` | UI login username (`CAMELEER_UI_USER` env var) | | `security.ui-user` | `admin` | UI login username (`CAMELEER_UI_USER` env var) |
| `security.ui-password` | `admin` | UI login password (`CAMELEER_UI_PASSWORD` env var) | | `security.ui-password` | `admin` | UI login password (`CAMELEER_UI_PASSWORD` env var) |
| `security.ui-origin` | `http://localhost:5173` | CORS allowed origin for UI (`CAMELEER_UI_ORIGIN` env var) | | `security.ui-origin` | `http://localhost:5173` | CORS allowed origin for UI (`CAMELEER_UI_ORIGIN` env var) |
| `security.jwt-secret` | *(random)* | HMAC secret for JWT signing (`CAMELEER_JWT_SECRET`). If set, tokens survive restarts |
| `security.oidc.enabled` | `false` | Enable OIDC login (`CAMELEER_OIDC_ENABLED`) |
| `security.oidc.issuer-uri` | | OIDC provider issuer URL (`CAMELEER_OIDC_ISSUER`) |
| `security.oidc.client-id` | | OAuth2 client ID (`CAMELEER_OIDC_CLIENT_ID`) |
| `security.oidc.client-secret` | | OAuth2 client secret (`CAMELEER_OIDC_CLIENT_SECRET`) |
| `security.oidc.roles-claim` | `realm_access.roles` | JSONPath to roles in OIDC id_token (`CAMELEER_OIDC_ROLES_CLAIM`) |
| `security.oidc.default-roles` | `VIEWER` | Default roles for new OIDC users (`CAMELEER_OIDC_DEFAULT_ROLES`) |
## Web UI Development ## Web UI Development
@@ -324,7 +379,7 @@ cameleer namespace:
Push to `main` triggers: **build** (UI npm + Maven, unit tests) → **docker** (buildx amd64 for server + UI, push to Gitea registry) → **deploy** (kubectl apply + rolling update). Push to `main` triggers: **build** (UI npm + Maven, unit tests) → **docker** (buildx amd64 for server + UI, push to Gitea registry) → **deploy** (kubectl apply + rolling update).
Required Gitea org secrets: `REGISTRY_TOKEN`, `KUBECONFIG_BASE64`, `CAMELEER_AUTH_TOKEN`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`, `CAMELEER_UI_USER` (optional), `CAMELEER_UI_PASSWORD` (optional). Required Gitea org secrets: `REGISTRY_TOKEN`, `KUBECONFIG_BASE64`, `CAMELEER_AUTH_TOKEN`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`, `CAMELEER_UI_USER` (optional), `CAMELEER_UI_PASSWORD` (optional), `CAMELEER_JWT_SECRET` (recommended — tokens survive restarts).
### Manual K8s Commands ### Manual K8s Commands