Skip to content

Commit 096b090

Browse files
Merged main into the branch
Signed-off-by: Dmytro Zaharnytskyi <zdmytro@redhat.com>
2 parents 94e3aa3 + a0419a0 commit 096b090

39 files changed

+2549
-1346
lines changed

deployment/base/maas-api/policies/auth-policy.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,12 @@ spec:
8282
selector: auth.identity.user.groups.@tostr
8383
key: X-MaaS-Group
8484
priority: 1
85+
# Subscription: from API key validation (when API key with subscription used)
86+
# This header is used by /v1/models to determine which subscription's models to return
87+
X-MaaS-Subscription:
88+
when:
89+
- predicate: request.headers.authorization.startsWith("Bearer sk-oai-")
90+
- predicate: auth.metadata.apiKeyValidation.subscription != ""
91+
plain:
92+
selector: auth.metadata.apiKeyValidation.subscription
93+
priority: 0

docs/content/architecture.md

Lines changed: 227 additions & 206 deletions
Large diffs are not rendered by default.

docs/content/configuration-and-management/model-listing-flow.md

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,39 +57,55 @@ If the API is not configured with a MaaSModelRef lister and namespace, or if lis
5757

5858
## Subscription Filtering and Aggregation
5959

60-
The `/v1/models` endpoint supports filtering and aggregating models across subscriptions using request headers.
60+
The `/v1/models` endpoint automatically filters models based on your authentication method and optional headers.
6161

62-
### Request Headers
62+
### Authentication-Based Behavior
6363

64-
- **`X-MaaS-Subscription`** (optional): Filter models to a specific subscription by name
65-
- **`X-MaaS-Return-All-Models`** (optional): When set to `"true"`, returns models from all subscriptions the user has access to
64+
#### API Key Authentication (Bearer sk-oai-*)
65+
When using an API key, the subscription is automatically determined from the key:
66+
- Returns **only** models from the subscription bound to the API key at mint time
67+
- The `X-MaaS-Subscription` header is automatically injected by the gateway
68+
- **No manual headers required**
6669

67-
!!! warning "Conflicting headers"
68-
You cannot specify both `X-MaaS-Subscription` and `X-MaaS-Return-All-Models` headers in the same request. This returns `400 Bad Request`.
70+
```bash
71+
# API key bound to "premium-subscription"
72+
curl -H "Authorization: Bearer sk-oai-abc123..." \
73+
https://maas.example.com/maas-api/v1/models
6974

70-
### Behavior Modes
75+
# Returns models from "premium-subscription" only
76+
```
7177

72-
#### Default (no header)
73-
Returns models from a single subscription:
74-
- If the user has access to only one subscription, models from that subscription are returned
75-
- If the user has access to multiple subscriptions, returns `403 Forbidden` with message: "user has access to multiple subscriptions, must specify subscription using X-MaaS-Subscription header"
78+
#### User Token Authentication (OpenShift/OIDC tokens)
79+
When using a user token, you have flexible options:
80+
81+
**Default (no X-MaaS-Subscription header)**:
82+
- Returns **all** models from all subscriptions you have access to
83+
- Models are deduplicated and subscription metadata is attached
7684

77-
#### Single Subscription (`X-MaaS-Subscription: <name>`)
78-
Returns only models accessible via the specified subscription:
7985
```bash
80-
curl -H "Authorization: Bearer $TOKEN" \
81-
-H "X-MaaS-Subscription: premium-subscription" \
86+
# User with access to "basic" and "premium" subscriptions
87+
curl -H "Authorization: Bearer $(oc whoami -t)" \
8288
https://maas.example.com/maas-api/v1/models
89+
90+
# Returns models from both subscriptions with subscription metadata
8391
```
8492

85-
#### All Subscriptions (`X-MaaS-Return-All-Models: true`)
86-
Returns models from all subscriptions the user has access to, with subscription metadata attached. If the user has access to zero subscriptions, returns HTTP 200 with an empty data array (not an error), allowing clients to handle this deterministically:
93+
**With X-MaaS-Subscription header** (optional):
94+
- Returns only models from the specified subscription
95+
- Behaves like an API key request - allows you to scope your query to a specific subscription
96+
8797
```bash
88-
curl -H "Authorization: Bearer $TOKEN" \
89-
-H "X-MaaS-Return-All-Models: true" \
98+
# Filter to only "premium" subscription models
99+
curl -H "Authorization: Bearer $(oc whoami -t)" \
100+
-H "X-MaaS-Subscription: premium-subscription" \
90101
https://maas.example.com/maas-api/v1/models
102+
103+
# Returns only "premium-subscription" models
91104
```
92105

106+
!!! tip "User token filtering"
107+
The `X-MaaS-Subscription` header allows user token requests to filter results to a specific subscription. This is useful when you have access to many subscriptions but only want to see models from one.
108+
93109
### Subscription Metadata
94110

95111
All models in the response include a `subscriptions` array with metadata for each subscription providing access to that model:
@@ -124,16 +140,22 @@ All models in the response include a `subscriptions` array with metadata for eac
124140

125141
### Deduplication Behavior
126142

127-
When `X-MaaS-Return-All-Models: true` is used, models are deduplicated by `(id, url)` key:
143+
Models are deduplicated by `(id, url, ownedBy)` key:
128144

129-
- **Same id + same URL**: Single entry with subscriptions aggregated into the `subscriptions` array
130-
- **Same id + different URLs**: Separate entries (different model endpoints)
145+
- **Same id + same URL + same MaaSModelRef (ownedBy)**: Single entry with subscriptions aggregated into the `subscriptions` array
146+
- **Different id, URL, or MaaSModelRef**: Separate entries
131147

132-
**Example:**
133-
- Model `gpt-3.5` at URL `https://example.com/gpt-3.5` is accessible via subscriptions A and B
148+
**User token authentication** (multiple subscriptions):
149+
- Model `gpt-3.5` from MaaSModelRef `namespace-a/model-a` at URL `https://example.com/gpt-3.5` is accessible via subscriptions A and B
134150
- Result: One entry with `subscriptions: [{name: "A"}, {name: "B"}]`
135-
- Model `gpt-3.5` at URL `https://example.com/gpt-3.5-premium` is only in subscription B
136-
- Result: Separate entry with `subscriptions: [{name: "B"}]`
151+
- Model `gpt-3.5` from MaaSModelRef `namespace-b/model-b` at the same URL is only in subscription B
152+
- Result: Separate entry with `subscriptions: [{name: "B"}]` (different MaaSModelRef)
153+
- Model `gpt-3.5` at URL `https://example.com/gpt-3.5-premium` from `namespace-a/model-a` is only in subscription B
154+
- Result: Separate entry with `subscriptions: [{name: "B"}]` (different URL)
155+
156+
**API key authentication** (single subscription):
157+
- Deduplication handles edge cases where multiple MaaSModelRef resources point to the same model endpoint
158+
- Each unique MaaSModelRef resource appears as a separate entry
137159

138160
!!! tip "Subscription metadata fields"
139161
The `displayName` and `description` fields are read from the MaaSSubscription CRD's `spec.displayName` and `spec.description` fields. If these fields are not set in the CRD, they will be empty strings in the response.

docs/content/configuration-and-management/quota-and-access-configuration.md

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ spec:
121121
tokenRateLimits:
122122
- limit: 100
123123
window: 1m
124+
priority: 10
124125
EOF
125126
```
126127

@@ -162,6 +163,7 @@ spec:
162163
tokenRateLimits:
163164
- limit: 100000
164165
window: 24h
166+
priority: 20
165167
tokenMetadata:
166168
organizationId: "premium-org"
167169
costCenter: "ai-team"
@@ -216,20 +218,7 @@ Users will get subscription access on their next request (after group membership
216218

217219
## Multiple Subscriptions per User
218220

219-
When a user belongs to multiple groups that each have a subscription:
220-
221-
1. **Single subscription** — No `X-MaaS-Subscription` header needed
222-
2. **Multiple subscriptions** — Client **must** send `X-MaaS-Subscription: <subscription-name>` to specify which subscription's rate limits apply
223-
224-
Example for a user in both `free-users` and `premium-users`:
225-
226-
```bash
227-
# Use free subscription limits
228-
curl -H "X-MaaS-Subscription: free-subscription" ...
229-
230-
# Use premium subscription limits
231-
curl -H "X-MaaS-Subscription: premium-subscription" ...
232-
```
221+
When a user belongs to multiple groups that each have a subscription, the access depends on the API key used. A subscription is bound to each API key at minting (explicit or highest priority). See [Understanding Token Management](token-management.md).
233222

234223
## Troubleshooting
235224

docs/content/configuration-and-management/subscription-known-issues.md

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,6 @@
22

33
This document describes known issues and operational considerations for the subscription-based MaaS Platform.
44

5-
## X-MaaS-Subscription Header
6-
7-
### Multiple Subscriptions Require Header
8-
9-
**Impact:** High
10-
11-
**Description:**
12-
13-
When a user belongs to multiple groups that each have a MaaSSubscription, the client **must** send the `X-MaaS-Subscription` header to specify which subscription's rate limits apply. If the header is omitted, the MaaS API returns an error and the request is denied with **403 Forbidden**.
14-
15-
**Example:**
16-
17-
```text
18-
User in groups: [system:authenticated, premium-users]
19-
Subscriptions: free-subscription (system:authenticated), premium-subscription (premium-users)
20-
21-
Request without header → 403 "must specify X-MaaS-Subscription"
22-
Request with X-MaaS-Subscription: premium-subscription → 200 OK (premium limits apply)
23-
```
24-
25-
**Workaround:**
26-
27-
- Ensure clients send `X-MaaS-Subscription: <subscription-name>` when users can have multiple subscriptions
28-
- Document which subscription names to use for each user segment
29-
- Consider using a single subscription per user segment to avoid header requirement
30-
315
## Subscription Selection Caching
326

337
### Cache TTL for Subscription Selection
@@ -55,11 +29,11 @@ Authorino caches the result of the MaaS API subscription selection call (e.g., 6
5529

5630
**Description:**
5731

58-
API keys store the user's groups at creation time. If a user's group membership changes after the key was created:
32+
API keys store the user's groups and bound subscription name at creation time. If a user's group membership changes after the key was created:
5933

60-
- The key still carries the **old** groups until it is revoked and recreated
61-
- Subscription selection uses the groups from the key validation response (the stored snapshot)
62-
- The user must create a new API key to get updated group membership and subscription access
34+
- The key still carries the **old** groups and subscription until it is revoked and recreated
35+
- Subscription metadata for gateway inference uses the stored groups and subscription from validation
36+
- The user must create a new API key to pick up new groups or a different default subscription
6337

6438
**Workaround:**
6539

@@ -68,5 +42,6 @@ API keys store the user's groups at creation time. If a user's group membership
6842

6943
## Related Documentation
7044

45+
- [Understanding Token Management](token-management.md)
7146
- [Access and Quota Overview](subscription-overview.md)
7247
- [Quota and Access Configuration](quota-and-access-configuration.md)

0 commit comments

Comments
 (0)