diff --git a/docs/README.md b/docs/README.md index 9d11e25..4217508 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,6 +4,8 @@ This directory contains detailed documentation for Kerberos features. Current topic documents include: +- [Admin Connector](./admin-connector.md) +- [Admin Debugging](./admin-debugging.md) - [Authentication](./authentication.md) - [Configuration](./configuration.md) - [Flow Components](./flow-components.md) diff --git a/docs/admin-connector.md b/docs/admin-connector.md new file mode 100644 index 0000000..5c4f28c --- /dev/null +++ b/docs/admin-connector.md @@ -0,0 +1,68 @@ +# Admin Connector + +The admin connector is a standalone binary (`cmd/admin-connector`) that acts as an authenticating reverse proxy. It validates that incoming requests carry a valid Kerberos admin session cookie and, if so, forwards the request to any configured upstream service. + +## Purpose + +The admin connector is used when a service should only be accessible to users who hold a valid Kerberos admin session. The connector reads the session cookie from each incoming request, checks it against the Kerberos admin session store, and either proxies the request to the configured target or rejects it with `401 Unauthorized`. + +``` +Client → Admin Connector (validates admin session cookie) → Target service +``` + +The connector: + +1. Reads the session cookie from the incoming request. +2. Queries the Kerberos admin persistence store to verify the session exists and has not expired. +3. Forwards the request to the configured upstream target if the session is valid. +4. Returns `401 Unauthorized` if the session is missing or expired. + +--- + +## Configuration + +The connector is configured via a single JSON file passed with the `--config` flag, and a set of environment variables. + +### Config File + +The config file supports the following high-level sections: + +- **`persistence`** (required) — points to the same database used by Kerberos (SQLite or PostgreSQL) so the connector can validate sessions. +- **`tls`** (optional) — configures TLS for the connector's own listening server. +- **`targetTls`** (optional) — configures TLS for the outbound connection to the target. +- **`origins`** (optional) — controls CORS / origin filtering for browser clients. + +--- + +### Environment Variables + +The connector is also configured through environment variables. These apply on top of (or instead of) the config file fields and control the runtime behaviour of the binary itself. + +| Variable | Default | Description | +|---|---|---| +| `TARGET` | *(required)* | Host and port of the upstream service to forward authenticated requests to, e.g. `my-service:8080`. | +| `PORT` | `30100` | Port on which the connector listens. | +| `READ_TIMEOUT_SECONDS` | `5` | HTTP server read timeout in seconds. | +| `WRITE_TIMEOUT_SECONDS` | `5` | HTTP server write timeout in seconds. | +| `OBSERVABILITY_ENABLED` | `true` | Enables or disables OpenTelemetry instrumentation. | +| `RUNTIME_METRICS` | `true` | When true, exposes Go runtime metrics via OpenTelemetry. | +| `LOG_TO_CONSOLE` | `false` | When true, logs are written in a human-readable console format. | +| `LOG_VERBOSITY` | `0` | Increases log verbosity. Higher values emit more detail. | +| `VERSION` | `unset` | Sets the service version reported in telemetry. | + +--- + +## Observability + +When observability is enabled, the connector emits the following OpenTelemetry metrics: + +| Metric | Description | +|---|---| +| `admin_connector_calls_total` | Total number of requests forwarded to the target. | +| `admin_connector_calls_denied_total` | Total number of requests rejected due to missing or expired sessions. | +| `admin_connector_callout_failures_total` | Total number of errors encountered while proxying to the target. | + +Each request also generates an OpenTelemetry span (server kind) containing the HTTP method and URL. + + + diff --git a/docs/admin-debugging.md b/docs/admin-debugging.md new file mode 100644 index 0000000..5ca48d3 --- /dev/null +++ b/docs/admin-debugging.md @@ -0,0 +1,205 @@ +# Admin Debugging + +Kerberos provides a debugging feature that records the full flow of individual requests as they pass through the gateway. Debugging is scoped per backend and time-boxed to a configurable session duration, so it can be safely enabled in a running environment without lasting impact. + +## How It Works + +When a debug session is active for a backend: + +1. The Observability flow component creates a `DebuggedCall` object and places it in the request context instead of the usual no-op. +2. Each flow component (Observability, Router, Auth, OAS Validator, Forwarder) records a _flow transition_ into the call as it starts and finishes processing. +3. After the response is sent, the call is finalised and persisted to the database. +4. The recorded calls can be retrieved via the admin API for inspection. + +A rate limit of 100 calls per second applies across all active debug sessions to limit overhead. + +--- + +## Permissions + +All debug endpoints require the `debugger` permission. The super user account always has this permission. Regular admin users need the permission assigned explicitly. + +--- + +## Debug Session Lifecycle + +``` +Start session → (session active) → calls are recorded → Stop / Delete / session expires +``` + +- **Start**: Opens a debug session for a backend, with a configurable expiry duration. +- **Extend**: Pushes the expiry further out. The total session lifetime cannot exceed one hour from start. +- **Stop**: Marks the session as stopped (no new calls are recorded) but keeps the session and its calls available for retrieval. +- **Delete**: Permanently removes the session and all associated call records. + +Only one active session per backend is allowed at a time. Starting a session when one is already active returns `409 Conflict`. + +--- + +## API Reference + +All endpoints are authenticated. They require an active admin session (via the admin login flow) and the `debugger` permission. + +### Debug Sessions + +#### Start a debug session + +``` +POST /api/admin/debug/{backend}/sessions +``` + +Request body (optional): + +```json +{ + "durationSeconds": 300 +} +``` + +| Field | Description | +|---|---| +| `durationSeconds` | How long (in seconds) the session should remain active. Minimum `60`, maximum `3600`. Defaults to `300` (5 minutes). | + +Returns `200` with the created `DebugSession` object, or `409` if an active session already exists. + +#### List debug sessions + +``` +GET /api/admin/debug/{backend}/sessions +``` + +Returns all sessions (including expired and stopped ones) for the given backend. + +#### Get a debug session + +``` +GET /api/admin/debug/{backend}/sessions/{sessionId} +``` + +Returns the `DebugSession` with the given ID. + +#### Stop a debug session + +``` +POST /api/admin/debug/{backend}/sessions/{sessionId} +``` + +Marks the session as stopped. Recording halts immediately; previously captured calls remain available. Returns `204` on success. + +#### Extend a debug session + +``` +PUT /api/admin/debug/{backend}/sessions/{sessionId} +``` + +Request body (required): + +```json +{ + "additionalDurationSeconds": 300 +} +``` + +Adds `additionalDurationSeconds` to the session's current expiry. The total session lifetime (measured from `startedAt`) cannot exceed one hour. Returns `200` with the updated session. + +#### Delete a debug session + +``` +DELETE /api/admin/debug/{backend}/sessions/{sessionId} +``` + +Permanently deletes the session and all its call records. Returns `204`. + +--- + +### Debug Session Calls + +#### List calls for a session + +``` +GET /api/admin/debug/{backend}/sessions/{sessionId}/calls +``` + +Query parameters: + +| Parameter | Description | +|---|---| +| `includeTransitions` | When `true`, each call includes its full list of flow transitions. Defaults to `false`. | + +Returns an array of `DebugSessionCall` objects. + +#### Get a specific call + +``` +GET /api/admin/debug/{backend}/sessions/{sessionId}/calls/{callId} +``` + +Returns a single `DebugSessionCall` including all its flow transitions. + +--- + +## Data Model + +### `DebugSession` + +| Field | Description | +|---|---| +| `id` | Unique session identifier. | +| `backend` | The backend name this session is attached to. | +| `startedAt` | When the session was created. | +| `expiresAt` | When the session will stop recording new calls. | +| `stoppedAt` | When the session was manually stopped. `null` if still active. | + +### `DebugSessionCall` + +| Field | Description | +|---|---| +| `id` | Unique call identifier. | +| `method` | HTTP method of the request. | +| `url` | Request URL as seen by the gateway. | +| `statusCode` | HTTP status code returned to the client. | +| `startedAt` | When the gateway started processing the request. | +| `stoppedAt` | When the gateway finished sending the response. | +| `flowTransitions` | Ordered list of transitions recorded by each flow component. | + +### `FlowTransition` + +Each `FlowTransition` represents one component's processing window during the call: + +| Field | Description | +|---|---| +| `component` | Name of the flow component (e.g. `observability`, `auth`, `forwarder`). | +| `direction` | `inbound` when the component is receiving the request; `outbound` when returning. | +| `startedAt` | When this transition began. | +| `stoppedAt` | When this transition ended. | +| `result.outcome` | `success` or `failure`. | +| `result.cause` | Non-empty only on `failure` — a short description of why the component rejected the request. | + +--- + +## Typical Debugging Workflow + +1. **Log in** to the admin API with an account that holds the `debugger` permission. +2. **Start a debug session** for the backend you want to inspect: + ``` + POST /api/admin/debug/my-service/sessions + {"durationSeconds": 120} + ``` +3. **Send one or more requests** through the gateway to the backend. +4. **List the captured calls**: + ``` + GET /api/admin/debug/my-service/sessions/{sessionId}/calls?includeTransitions=true + ``` +5. **Inspect individual calls** to see which flow component rejected or delayed the request. +6. **Stop or delete the session** when done: + ``` + POST /api/admin/debug/my-service/sessions/{sessionId} + ``` + +--- + +## Notes + +- Debugging adds a small per-request overhead (database write on call finalisation). Keep sessions short and targeted to production backends. +- The rate limiter silently drops recording (reverts to a no-op call) if the 100-calls/second threshold is exceeded; the request itself is still processed normally. +- Expired sessions are not automatically deleted. Use the delete endpoint to clean up old sessions and their call records. diff --git a/docs/authentication.md b/docs/authentication.md index 3900974..1d192ab 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -28,22 +28,23 @@ Backends can be configured with path exemptions that bypass authentication. Thes ## Basic Authentication -Basic authentication is the primary authentication method supported by Kerberos. It uses session-based authentication with the following components: +Basic authentication is the primary authentication method supported by Kerberos. It uses session-based authentication with the following components. Organisations, users, groups, and sessions managed by the basic authentication method are described in detail in the [Organisations](./organizations.md) document. ### Session Management - Sessions are created upon successful login via the `/api/auth/basic/organisations/{orgID}/login` endpoint -- Each session is identified by a unique session ID returned in the `X-Krb-Session` header +- Each session is identified by a unique session ID stored in a `session` HTTP-only cookie set on the response - Sessions have a 15-minute expiration time -- Subsequent requests must include the session ID in the `X-Krb-Session` header +- Subsequent requests must include the `session` cookie automatically sent by the browser (or HTTP client) +- The session can be refreshed before expiry via the `/api/auth/basic/organisations/{orgID}/refresh` endpoint, which resets the 15-minute window - Users can logout via the `/api/auth/basic/organisations/{orgID}/logout` endpoint, which invalidates all their active sessions ### Authentication Process 1. **Login**: Users provide username, password, and organisation ID -2. **Session Creation**: On successful authentication, a session is created and its ID is returned +2. **Session Creation**: On successful authentication, a session is created and its ID is stored in an HTTP-only `session` cookie returned in the response 3. **Request Authentication**: For each authenticated request, the authorizer: - - Extracts the session ID from the `X-Krb-Session` header + - Extracts the session ID from the `session` cookie - Queries the database to validate the session - Checks if the session has expired - Adds `X-Krb-Org` and `X-Krb-User` headers to the request with the user's organisation and user IDs @@ -89,7 +90,7 @@ Administrator accounts are automatically granted access to operations that would ### Super User Accounts -In addition to organisation administrators, Kerberos supports super user accounts that have access to all auth API paths across all organisations. These accounts are typically used for system administration and are configured separately from regular organisation administrators. Super user accounts bypass most authorization checks and are intended for use by the administration API (note: the admin functionality is being moved and is not covered in this documentation). +In addition to organisation administrators, Kerberos supports super user accounts that have access to all auth API paths across all organisations. These accounts are typically used for system administration and are configured separately from regular organisation administrators. Super user accounts bypass most authorization checks and are intended for use by the admin API. Super user credentials are configured in the `admin.superUser` section of the Kerberos configuration file. ### Creating Administrator Accounts diff --git a/docs/routing.md b/docs/routing.md index 9d20e73..2fbb69e 100644 --- a/docs/routing.md +++ b/docs/routing.md @@ -2,7 +2,7 @@ HTTP handler call order: -1. OTEL +1. Observability 2. Router (fetch backend) 3. Forward (using router backend)