Skip to content

Commit 1d7fa44

Browse files
authored
Merge pull request #603 from omertuc/authdoc
LCORE-597: Document auth/authz
2 parents 9839dd2 + 3448fe8 commit 1d7fa44

File tree

2 files changed

+261
-98
lines changed

2 files changed

+261
-98
lines changed

README.md

Lines changed: 1 addition & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ The service includes comprehensive user data collection capabilities for various
3636
* [Control model/provider overrides via authorization](#control-modelprovider-overrides-via-authorization)
3737
* [Safety Shields](#safety-shields)
3838
* [Authentication](#authentication)
39-
* [K8s based authentication](#k8s-based-authentication)
40-
* [JSON Web Keyset based authentication](#json-web-keyset-based-authentication)
41-
* [No-op authentication](#no-op-authentication)
4239
* [CORS](#cors)
4340
* [Default values](#default-values)
4441
* [Allow credentials](#allow-credentials)
@@ -397,101 +394,7 @@ utilized:
397394

398395
## Authentication
399396

400-
Currently supported authentication modules are:
401-
* `k8s` Kubernetes based authentication
402-
* `jwk-token` JSON Web Keyset based authentication
403-
* `noop` No operation authentication (default)
404-
* `noop-with-token` No operation authentication with token
405-
406-
### K8s based authentication
407-
408-
K8s based authentication is suitable for running the Lightspeed Stack in Kubernetes environments.
409-
The user accessing the service must have a valid Kubernetes token and the appropriate RBAC permissions to access the service.
410-
The user must have `get` permission on the Kubernetes RBAC non-resource URL `/ls-access`.
411-
Here is an example of granting `get` on `/ls-access` via a ClusterRole’s nonResourceURLs rule.
412-
Example:
413-
```yaml
414-
# Allow GET on non-resource URL /ls-access
415-
apiVersion: rbac.authorization.k8s.io/v1
416-
kind: ClusterRole
417-
metadata:
418-
name: lightspeed-access
419-
rules:
420-
- nonResourceURLs: ["/ls-access"]
421-
verbs: ["get"]
422-
---
423-
# Bind to a user, group, or service account
424-
apiVersion: rbac.authorization.k8s.io/v1
425-
kind: ClusterRoleBinding
426-
metadata:
427-
name: lightspeed-access-binding
428-
roleRef:
429-
apiGroup: rbac.authorization.k8s.io
430-
kind: ClusterRole
431-
name: lightspeed-access
432-
subjects:
433-
- kind: User # or ServiceAccount, Group
434-
name: SOME_USER_OR_SA
435-
apiGroup: rbac.authorization.k8s.io
436-
```
437-
438-
Configuring K8s based authentication requires the following steps:
439-
1. Enable K8s authentication module
440-
```yaml
441-
authentication:
442-
module: "k8s"
443-
```
444-
2. Configure the Kubernetes authentication settings.
445-
When deploying Lightspeed Stack in a Kubernetes cluster, it is not required to specify cluster connection details.
446-
It automatically picks up the in-cluster configuration or through a kubeconfig file.
447-
This step is not neccessary.
448-
When running outside a kubernetes cluster or connecting to external Kubernetes clusters, Lightspeed Stack requires the cluster connection details in the configuration file:
449-
- `k8s_cluster_api` Kubernetes Cluster API URL. The URL of the K8S/OCP API server where tokens are validated.
450-
- `k8s_ca_cert_path` Path to the CA certificate file for clusters with self-signed certificates.
451-
- `skip_tls_verification` Whether to skip TLS verification.
452-
```yaml
453-
authentication:
454-
module: "k8s"
455-
skip_tls_verification: false
456-
k8s_cluster_api: "https://your-k8s-api-server:6443"
457-
k8s_ca_cert_path: "/path/to/ca.crt"
458-
```
459-
460-
### JSON Web Keyset based authentication
461-
462-
JWK (JSON Web Keyset) based authentication is suitable for scenarios where you need to authenticate users based on tokens. This method is commonly used in web applications and APIs.
463-
464-
To configure JWK based authentication, you need to specify the following settings in the configuration file:
465-
- `module` must be set to `jwk-token`
466-
- `jwk_config` JWK configuration settings must set at least `url` field:
467-
- `url`: The URL of the JWK endpoint.
468-
- `jwt_configuration`: JWT configuration settings.
469-
- `user_id_claim`: The key of the user ID in JWT claim.
470-
- `username_claim`: The key of the username in JWT claim.
471-
472-
```yaml
473-
authentication:
474-
module: "jwk-token"
475-
jwk_config:
476-
url: "https://your-jwk-url"
477-
jwt_configuration:
478-
user_id_claim: user_id
479-
username_claim: username
480-
```
481-
482-
### No-op authentication
483-
484-
Lightspeed Stack provides 2 authentication module to bypass the authentication and authorization checks:
485-
- `noop` No operation authentication (default)
486-
- `noop-with-token` No operation authentication accepting a bearer token
487-
488-
If authentication module is not specified, Lightspeed Stack will use `noop` by default.
489-
To activate `noop-with-token`, you need to specify it in the configuration file:
490-
491-
```yaml
492-
authentication:
493-
module: "noop-with-token"
494-
```
397+
See [authentication and authorization](docs/auth.md).
495398

496399
## CORS
497400

docs/auth.md

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# Authentication and Authorization
2+
3+
Lightspeed Core Stack implements a modular authentication and authorization
4+
system with multiple authentication methods. Authorization is configurable
5+
through role-based access control.
6+
7+
## Authentication configuration
8+
9+
The authentication system is configured via the `authentication` section in
10+
the configuration file.
11+
12+
## Authentication Modules
13+
14+
Authentication is handled through selectable modules configured via the
15+
`module` field in the authentication configuration.
16+
17+
### No-op (`noop`)
18+
19+
Development-only authentication that bypasses security checks.
20+
21+
**Configuration:**
22+
```yaml
23+
authentication:
24+
module: noop
25+
```
26+
27+
**Behavior:**
28+
- Accepts any request without token validation
29+
- Extracts `user_id` from query parameters (defaults to `00000000-0000-0000-0000-000`)
30+
- Uses fixed username `lightspeed-user`
31+
32+
### No-op with Token (`noop-with-token`)
33+
34+
Development authentication that requires tokens but doesn't validate them.
35+
36+
**Configuration:**
37+
```yaml
38+
authentication:
39+
module: noop-with-token
40+
```
41+
42+
**Behavior:**
43+
- Extracts bearer token from the `Authorization` header
44+
- Same user ID and username handling as `noop`
45+
- Token is passed through unvalidated for downstream use
46+
47+
### Kubernetes (`k8s`)
48+
49+
K8s based authentication is suitable for running the Lightspeed Stack in
50+
Kubernetes environments. The user accessing the service must have a valid
51+
Kubernetes token and the appropriate RBAC permissions to access the service.
52+
The user must have the `get` permission on the Kubernetes RBAC non-resource URL
53+
`/ls-access`. Here is an example of granting `get` on `/ls-access` via a
54+
ClusterRole’s nonResourceURLs rule:
55+
56+
```yaml
57+
# Allow GET on non-resource URL /ls-access
58+
apiVersion: rbac.authorization.k8s.io/v1
59+
kind: ClusterRole
60+
metadata:
61+
name: lightspeed-access
62+
rules:
63+
- nonResourceURLs: ["/ls-access"]
64+
verbs: ["get"]
65+
---
66+
# Bind to a user, group, or service account
67+
apiVersion: rbac.authorization.k8s.io/v1
68+
kind: ClusterRoleBinding
69+
metadata:
70+
name: lightspeed-access-binding
71+
roleRef:
72+
apiGroup: rbac.authorization.k8s.io
73+
kind: ClusterRole
74+
name: lightspeed-access
75+
subjects:
76+
- kind: User # or ServiceAccount, Group
77+
name: SOME_USER_OR_SA
78+
apiGroup: rbac.authorization.k8s.io
79+
```
80+
81+
**Configuration:**
82+
83+
When deploying Lightspeed Stack in a Kubernetes cluster, it is not required to
84+
specify cluster connection details, it automatically picks up the in-cluster
85+
configuration or through a kubeconfig file.
86+
87+
When running outside a kubernetes cluster or connecting to external Kubernetes
88+
clusters, Lightspeed Stack requires the cluster connection details in the
89+
configuration file:
90+
91+
- `k8s_cluster_api` Kubernetes Cluster API URL. The URL of the k8s/OCP API server where tokens are validated.
92+
- `k8s_ca_cert_path` Path to the CA certificate file for clusters with self-signed certificates.
93+
- `skip_tls_verification` Whether to skip TLS verification.
94+
95+
For example:
96+
97+
```yaml
98+
authentication:
99+
module: k8s
100+
k8s_cluster_api: https://kubernetes.default.svc # optional, will be auto-detected
101+
k8s_ca_cert_path: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt # optional, will be auto-detected
102+
skip_tls_verification: false # optional, insecure
103+
```
104+
105+
**Behavior:**
106+
- Validates bearer tokens via the Kubernetes TokenReview API
107+
- Performs authorization checks using SubjectAccessReview (SAR)
108+
- Checks access to configured virtual path (default: `/ls-access`) with `get` verb
109+
- Extracts user ID and username from token claims
110+
- Special handling for the `kube:admin` user (uses cluster ID as user ID)
111+
112+
**Requirements:**
113+
- Valid Kubernetes service account token in the `Authorization` header
114+
- RBAC rules granting access to the virtual path
115+
- Cluster access or kubeconfig file
116+
117+
### JWK Token (`jwk-token`)
118+
119+
JWK (JSON Web Keyset) based authentication is suitable for scenarios where you
120+
need to authenticate users based on tokens. This method is commonly used in web
121+
applications and APIs.
122+
123+
Users provide a JWT (JSON Web Token) in the `Authorization` header of their
124+
requests. This JWT is validated against the JWK set fetched from the configured
125+
URL.
126+
127+
**Configuration:**
128+
```yaml
129+
authentication:
130+
module: jwk-token
131+
jwk_config:
132+
url: https://auth.example.com/.well-known/jwks.json
133+
jwt_configuration:
134+
user_id_claim: sub # optional, defaults to 'sub'
135+
username_claim: name # optional, defaults to 'preferred_username'
136+
role_rules: [] # optional role extraction rules. See Authorization section for details.
137+
```
138+
139+
**Behavior:**
140+
- Fetches JWK set from configured URL (cached for 1 hour)
141+
- Validates JWT signature against JWK set
142+
- Extracts user ID and username from configurable JWT claims
143+
- Returns default credentials (guest-like) if no `Authorization` header present (guest access)
144+
145+
## Authorization System
146+
147+
Authorization is controlled through role-based access control using two resolver types.
148+
149+
### Role Resolution
150+
151+
Determines user roles based on authentication method:
152+
153+
**No-op/K8s Authentication:**
154+
- Uses a no-op role resolver
155+
- All users get the special `*` (everyone) role only
156+
- To be expanded in the future
157+
158+
**JWK Token Authentication:**
159+
- Uses JWT claims to determine user roles through JSONPath expressions
160+
- Falls back to a no-op resolver if no role rules are configured
161+
162+
#### JWT Role Rules
163+
164+
Extract roles from JWT claims using JSONPath expressions, for example:
165+
166+
```yaml
167+
authentication:
168+
module: jwk-token
169+
jwk_config:
170+
jwt_configuration:
171+
role_rules:
172+
- jsonpath: "$.realm_access.roles[*]"
173+
operator: contains
174+
value: "manager"
175+
roles: ["manager"]
176+
- jsonpath: "$.org_id"
177+
operator: "equals"
178+
value: [["dummy_corp"]]
179+
roles: ["dummy_employee"]
180+
- jsonpath: "$.groups[*]"
181+
operator: in
182+
value: ["developers", "qa"]
183+
roles: ["developer"]
184+
negate: false
185+
```
186+
187+
**Fields:**
188+
- `jsonpath`: JSONPath expression to extract values from JWT claims.
189+
- `operator`: Comparison operator (see below)
190+
- `value`: Value(s) to evaluate the extracted values and operator against
191+
- `roles`: List of roles to assign if the rule matches
192+
- `negate`: If true, inverts the rule match result (optional, defaults to false)
193+
194+
Note that the JSONPath expression always yields a list of values, even for
195+
single-value expressions, so comparisons should be done accordingly.
196+
197+
**Operators:**
198+
- `equals`: Exact match
199+
- `contains`: Value contains the specified string
200+
- `in`: Value is in the specified list
201+
- `match`: Regex pattern match (uses pre-compiled patterns)
202+
203+
### Access Resolution
204+
205+
Various operations inside lightspeed require authorization checks. Those
206+
operations are associated with actions (e.g. `query`, `info`, `admin`).
207+
208+
Once user roles are determined, checking whether a user is allowed to perform
209+
an action is done through access resolvers.
210+
211+
**No-op resolver:**
212+
213+
A resolver which uses a no-op access resolver that grants all users access to
214+
all actions, used when no access rules are configured no-op authentication is
215+
configured, or at-least currently when k8s authentication is configured.
216+
217+
**Rule-based Access:**
218+
219+
A resolver which does the obvious thing of checking whether any of the user's
220+
roles is allowed to perform the requested action based on the access rules in
221+
the authorization configuration. It also grants all users which have the `admin`
222+
action unrestricted access to all other actions.
223+
224+
#### Access Rules
225+
226+
Define which roles can perform which actions:
227+
228+
```yaml
229+
authorization:
230+
access_rules:
231+
# `*` is a special role that is given to all users
232+
- role: "*"
233+
actions: ["query", "info"]
234+
- role: "manager"
235+
# admin is a special *action* that grants unrestricted access to all actions.
236+
# Note that only the `admin` *action* is special, there is no special `admin` role.
237+
actions: ["admin"]
238+
- role: "dummy_employee"
239+
actions: ["list_conversations"]
240+
- role: "developer"
241+
actions: ["query", "get_config", "list_conversations"]
242+
```
243+
244+
**Available Actions:**
245+
- `admin` - If a user has this action, they automatically can perform all other actions
246+
- `query` - Access query endpoints
247+
- `query_other_conversations` - Query conversations not owned by the user
248+
- `streaming_query` - Access streaming query endpoints
249+
- `info` - Access the `/` endpoint, `/info` endpoint, `/readiness` endpoint, and `/liveness` endpoint
250+
- `get_config` - Access the `/config` endpoint
251+
- `get_models` - Access the `/models` endpoint
252+
- `get_metrics` - Access the `/metrics` endpoint
253+
- `list_conversations` - Access the `/conversations` endpoint
254+
- `list_other_conversations` - Access conversations not owned by the user
255+
- `get_conversation` - `GET` conversations from `/conversations/{conversation_id}` endpoint
256+
- `read_other_conversations` - Read conversations not owned by the user
257+
- `delete_conversation` - `DELETE` conversations from `/conversations/{conversation_id}` endpoint
258+
- `delete_other_conversations` - Delete conversations not owned by the user
259+
- `feedback` - Access the `/feedback` endpoint
260+
- `model_override` - Allow user to choose the model when querying

0 commit comments

Comments
 (0)