Two independent bugs, both silent, both found while pointing an agent harness
at api.riotpiao.com.
1. Requests over ~10.6KB failed with HTTP 400
{"error":{"message":"[] is too short - 'messages'"}}.
The request-transformer plugin on the llm-chat-* routes rewrites the JSON
body, which means it reads it via kong.request.get_body(). That returns
nothing once nginx spills the body past client_body_buffer_size into a temp
file, so the plugin re-serialized a body with no `messages` and the upstream
rejected it. Measured on /v1/ornith/chat/completions: 10588 B -> 200,
11088 B -> 400. Isolated by size-sweeping /v1/embeddings, the one route with
no request-transformer, which passed an 18057 B body straight through to a
semantic 413 from TEI.
Raises the Kong http-block buffer to 16m. Any agent request carrying tool
schemas clears the old ceiling in a single turn.
2. key-auth was never applied to any model route.
The model-key-auth KongPlugin sat in namespace `api` while all five routes
that annotate it live in `llm-serving`. The ingress controller resolves
konghq.com/plugins against the annotated object's own namespace, so the
reference dangled and the plugin never bound. Verified before the fix:
unauthenticated GET /v1/models and POST /v1/ornith/chat/completions both
returned 200. A dangling plugin reference fails open and logs nothing.
Re-test both without a key after this syncs; expect 401.
Note for follow-up: llm-embeddings and llm-score carry no plugins annotation at
all, so they stay unauthenticated even after this change.
Co-Authored-By: Claude Opus 5 <[email protected]>
50 lines
1.9 KiB
YAML
50 lines
1.9 KiB
YAML
# API auth layer — Kong key-auth on the model routes.
|
|
#
|
|
# The model API (api.riotpiao.com/v1/...) requires a static API key, presented
|
|
# OpenAI-style as `Authorization: Bearer <key>` (or `apikey: <key>`). The key
|
|
# lives in the ksops-managed Secret model-invoke-apikey (labelled
|
|
# konghq.com/credential: key-auth) and is bound to the KongConsumer below.
|
|
#
|
|
# Issue the key to rock; use it as the OpenAI SDK api_key. Rotate by updating the
|
|
# ksops secret. This is self-contained in Kong — the invoke path does not depend
|
|
# on an Authentik token (Authentik still fronts every *human* dashboard SSO).
|
|
---
|
|
apiVersion: configuration.konghq.com/v1
|
|
kind: KongConsumer
|
|
metadata:
|
|
name: model-invoker
|
|
namespace: api
|
|
annotations:
|
|
kubernetes.io/ingress.class: kong
|
|
username: model-invoker
|
|
credentials:
|
|
- model-invoke-apikey
|
|
---
|
|
# key-auth: require the API key on the model routes. key_in_header accepts the
|
|
# `apikey` header; key_in_bearer accepts `Authorization: Bearer <key>` so any
|
|
# OpenAI-compatible SDK (api_key=..., base_url=https://api.riotpiao.com/v1) works
|
|
# unchanged.
|
|
#
|
|
# Namespace `llm-serving`, not `api`: the ingress controller resolves a
|
|
# `konghq.com/plugins` annotation against the annotated object's OWN namespace,
|
|
# and all five model routes in llm-routes.yaml live in llm-serving. While this
|
|
# sat in `api` the reference dangled, the plugin never bound, and every model
|
|
# route served traffic with no key at all — verified: an unauthenticated
|
|
# /v1/models and /v1/ornith/chat/completions both returned 200. A dangling
|
|
# plugin reference is silent; it fails open, so re-test without a key after any
|
|
# move rather than trusting that the object exists.
|
|
apiVersion: configuration.konghq.com/v1
|
|
kind: KongPlugin
|
|
metadata:
|
|
name: model-key-auth
|
|
namespace: llm-serving
|
|
plugin: key-auth
|
|
config:
|
|
key_names:
|
|
- apikey
|
|
- authorization
|
|
key_in_header: true
|
|
key_in_query: false
|
|
key_in_body: false
|
|
hide_credentials: true
|