@@ -72,32 +72,45 @@ spec:
7272 response :
7373 success :
7474 headers :
75- # Merge patch replaces the entire response block, so all headers must
76- # be re-declared. Use three-way CEL expressions (no "when" clause) so
77- # headers resolve for all token types: API keys, OIDC JWT, OpenShift
78- # TokenReview. The base policy's split X-MaaS-Username/OC approach
79- # with "when" clauses cannot survive a merge patch (when:null does not
80- # reliably clear fields), causing 500 AUTH_FAILURE refId 003.
75+ # Override the base X-MaaS-Username / X-MaaS-Group headers so they
76+ # handle API keys, OIDC JWT, and OpenShift TokenReview.
77+ #
78+ # API keys (Bearer sk-oai-*): identity comes from apiKeyValidation metadata — the
79+ # base policy used plain selectors here. OIDC-only expressions omit that path and
80+ # yield empty username → maas-api HTTP 500 AUTH_FAILURE refId 001 on /v1/models.
81+ # Order: apiKeyValidation → OIDC claims → OpenShift TokenReview.
82+ # No "when" clause — these headers must apply to ALL token types (API keys,
83+ # OIDC JWT, OpenShift TokenReview). The three-way expression handles each case.
84+ # The base policy restricts these to sk-oai-* only; merge patch must explicitly
85+ # null the "when" to clear the base's restriction.
8186 X-MaaS-Username :
87+ when : null
8288 plain :
89+ selector : null
8390 expression : >-
8491 (has(auth.metadata) && has(auth.metadata.apiKeyValidation)) ?
8592 auth.metadata.apiKeyValidation.username :
8693 (has(auth.identity.preferred_username) ?
8794 auth.identity.preferred_username :
8895 (has(auth.identity.sub) ? auth.identity.sub : auth.identity.user.username))
96+ # Never call .join on a missing path — that stringifies nil as "<nil>"
97+ # and breaks maas-api JSON parsing.
8998 X-MaaS-Group :
99+ when : null
90100 plain :
101+ selector : null
91102 expression : >-
92103 (has(auth.metadata) && has(auth.metadata.apiKeyValidation)) ?
93104 (size(auth.metadata.apiKeyValidation.groups) > 0 ?
94105 '["' + auth.metadata.apiKeyValidation.groups.join('","') + '"]' :
95106 '["system:authenticated"]') :
96107 (has(auth.identity.groups) && size(auth.identity.groups) > 0 ?
97108 '["system:authenticated","' + auth.identity.groups.join('","') + '"]' :
98- (has(auth.identity.user) && has(auth.identity.user .groups) && size(auth.identity.user.groups) > 0 ?
109+ (has(auth.identity.user.groups) && size(auth.identity.user.groups) > 0 ?
99110 '["system:authenticated","' + auth.identity.user.groups.join('","') + '"]' :
100111 '["system:authenticated"]'))
112+ # Subscription: from API key validation (must be preserved from base policy).
113+ # /v1/models reads this header to filter by subscription.
101114 X-MaaS-Subscription :
102115 when :
103116 - selector : request.headers.authorization
0 commit comments