diff --git a/docs/proposals/013-aigatewayroute-securitypolicy/proposal.md b/docs/proposals/013-aigatewayroute-securitypolicy/proposal.md new file mode 100644 index 0000000000..fd95eeaa96 --- /dev/null +++ b/docs/proposals/013-aigatewayroute-securitypolicy/proposal.md @@ -0,0 +1,505 @@ +# Client-Facing Security Policy for AIGatewayRoute + +## Table of Contents + +1. [Background and Motivation](#background-and-motivation) +2. [Current State](#current-state) +3. [Goals and Non-Goals](#goals-and-non-goals) +4. [Design Constraints](#design-constraints) +5. [Proposed Design](#proposed-design) + - 5.1 [API](#api) + - 5.2 [Generated Resources](#generated-resources) + - 5.3 [Reconciliation](#reconciliation) + - 5.4 [Policy Scope and Merging](#policy-scope-and-merging) +6. [Model-Aware Authorization: Out of Scope](#model-aware-authorization-out-of-scope) +7. [Security Considerations](#security-considerations) +8. [Status and Error Handling](#status-and-error-handling) +9. [Implementation Plan](#implementation-plan) +10. [Testing](#testing) +11. [Alternatives Considered](#alternatives-considered) +12. [Design Decisions](#design-decisions) +13. [Open Questions](#open-questions) + +## Background and Motivation + +`AIGatewayRoute` configures routing for inference requests, but it does not currently provide a first-class way to authenticate or authorize clients. Operators can create an Envoy Gateway `SecurityPolicy` and attach it to the `HTTPRoute` generated by the Agent Router controller, but doing so requires knowledge of that implementation detail and creates two resources whose lifecycles must be managed separately. + +This differs from `MCPRoute`, which exposes client-facing authentication under `spec.securityPolicy` and generates the corresponding Envoy Gateway `SecurityPolicy`. As a result, the two primary route APIs offer inconsistent security experiences even though both ultimately use Envoy Gateway. + +Common inference access-control requirements include: + +- Require a valid JWT, API key, or external authorization decision before accepting an inference request. +- Associate an API key with a client, user, service account, or tenant. +- Authorize users or groups to access an inference endpoint. +- Apply organization-wide security at the `Gateway` while adding route-specific policy. +- Restrict particular identities to selected models. + +This proposal adds a client-facing `securityPolicy` field to `AIGatewayRoute`. The controller uses it to create and manage an Envoy Gateway `SecurityPolicy` targeting the generated `HTTPRoute`. + +The proposal is intentionally limited to centralizing route-level security configuration. Model-aware authorization, where permissions are evaluated using the authenticated principal and the model extracted from the request body, is outside its scope. That capability would require a substantially broader data-plane design because Envoy Gateway evaluates its authentication and external authorization filters while processing request headers, whereas Agent Router derives the trusted `x-ai-eg-model` value later while processing the request body. It should be evaluated separately in the future rather than coupled to this configuration-centralization effort. + +## Current State + +An `AIGatewayRoute` and its generated resources currently have the following relationship: + +```text +AIGatewayRoute +├── owns HTTPRoute with the same namespace/name +├── owns host-rewrite HTTPRouteFilter +└── owns route-not-found HTTPRouteFilter +``` + +The generated `HTTPRoute` copies the route's labels, annotations, parent references, hostnames, rule names, matches, and backend references. Operators may manually attach an Envoy Gateway `SecurityPolicy` to either: + +- A parent `Gateway` or listener, to protect multiple routes. +- The generated `HTTPRoute`, to protect one `AIGatewayRoute`. + +Manual attachment works, but has several usability limitations: + +1. Users must know that `AIGatewayRoute` creates an `HTTPRoute` with the same name. +2. The security resource is not owned by the `AIGatewayRoute` and does not share its lifecycle. +3. Configuration differs from `MCPRoute` for equivalent JWT, API key, and external authorization behavior. +4. There is no Agent Router status reporting for invalid or conflicting security configuration. + +`BackendSecurityPolicy` does not solve this problem. It configures credentials on traffic leaving the gateway for an `AIServiceBackend` or `InferencePool`; it does not authenticate clients entering the gateway. + +## Goals and Non-Goals + +### Goals + +- Add optional client-facing security configuration to `AIGatewayRoute`. +- Generate an Envoy Gateway `SecurityPolicy` attached to the controller-generated `HTTPRoute`. +- Support JWT authentication, API key authentication, external authorization, and policy merging using Envoy Gateway primitives. +- Match the established `MCPRoute` ownership, naming, reconciliation, and cleanup behavior where practical. +- Preserve compatibility with manually managed `SecurityPolicy` resources on a parent `Gateway` or listener. +- Document why model-aware authorization is outside the scope of this proposal. +- Default to no behavior change when `spec.securityPolicy` is absent. + +### Non-Goals + +- Define a new identity store for users, groups, or API keys. +- Store plaintext credentials in `AIGatewayRoute`. +- Replace Envoy Gateway's `SecurityPolicy` API or external authorization protocol. +- Change `BackendSecurityPolicy` or upstream provider authentication. +- Add per-rule generated `SecurityPolicy` resources in the first version. +- Implement model-aware authorization based on the model extracted from the request body. +- Define a new identity store, policy language, or data-plane authorization protocol. + +## Design Constraints + +### SecurityPolicy Is a Separate Resource + +Gateway API policy attachment uses a separate policy resource with `targetRefs`; security configuration is not embedded in an `HTTPRoute`. The new field is therefore an Agent Router convenience API. The controller translates it into an owned Envoy Gateway `SecurityPolicy` rather than embedding policy fields in the generated `HTTPRoute`. + +### Filter Ordering + +Agent Router reads and parses the inference request body in the external processor. Once the model has been parsed, it overwrites or adds the trusted `x-ai-eg-model` header. Envoy Gateway client-authentication and external-authorization filters are evaluated before this request-body processing point. + +This ordering is relevant to a future model-aware authorization design, but does not block the route-level security configuration proposed here. + +Consequences for this proposal: + +- A client-provided `x-ai-eg-model` value must not be trusted for authorization. +- A generated Envoy Gateway `SecurityPolicy` cannot use Agent Router's derived `x-ai-eg-model` value. +- `extAuth.bodyToExtAuth` can send the original request body to an authorization service, but that service must parse every supported downstream API schema itself and enforce a bounded body size. +- The generated policy protects the route as a whole and does not make decisions based on the model extracted from the body. + +### Route Rule Targeting + +Envoy Gateway policy attachment can conceptually target an `HTTPRoute` rule through `sectionName`. However, support for `HTTPRouteRule.name` has historically varied across Gateway API implementations. `MCPRoute` currently avoids setting `sectionName` for this reason. + +The initial implementation targets the entire generated `HTTPRoute`. Per-rule policy attachment can be added when the required Gateway API feature is stable and supported by the project's compatibility matrix. + +### API Versioning + +`v1beta1` is the storage version and defines the canonical API. The project also serves the deprecated `v1alpha1` API, so this field is added to both versions for compatibility. Equivalent types must be added to both packages and all generated artifacts must be refreshed. + +## Proposed Design + +### API + +Add an optional field to `AIGatewayRouteSpec`: + +```go +type AIGatewayRouteSpec struct { + // Existing fields omitted. + + // SecurityPolicy configures client-facing authentication and authorization + // for this route. The controller materializes this configuration as an Envoy + // Gateway SecurityPolicy targeting the generated HTTPRoute. + // + // +optional + SecurityPolicy *AIGatewayRouteSecurityPolicy `json:"securityPolicy,omitempty"` +} +``` + +The first version reuses Envoy Gateway types and intentionally exposes only the primitives that map directly to a generated `SecurityPolicy`: + +```go +// AIGatewayRouteSecurityPolicy defines client-facing security for an +// AIGatewayRoute. +type AIGatewayRouteSecurityPolicy struct { + // JWT configures validation of JSON Web Tokens presented by clients. + // + // +optional + JWT *egv1a1.JWT `json:"jwt,omitempty"` + + // APIKeyAuth configures client API key authentication. + // + // +optional + APIKeyAuth *egv1a1.APIKeyAuth `json:"apiKeyAuth,omitempty"` + + // ExtAuth delegates authorization decisions to an external service. + // + // +optional + ExtAuth *egv1a1.ExtAuth `json:"extAuth,omitempty"` + + // MergeType controls how this generated policy combines with a policy + // attached to a parent Gateway or listener. Replace is not accepted. + // + // +kubebuilder:validation:XValidation:rule="self != 'Replace'",message="Replace is not a valid MergeType for SecurityPolicy" + // +optional + MergeType *egv1a1.MergeType `json:"mergeType,omitempty"` +} +``` + +This shape is deliberately close to `MCPRouteSecurityPolicy`, but it does not include MCP-specific OAuth protected-resource metadata or MCP tool authorization. JWT configuration is exposed directly because inference routes do not implement the MCP OAuth discovery contract. + +At least one of `jwt`, `apiKeyAuth`, or `extAuth` must be present when `securityPolicy` is configured. This is an invalid configuration, not an alternative way to disable the policy. The CRD should reject an empty policy with CEL validation; the controller should retain the same validation as a defensive check and report `NotAccepted` if an invalid object reaches reconciliation. + +The first version intentionally exposes Envoy Gateway's `JWT`, `APIKeyAuth`, and `ExtAuth` types directly. This keeps the API small and consistent with `MCPRoute`, avoids duplicating Envoy Gateway's schema, and makes the controller a thin projection rather than a second security API. A wrapper can be introduced later if decoupling from Envoy Gateway becomes a demonstrated compatibility requirement. + +Example using JWT validation and external authorization: + +```yaml +apiVersion: aigateway.envoyproxy.io/v1beta1 +kind: AIGatewayRoute +metadata: + name: inference + namespace: default +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: inference-gateway + securityPolicy: + jwt: + providers: + - name: corporate-idp + issuer: https://id.example.com + audiences: + - agent-router + remoteJWKS: + uri: https://id.example.com/.well-known/jwks.json + extAuth: + grpc: + backendRefs: + - name: authorization-service + port: 9000 + mergeType: StrategicMerge + rules: + - name: openai-models + matches: + - headers: + - type: Exact + name: x-ai-eg-model + value: gpt-4o-mini + backendRefs: + - name: openai +``` + +In this example, JWT and external authorization protect the whole route. The `x-ai-eg-model` match controls routing after Agent Router derives the model; it is not an input to the generated `SecurityPolicy` decision. + +### Generated Resources + +For the example above, the controller creates a resource equivalent to: + +```yaml +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: ai-eg-aigw-inference + namespace: default + ownerReferences: + - apiVersion: aigateway.envoyproxy.io/v1beta1 + kind: AIGatewayRoute + name: inference +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: inference + jwt: {} # copied from spec.securityPolicy.jwt + extAuth: {} # copied from spec.securityPolicy.extAuth + mergeType: StrategicMerge +``` + +The generated name uses a reserved, deterministic prefix to avoid colliding with the `HTTPRoute` or a user-created policy. The prefix should be defined in `internal/internalapi` and be distinct from the existing MCP prefix: + +```go +const AIGatewayRouteGeneratedResourcePrefix = "ai-eg-aigw-" +``` + +The generated resource must have: + +- A controller owner reference to the `AIGatewayRoute`. +- The same namespace as the `AIGatewayRoute` and generated `HTTPRoute`. +- A label identifying it as managed by Agent Router. +- A single `targetRef` to the generated `HTTPRoute`. +- No `sectionName` in the first version. + +The controller owns the entire generated `SecurityPolicy` spec. Users must configure it through `AIGatewayRoute.spec.securityPolicy`, not edit the generated object directly. + +### Reconciliation + +Extend `syncAIGatewayRoute` with security-policy reconciliation after the desired `HTTPRoute` has been constructed: + +```text +Reconcile AIGatewayRoute +├── reconcile HTTPRouteFilters +├── create or update HTTPRoute +├── if spec.securityPolicy is configured +│ └── create or update generated SecurityPolicy +├── otherwise +│ └── delete generated SecurityPolicy if present +└── notify referenced Gateways +``` + +The implementation should follow the existing `MCPRoute` pattern: + +1. Compute the deterministic generated-policy name. +2. Read the existing `SecurityPolicy`. +3. On creation, set the controller reference. +4. Build a fresh desired `SecurityPolicySpec` instead of mutating selected old fields. +5. Copy JWT, API key, external authorization, and merge configuration. +6. Set a target reference to the generated `HTTPRoute`. +7. Create or update the resource. +8. Delete it when `spec.securityPolicy` is removed. + +Add `.Owns(&egv1a1.SecurityPolicy{})` to the controller builder. It causes direct changes or deletion of the generated policy to enqueue its owning `AIGatewayRoute`, allowing the controller to restore desired state. The owner reference also provides garbage collection if the route is deleted. This is preferable to relying only on manual cleanup, even though the current MCP controller uses the latter pattern. + +Reconciliation must not adopt or overwrite an existing resource with the deterministic name unless it is controlled by the current `AIGatewayRoute`. A name collision should set the route to `NotAccepted` with a clear message. No adoption annotation is needed for the first version. + +### Policy Scope and Merging + +The generated policy applies to every rule in the generated `HTTPRoute`, including the controller-injected `route-not-found` rule. This is desirable by default because unauthenticated requests should not gain information about configured models through different error behavior. + +An operator may also attach a `SecurityPolicy` to the parent `Gateway` or listener. `mergeType` controls whether the generated route policy combines with the closest parent policy according to Envoy Gateway semantics. The API rejects `Replace` because replacement is represented by omitting a merge type and because exposing both forms would make policy inheritance difficult to reason about. + +Two independently managed `SecurityPolicy` resources must not target the same generated `HTTPRoute` at the same attachment point. Envoy Gateway's conflict rules would select a policy, but relying on that selection makes the effective security configuration surprising. Documentation should state that enabling `AIGatewayRoute.spec.securityPolicy` makes the generated route-level policy authoritative; additional policy should be attached to a parent and merged. + +## Model-Aware Authorization: Out of Scope + +The broader permission matrix is a valid future requirement, but it is intentionally not implemented by this proposal: + +```text +principal (user, group, or API key) x artifact (model or MCP tool) -> allow/deny +``` + +Implementing this for inference requests would require a decision point after Agent Router parses the model from the body. It would also require a defined identity-propagation mechanism, a policy evaluation contract, failure semantics, observability, and potentially a new external authorization protocol or local policy engine. + +Those concerns are materially broader than the objective of this proposal: centralizing the configuration of security for routes that expose LLM models. + +### Why It Is Deferred + +The trusted model header is produced by the external processor during request-body handling. Envoy's JWT, API key, and external authorization filters make their normal decisions earlier. Authorizing an inbound `x-ai-eg-model` header would introduce a confused-deputy vulnerability because the client controls that value until Agent Router overwrites it. + +`ExtAuth.bodyToExtAuth` is a possible deployment-specific workaround. It allows the authorization service to inspect the original body and derive the model independently. It has important tradeoffs: + +- The service must understand every accepted downstream request schema. +- Requests must be buffered up to `maxRequestBytes`. +- Oversized requests fail before authorization, commonly with HTTP 413. +- Model extraction behavior can drift between Agent Router and the authorization service. +- Body contents may contain sensitive prompts and should not be disclosed unnecessarily. + +For these reasons, body forwarding is supported by the underlying `ExtAuth` type but is not presented as native model-aware authorization. It is also not part of the implementation proposed here. + +### Possible Future Proposal: Post-Parse Authorization + +A later phase should add an Agent Router authorization contract evaluated immediately after the model is parsed and before backend selection or upstream credential injection. Two implementation strategies are viable: + +#### Option A: External Authorization From ExtProc + +The external processor calls a configured authorization service with a normalized request: + +```json +{ + "principal": { + "subject": "user-123", + "groups": ["developers"], + "apiKeyClientId": "client-456" + }, + "artifact": { + "type": "LLMModel", + "name": "gpt-4o-mini" + }, + "route": { + "namespace": "default", + "name": "inference", + "rule": "openai-models" + } +} +``` + +This keeps policy data outside Agent Router and supports dynamic systems such as Open Policy Agent, Cedar, OpenFGA, or a bespoke permissions service. It requires a new runtime client, timeout/failure semantics, observability, and careful propagation of authenticated identity from Envoy dynamic metadata to extproc. + +#### Option B: Native Declarative Authorization + +Add a separate policy API, tentatively `AIGatewayRouteAuthorizationPolicy`, with target references and rules over authenticated claims, client identity, route, model, and backend. The external processor compiles and evaluates those rules locally after parsing the request. + +This avoids a network call and provides a Kubernetes-native experience, but it introduces a new policy language and distribution lifecycle. It should reuse CEL rather than inventing custom user/group matching semantics. + +Both options require a separate proposal. This document does not select an implementation for model-aware authorization or commit Agent Router to either approach. + +### Identity Propagation + +Any future post-parse authorization design would require trusted identity, not arbitrary client headers. It would need to consume one or more of: + +- Verified JWT claims emitted by Envoy's JWT filter into dynamic metadata. +- A stable client identifier produced by API key authentication. +- Trusted headers emitted by external authorization after stripping client-provided values. + +The set of dynamic metadata namespaces needed by extproc would need to be explicitly forwarded through `GatewayConfig`. These details are deferred to that future proposal. + +## Security Considerations + +### Fail Closed + +Authentication and authorization errors should deny the request. `ExtAuth` fail-open behavior remains available through Envoy Gateway configuration, but examples and documentation should default to fail closed. + +### Trusted Identity + +Headers such as `x-user`, `x-groups`, `x-tenant-id`, and `x-ai-eg-model` are untrusted when supplied by a client. A policy may use them only if a trusted gateway filter first removes and reconstructs them from verified identity or request data. + +JWT configuration should specify an audience whenever the identity provider supports it. Issuer and JWKS configuration define trust anchors and must not be inferred from untrusted token claims. + +### API Key Storage + +Client API keys must be referenced through Kubernetes Secrets using Envoy Gateway's `APIKeyAuth` model. Keys must not be accepted inline in `AIGatewayRoute`. + +API key authentication establishes a client identity only if the selected Envoy Gateway configuration makes a stable client identifier available to external authorization. Possession of a valid key and authorization for a model are separate decisions. + +### Request Body Disclosure + +Enabling `bodyToExtAuth` sends prompt contents and potentially sensitive data to the authorization service. This proposal does not require or recommend enabling it for model authorization. Any future proposal using it must set the smallest practical `maxRequestBytes`, secure the connection, avoid body logging, and document retention behavior. + +### Generated Resource Tampering + +RBAC should restrict direct writes to generated resources. The controller should restore drift, reject ownership conflicts, and never adopt a policy controlled by another object. + +## Status and Error Handling + +The existing `AIGatewayRoute` condition remains the initial reporting surface: + +- `Accepted`: the `HTTPRoute` and optional generated `SecurityPolicy` were reconciled. +- `NotAccepted`: validation, ownership, reference, or API errors prevented reconciliation. + +Representative messages include: + +- `securityPolicy must configure at least one authentication or authorization mechanism` +- `generated SecurityPolicy default/ai-eg-aigw-inference is controlled by another resource` +- `failed to create generated SecurityPolicy: ...` + +The controller should not report `Accepted` until both the `HTTPRoute` and desired `SecurityPolicy` have been persisted. Envoy Gateway acceptance status is reported on its resources and is not duplicated into `AIGatewayRoute` in the first version. + +If security reconciliation fails after the `HTTPRoute` exists, the route may temporarily remain reachable under a parent policy or without the desired route-level policy. Deployments requiring atomic rollout should first protect the parent `Gateway` with a default-deny or authentication policy. Kubernetes reconciliation cannot atomically update these separate resources. + +## Implementation Plan + +### Phase 1: Route-Level SecurityPolicy Generation + +1. Add `AIGatewayRouteSecurityPolicy` and `AIGatewayRouteSpec.SecurityPolicy` to the served API versions required by the compatibility policy. +2. Add kubebuilder validation and regenerate DeepCopy implementations, CRDs, clients, and API documentation. +3. Add a deterministic generated-resource prefix to `internal/internalapi`. +4. Add `syncAIGatewayRouteSecurityPolicy`, `ensureAIGatewayRouteSecurityPolicy`, and cleanup helpers to the route controller. +5. Set a controller owner reference and managed-by label. +6. Add `Owns(&egv1a1.SecurityPolicy{})` to the `AIGatewayRoute` controller builder. +7. Reconcile the policy after the `HTTPRoute` and before notifying Gateways. +8. Add user documentation and examples for JWT, API keys, external authorization, merging, and body-forwarding caveats. + +The MCP and inference implementations should share small pure helpers for constructing target references or checking ownership where this removes duplication. The route-specific reconciliation should remain separate because MCP additionally manages OAuth discovery resources and protected-resource metadata. + +### Future Work Outside This Proposal + +Model-aware authorization should be evaluated in a separate proposal. Its scope would include identity propagation to extproc, a normalized authorization contract, policy evaluation, timeout and failure semantics, caching, observability, and the distinction between route access and model access. + +## Testing + +### API and CRD Tests + +- Accept JWT-only, API-key-only, ext-auth-only, and supported combinations. +- Reject an empty `securityPolicy`. +- Reject invalid merge types. +- Verify schema parity for served API versions. + +### Controller Unit Tests + +- Create a generated `SecurityPolicy` with the expected name, owner reference, target reference, and copied fields. +- Update the generated policy when the route configuration changes. +- Restore the generated policy after external deletion or mutation. +- Delete the generated policy when `securityPolicy` is removed. +- Garbage-collect it when the `AIGatewayRoute` is deleted. +- Reject a deterministic-name collision with an uncontrolled object. +- Preserve and merge parent-policy behavior through `mergeType`. +- Leave existing route behavior unchanged when the field is absent. + +### End-to-End Tests + +- JWT: valid token succeeds; missing, invalid, wrong-issuer, and wrong-audience tokens fail. +- API key: configured key succeeds; missing and unknown keys fail. +- External authorization: allow succeeds and deny returns HTTP 403. +- Parent and route policy merging applies both intended controls. +- A client-forged `x-ai-eg-model` does not bypass route matching or authorization. +- `bodyToExtAuth` behavior is documented and tested separately if included in examples. + +Model-aware authorization tests are outside the scope of this proposal and should be defined by the future design that implements that capability. + +## Alternatives Considered + +### Require Users to Create Envoy Gateway SecurityPolicy Directly + +This already works and remains appropriate for advanced deployments. It is not preferred as the only interface because users must target an implementation-generated resource, lifecycle management is split, status is disconnected, and MCP and inference routes remain inconsistent. + +### Embed Security Configuration in Each Rule + +Per-rule configuration appears attractive for model groups, but it depends on portable `sectionName` support and duplicates authentication configuration across rules. It also still cannot use the model parsed from the request body during Envoy's earlier authorization phase. Rejected for the first version. + +### Create a New AIGatewayRoutePolicy CRD Immediately + +A dedicated policy CRD would align with Gateway API policy attachment and support one policy targeting multiple routes. However, the first phase is a thin wrapper over an existing one-to-one Envoy Gateway resource, and an inline route field matches the established `MCPRoute` user experience. A separate CRD becomes more compelling for native model-aware authorization, where it represents genuinely new behavior rather than a projection of `SecurityPolicy`. + +### Extend BackendSecurityPolicy + +Rejected because `BackendSecurityPolicy` protects gateway-to-provider traffic and manages upstream credentials. Client authentication and authorization occur on the downstream side and have different targets, trust boundaries, and failure semantics. + +### Trust x-ai-eg-model From the Client + +Rejected. Although clients may send this header and some deployments route on it, the canonical model can come from the request body. Authorization must use the value parsed and overwritten by Agent Router, not an untrusted pre-processing value. + +### Always Send Request Bodies to Envoy ExtAuth + +Rejected as the default because it duplicates protocol parsing, buffers requests, can expose prompts, and couples the authorization service to every supported request schema. It remains an opt-in capability of Envoy Gateway's `ExtAuth` API. + +## Design Decisions + +The following decisions are considered fixed for this proposal: + +1. **API shape:** use Envoy Gateway's `JWT`, `APIKeyAuth`, and `ExtAuth` types directly. Do not add wrappers until a real compatibility need appears. +2. **API versions:** add the field to both served API versions for compatibility. `v1beta1` is canonical and remains the storage version; `v1alpha1` is deprecated but receives the equivalent field and generated artifacts. +3. **Empty policy:** an explicitly configured but empty `securityPolicy` is invalid. An omitted field disables route-level security generation. +4. **Generated resource identity:** use `ai-eg-aigw-` as the generated-resource prefix and `app.kubernetes.io/managed-by=envoy-ai-gateway` as the managed-by label. +5. **Ownership and drift:** set an `AIGatewayRoute` controller reference and register `Owns(&egv1a1.SecurityPolicy{})`. Never adopt a same-name resource controlled by another object. +6. **Per-rule attachment:** do not set `sectionName` or promise per-rule security until the compatibility matrix supports stable `HTTPRouteRule.name` targeting. +7. **Model-aware authorization:** keep it outside this proposal and evaluate it separately as a broader data-plane design. + +## Open Questions + +1. When can the compatibility matrix safely support per-rule policy attachment through `sectionName`? +2. Which Envoy Gateway API version should be used for the generated `SecurityPolicy` when that dependency changes independently of Agent Router's API versions? +3. Should future model-aware authorization use an external service, local CEL evaluation, or another policy engine? This is intentionally not decided here. + +## Recommendation + +Implement Phase 1 as a small, backwards-compatible extension that gives `AIGatewayRoute` parity with `MCPRoute` for route-level client security. Generate and own a standard Envoy Gateway `SecurityPolicy`; do not create a second authentication engine. + +Do not include model-aware authorization in this work. It has a substantially larger impact on the data plane and identity propagation than the centralization goal addressed here. Revisit it in a separate proposal once the route-level security API is established and its requirements are better understood. \ No newline at end of file