Commit 152e531
chore: upgrade/validate Kuadrant 1.4.2 (opendatahub-io#643)
# Upgrade to Kuadrant 1.4.2
https://redhat.atlassian.net/browse/RHOAIENG-55749
https://redhat.atlassian.net/browse/RHOAIENG-54157
## Summary
Upgrades deployment to use Kuadrant 1.4.2 (from 1.3.1) to enable
authorization header stripping for security and migrates AuthPolicy
configurations to the new schema format required
by Authorino v0.23.1.
## Changes
### 1. Kuadrant Upgrade
- Update `scripts/deploy.sh` to install Kuadrant v1.4.2 catalog (was
v1.3.1)
- Brings Authorino v0.23.1 (was v0.22.0)
- **Required for authorization header stripping capability**
### 2. Authorization Header Stripping for Internal Models
**Security enhancement to prevent credential exfiltration**
Added authorization header stripping in
`maas-controller/pkg/controller/maas/maasauthpolicy_controller.go` for
internal KServe models.
**Problem:** User credentials (OpenShift tokens or API keys) were being
forwarded to model backends, creating a credential exfiltration risk
where malicious or compromised models
could capture and misuse tokens.
**Solution:** Authorino now strips the Authorization header before
forwarding requests to internal model backends:
```go
rule["response"] = map[string]any{
"success": map[string]any{
"headers": map[string]any{
// Strip Authorization header to prevent token exfiltration
"Authorization": map[string]any{
"plain": map[string]any{
"value": "",
},
"key": "authorization",
"metrics": false,
"priority": int64(0),
},
// ... other headers (username, groups, subscription)
Impact:
- User tokens and API keys are validated by Authorino but NOT forwarded
to model services
- Applies to both inference requests and model discovery probing
- Only affects internal KServe models (ExternalModel resources with
credentialRef are unaffected)
Version requirement verified: Testing confirmed that Kuadrant 1.4.1 /
Authorino v0.24.0 does not properly strip headers (appends empty value
but leaves original token present).
Kuadrant 1.4.2 / Authorino v0.23.1 correctly replaces the authorization
header.
3. AuthPolicy Schema Migration
Migrate deployment/base/maas-api/policies/auth-policy.yaml from CEL
predicate format to selector/operator format:
Before (v1.3.1 format):
when:
- predicate: request.headers.authorization.startsWith("Bearer sk-oai-")
After (v1.4.2 format):
when:
- selector: request.headers.authorization
operator: matches
value: "^Bearer sk-oai-.*"
4. Fallback Header Handling
- Removed negative lookahead regex from fallback headers
(X-MaaS-Username-OC, X-MaaS-Group-OC)
- Authorino v0.23.1's matches operator doesn't support ^Bearer
(?!sk-oai-).* pattern
- Now rely on priority system instead:
- API key headers: priority: 0 (higher priority, evaluated first)
- Fallback headers: priority: 1 (lower priority, only used when API key
when clause doesn't match)
5. Subscription Header Fix
Fixed handling of multiple X-Maas-Subscription header values in
maas-api/internal/handlers/models.go:
Problem: When clients send x-maas-subscription header (even empty
string), Authorino appends its injected value, resulting in:
X-Maas-Subscription: ["", "simulator-subscription"]
Gin's GetHeader() returns only the first value (empty string), causing
403 errors.
Solution: Iterate header values in reverse order and take the last
non-empty value:
headerValues := c.Request.Header.Values("X-Maas-Subscription")
for i := len(headerValues) - 1; i >= 0; i-- {
trimmed := strings.TrimSpace(headerValues[i])
if trimmed != "" {
requestedSubscription = trimmed
break
}
}
This ensures we use Authorino's validated subscription when available,
while still supporting clients that don't send the header.
6. Documentation Updates
Updated version requirements in README.md and
docs/content/install/prerequisites.md:
- MaaS v0.2.0+ requires Kuadrant 1.4.2+ (ODH) or RHCL 1.3+ (RHOAI)
- Added detailed explanation of authorization header stripping security
requirement
Testing
All E2E tests passing (74 passed):
Fixed by subscription header change:
- ✅ test_empty_subscription_header_value - correctly auto-selects
subscription when empty header sent
- ✅ test_api_key_ignores_subscription_header - correctly uses API key's
bound subscription, ignoring client header
Verified working:
- ✅ API key authentication with subscription binding
- ✅ OpenShift token authentication
- ✅ Subscription-scoped model filtering
- ✅ Rate limiting with TokenRateLimitPolicy
- ✅ Namespace-scoped resource access
- ✅ Cross-namespace model references
Authorization header stripping verified:
- ✅ Kuadrant 1.4.2 / Authorino v0.23.1: Header correctly stripped
(backend receives empty string)
- ❌ Kuadrant 1.4.1 / Authorino v0.24.0: Header NOT properly stripped
(original token still present)
Compatibility
The new AuthPolicy schema format is backward compatible with Kuadrant
1.3.1. This was verified by:
1. Deploying main branch code (predicate format) with Kuadrant 1.4.2 ✅
2. Deploying new schema format with Kuadrant 1.3.1 ✅
This allows safe deployment of auth-policy changes before operator
upgrade.
Migration Notes
For clusters upgrading from Kuadrant 1.3.x to 1.4.x:
1. Apply updated AuthPolicy first (backward compatible)
2. Upgrade Kuadrant operator to 1.4.2
3. Monitor Authorino reconciliation - should be seamless
4. Validate auth flows - API key and OpenShift token authentication
5. Verify header stripping - User tokens should not reach model backends
No service disruption expected during upgrade.
Related Issues
- [RHOAIENG-55749](https://redhat.atlassian.net/browse/RHOAIENG-55749):
Validate Kuadrant/RHCL Compatibility and Upgrade
- [RHOAIENG-54157](https://redhat.atlassian.net/browse/RHOAIENG-54157):
Strip Authorization Header to Prevent Credential Exfiltration
Merge criteria:
- The commits are squashed in a cohesive manner and have meaningful
messages.
- Testing instructions have been added in the PR body (for PRs involving
changes that are not immediately obvious).
- The developer has manually tested the changes and verified that the
changes work
Summary by CodeRabbit
- Security
- Added authorization header stripping for internal models to prevent
credential exfiltration to model backends
- Bug Fixes
- Improved API key validation logic for more robust authentication
handling
- Enhanced subscription header processing to correctly handle multiple
header instances
- Chores
- Upgraded Kuadrant policy-engine dependency from v1.3.1 to v1.4.2
- Documentation
- Updated version requirements to specify Kuadrant 1.4.2+ / RHCL 1.3+
for MaaS v0.2.0+
- Added security context explanation for authorization header stripping
requirement
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Strengthened API-key checks using regex-based matching and adjusted
header precedence so API-key-derived values override fallback headers.
* Fixed subscription header handling to pick the last non-empty value
when multiple headers are present and tightened non-empty checks.
* Ensure upstream Authorization is stripped from responses to prevent
credential forwarding.
* **Documentation**
* Updated prerequisites and migration notes; clarified minimum versions.
* **Chores**
* Bumped Kuadrant policy-engine reference to v1.4.2.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>1 parent d4a15d8 commit 152e531
File tree
6 files changed
+93
-32
lines changed- deployment/base/maas-api/policies
- docs/content/install
- maas-api/internal/handlers
- maas-controller/pkg/controller/maas
- scripts
6 files changed
+93
-32
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | | - | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
28 | 57 | | |
29 | 58 | | |
30 | 59 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
| |||
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
30 | | - | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
| |||
42 | 46 | | |
43 | 47 | | |
44 | 48 | | |
45 | | - | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
46 | 52 | | |
47 | 53 | | |
48 | 54 | | |
| |||
55 | 61 | | |
56 | 62 | | |
57 | 63 | | |
58 | | - | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
59 | 67 | | |
60 | 68 | | |
61 | 69 | | |
62 | | - | |
| 70 | + | |
| 71 | + | |
63 | 72 | | |
64 | | - | |
65 | | - | |
66 | 73 | | |
67 | 74 | | |
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
71 | 78 | | |
72 | 79 | | |
73 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
74 | 83 | | |
75 | 84 | | |
76 | 85 | | |
77 | | - | |
| 86 | + | |
| 87 | + | |
78 | 88 | | |
79 | | - | |
80 | | - | |
81 | 89 | | |
82 | 90 | | |
83 | 91 | | |
| |||
86 | 94 | | |
87 | 95 | | |
88 | 96 | | |
89 | | - | |
90 | | - | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
91 | 103 | | |
92 | 104 | | |
93 | 105 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
37 | | - | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | | - | |
| 46 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
191 | 201 | | |
192 | 202 | | |
193 | 203 | | |
| |||
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
452 | 452 | | |
453 | 453 | | |
454 | 454 | | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
455 | 466 | | |
456 | 467 | | |
457 | 468 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
| 14 | + | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
117 | | - | |
| 117 | + | |
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
| |||
372 | 372 | | |
373 | 373 | | |
374 | 374 | | |
375 | | - | |
| 375 | + | |
376 | 376 | | |
377 | 377 | | |
378 | 378 | | |
379 | 379 | | |
380 | 380 | | |
381 | | - | |
| 381 | + | |
382 | 382 | | |
383 | 383 | | |
384 | 384 | | |
| |||
866 | 866 | | |
867 | 867 | | |
868 | 868 | | |
869 | | - | |
| 869 | + | |
870 | 870 | | |
871 | | - | |
872 | | - | |
| 871 | + | |
| 872 | + | |
873 | 873 | | |
874 | 874 | | |
875 | 875 | | |
876 | | - | |
| 876 | + | |
877 | 877 | | |
878 | 878 | | |
879 | 879 | | |
| |||
884 | 884 | | |
885 | 885 | | |
886 | 886 | | |
887 | | - | |
| 887 | + | |
888 | 888 | | |
889 | 889 | | |
890 | 890 | | |
| |||
0 commit comments