From b535e85c90c684557e9a04478ebde7dbd4fe9b87 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 09:12:40 -0400 Subject: [PATCH 01/20] Expanded YAML examples and added doc tests Signed-off-by: Kristin Brown --- .../standalone/main/configuration/backends.md | 180 ++++++- .../main/configuration/listeners.md | 285 +++++++++-- .../configuration/resiliency/mirroring.md | 58 ++- .../configuration/resiliency/rate-limits.md | 207 ++++++-- .../main/configuration/resiliency/retries.md | 68 ++- .../main/configuration/resiliency/timeouts.md | 90 +++- .../configuration/security/apikey-authn.md | 122 ++++- .../configuration/security/backend-authn.md | 70 ++- .../configuration/security/backend-tls.md | 88 +++- .../configuration/security/basic-authn.md | 73 ++- .../main/configuration/security/csrf.md | 59 ++- .../configuration/security/external-authz.md | 93 +++- .../main/configuration/security/http-authz.md | 67 ++- .../main/configuration/security/jwt-authn.md | 128 ++++- .../main/configuration/security/mcp-authn.md | 128 ++--- .../main/configuration/security/mcp-authz.md | 106 ++++- .../main/configuration/security/oidc.md | 30 +- .../traffic-management/direct-response.md | 66 ++- .../traffic-management/manipulation.md | 56 ++- .../traffic-management/matching.md | 449 ++++++++++++------ .../traffic-management/redirects.md | 60 ++- .../traffic-management/rewrites.md | 58 ++- .../traffic-management/transformations.md | 134 +++++- 23 files changed, 2201 insertions(+), 474 deletions(-) diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 94519de4c..170341f85 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -3,11 +3,26 @@ title: Backends weight: 13 description: Configure backends to route traffic to hostnames, LLM providers, and MCP servers. prev: /configuration/listeners +test: + backends: + - file: content/docs/standalone/main/configuration/backends.md + path: backends --- Agentgateway {{< gloss "Backend" >}}backends{{< /gloss >}} control where traffic is routed to. Agentgateway supports a variety of backends, such as simple hostnames and IP addresses, {{< gloss "Provider" >}}LLM providers{{< /gloss >}}, and MCP servers. +{{< doc-test paths="backends" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +export OPENAI_API_KEY="${OPENAI_API_KEY:-dummy}" +{{< /doc-test >}} + ## Static Hosts The simplest form of backend is a static hostname or IP address. For example: @@ -26,6 +41,28 @@ binds: weight: 9 ``` +{{< doc-test paths="backends" >}} +# WHAT THIS TEST VALIDATES: +# * The static host backend example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That traffic is actually routed/weighted to the hosts at runtime — requires +# reachable backends the page omits. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - protocol: HTTP + routes: + - backends: + - host: example.com:8080 + weight: 1 + - host: 127.0.0.1:80 + weight: 9 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ## MCP Servers The MCP backend allows you to connect to an MCP server. @@ -33,33 +70,93 @@ Below shows a simple example, exposing a local and remote MCP server. See the [MCP connectivity guide]({{< link-hextra path="/mcp/" >}}) for more information. ```yaml -backends: -- mcp: - targets: - - name: stdio-server - stdio: - cmd: npx - args: ["@modelcontextprotocol/server-everything"] - - name: http-server - mcp: - host: https://example.com/mcp +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: stdio-server + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + - name: http-server + mcp: + host: https://example.com/mcp ``` +{{< doc-test paths="backends" >}} +# WHAT THIS TEST VALIDATES: +# * The MCP backend example config (stdio + remote MCP targets) is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the MCP targets actually start/connect at runtime — requires the npx +# command and remote server the page does not stand up. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: stdio-server + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + - name: http-server + mcp: + host: https://example.com/mcp +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} + ### Session routing By default, MCP backends use stateful session routing, where the gateway tracks session IDs and routes subsequent requests to the same upstream. For upstreams that do not maintain server-side session state, you can set `statefulMode: Stateless`. In stateless mode, the gateway automatically wraps each request with an initialization sequence, so the upstream server processes every request independently. ```yaml -backends: -- mcp: - statefulMode: Stateless - targets: - - name: openapi-server - openapi: - schema: - url: https://petstore3.swagger.io/api/v3/openapi.json +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + statefulMode: Stateless + targets: + - name: openapi-server + openapi: + schema: + url: https://petstore3.swagger.io/api/v3/openapi.json ``` +{{< doc-test paths="backends" >}} +# WHAT THIS TEST VALIDATES: +# * The stateless session-routing MCP backend example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That stateless wrapping actually occurs at runtime — requires the OpenAPI +# upstream and live MCP traffic the page omits. +cat <<'EOF' > config3.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + statefulMode: Stateless + targets: + - name: openapi-server + openapi: + schema: + url: https://petstore3.swagger.io/api/v3/openapi.json +EOF +agentgateway -f config3.yaml --validate-only +{{< /doc-test >}} + ## LLM Providers Agentgateway natively supports connecting to LLM providers, such as OpenAI and Anthropic. @@ -67,12 +164,43 @@ Below shows a simple example, connecting to OpenAI. See the [LLM consumption guide]({{< link-hextra path="/llm/" >}}) for more information. ```yaml -backends: -- ai: - provider: - openAI: - model: gpt-3.5-turbo -policies: - backendAuth: - key: "$OPENAI_API_KEY" +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - ai: + name: openai + provider: + openAI: + model: gpt-3.5-turbo + policies: + backendAuth: + key: "$OPENAI_API_KEY" ``` + +{{< doc-test paths="backends" >}} +# WHAT THIS TEST VALIDATES: +# * The OpenAI LLM provider (ai backend) example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That requests are actually proxied to OpenAI at runtime — requires a real +# OPENAI_API_KEY and live LLM traffic the page omits. +cat <<'EOF' > config4.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - ai: + name: openai + provider: + openAI: + model: gpt-3.5-turbo + policies: + backendAuth: + key: "$OPENAI_API_KEY" +EOF +agentgateway -f config4.yaml --validate-only +{{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/listeners.md b/content/docs/standalone/main/configuration/listeners.md index 15474cee0..757e83b6b 100644 --- a/content/docs/standalone/main/configuration/listeners.md +++ b/content/docs/standalone/main/configuration/listeners.md @@ -2,11 +2,35 @@ title: Listeners weight: 12 description: Configure listeners for agentgateway. ---- +test: + listeners: + - file: content/docs/standalone/main/configuration/listeners.md + path: listeners +--- Listeners are the entrypoints for traffic into agentgateway. Agentgateway supports both {{< gloss "HTTP (Hypertext Transfer Protocol)" >}}HTTP{{< /gloss >}} and {{< gloss "TCP (Transmission Control Protocol)" >}}TCP{{< /gloss >}} traffic, with and without {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}}. +{{< doc-test paths="listeners" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + +{{< doc-test paths="listeners" >}} +# Create self-signed certs referenced by the examples +mkdir -p examples/tls/certs certs +openssl req -x509 -newkey rsa:2048 -keyout examples/tls/certs/key.pem -out examples/tls/certs/cert.pem -days 365 -nodes -subj "/CN=localhost" 2>/dev/null +openssl req -x509 -newkey rsa:2048 -keyout examples/tls/certs/key-a.pem -out examples/tls/certs/cert-a.pem -days 365 -nodes -subj "/CN=a.example.com" 2>/dev/null +openssl req -x509 -newkey rsa:2048 -keyout examples/tls/certs/key-wildcard.pem -out examples/tls/certs/cert-wildcard.pem -days 365 -nodes -subj "/CN=wildcard.example.com" 2>/dev/null +cp examples/tls/certs/cert.pem certs/cert.pem +cp examples/tls/certs/key.pem certs/key.pem +{{< /doc-test >}} + ## HTTP Listeners An HTTP listener can be configured by setting `protocol: HTTP` in the listener configuration. @@ -14,23 +38,67 @@ This is also the default protocol if no protocol is specified. For example: ```yaml -listeners: -- protocol: HTTP - routes: [] +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - protocol: HTTP + routes: [] ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The HTTP listener example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the listener actually serves traffic at runtime — the config defines +# no routes or backends to exercise. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - protocol: HTTP + routes: [] +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ## HTTPS Listeners Serving {{< gloss "HTTPS (HTTP Secure)" >}}HTTPS{{< /gloss >}} traffic requires TLS certificates and setting `protocol: HTTPS` in the listener configuration: ```yaml -listeners: -- protocol: HTTPS - tls: - cert: examples/tls/certs/cert.pem - key: examples/tls/certs/key.pem +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - protocol: HTTPS + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem + routes: [] ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The HTTPS listener example config (cert + key) is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That TLS is actually negotiated at runtime — requires a client connection +# the page does not exercise. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - protocol: HTTPS + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem + routes: [] +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} + To generate a self-signed certificate for local testing, you can use `openssl`. Self-signed certificates trigger security warnings in browsers and clients, so use a certificate from a trusted certificate authority, such as Let's Encrypt, in production. ```sh @@ -42,21 +110,55 @@ Requests can be routed based on the [hostname](https://en.wikipedia.org/wiki/Ser The most exact match will be used, as well as the corresponding TLS certificates. ```yaml -listeners: -- name: discrete - protocol: HTTPS - hostname: a.example.com - tls: - cert: examples/tls/certs/cert-a.pem - key: examples/tls/certs/key-a.pem -- name: wildcard - protocol: HTTPS - hostname: "*.example.com" - tls: - cert: examples/tls/certs/cert-wildcard.pem - key: examples/tls/certs/key-wildcard.pem +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - name: discrete + protocol: HTTPS + hostname: a.example.com + tls: + cert: examples/tls/certs/cert-a.pem + key: examples/tls/certs/key-a.pem + routes: [] + - name: wildcard + protocol: HTTPS + hostname: "*.example.com" + tls: + cert: examples/tls/certs/cert-wildcard.pem + key: examples/tls/certs/key-wildcard.pem + routes: [] ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The hostname-based HTTPS example config (discrete + wildcard SNI) is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That SNI hostname matching selects the right cert at runtime — requires TLS +# client connections the page does not exercise. +cat <<'EOF' > config3.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - name: discrete + protocol: HTTPS + hostname: a.example.com + tls: + cert: examples/tls/certs/cert-a.pem + key: examples/tls/certs/key-a.pem + routes: [] + - name: wildcard + protocol: HTTPS + hostname: "*.example.com" + tls: + cert: examples/tls/certs/cert-wildcard.pem + key: examples/tls/certs/key-wildcard.pem + routes: [] +EOF +agentgateway -f config3.yaml --validate-only +{{< /doc-test >}} + ### Redirect HTTP to HTTPS To serve both HTTP and HTTPS, configure an HTTP listener that redirects all traffic to the HTTPS listener with a `requestRedirect` policy. The following example listens for plaintext HTTP on port 80 and redirects it to HTTPS, while serving encrypted traffic on port 443. @@ -81,6 +183,34 @@ binds: routes: [] ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The "Redirect HTTP to HTTPS" example config (HTTP requestRedirect + HTTPS listener) is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That an HTTP request is actually redirected to HTTPS at runtime — requires a +# client request the page does not exercise. +cat <<'EOF' > config4.yaml +binds: +- port: 80 + listeners: + - name: http + protocol: HTTP + routes: + - policies: + requestRedirect: + scheme: https +- port: 443 + listeners: + - name: https + protocol: HTTPS + tls: + cert: ./certs/cert.pem + key: ./certs/key.pem + routes: [] +EOF +agentgateway -f config4.yaml --validate-only +{{< /doc-test >}} + ## TCP Listeners TCP listeners can be configured by setting `protocol: TCP` in the listener configuration. @@ -90,12 +220,33 @@ TCP listeners are useful when serving traffic that is not HTTP based. > A large portion of agentgateway's functionality is specific to HTTP traffic, and not available for TCP traffic. ```yaml -listeners: -- name: default - protocol: TCP - tcpRoutes: [] +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 9000 + listeners: + - name: default + protocol: TCP + tcpRoutes: [] ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The TCP listener example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That TCP traffic is actually forwarded at runtime — the config defines no +# tcpRoutes or backends to exercise. +cat <<'EOF' > config5.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 9000 + listeners: + - name: default + protocol: TCP + tcpRoutes: [] +EOF +agentgateway -f config5.yaml --validate-only +{{< /doc-test >}} + Additionally, note the use of `tcpRoutes` instead of `routes` (which are HTTP routes) in the example. ## Auto-detect protocol @@ -103,14 +254,37 @@ Additionally, note the use of `tcpRoutes` instead of `routes` (which are HTTP ro Set `protocol: auto` to automatically detect the protocol for each incoming connection. The gateway peeks at the first byte of the connection. If the byte is `0x16` (a TLS ClientHello), the gateway dispatches the connection as TLS. Otherwise, the gateway dispatches it as HTTP. Use auto-detection in mixed-protocol environments where the same port accepts both TLS and plaintext traffic. ```yaml -listeners: -- protocol: auto - routes: [] - tls: - cert: examples/tls/certs/cert.pem - key: examples/tls/certs/key.pem +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - protocol: auto + routes: [] + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem ``` +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The auto-detect protocol listener example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the gateway actually dispatches TLS vs HTTP per connection at runtime — +# requires client connections the page does not exercise. +cat <<'EOF' > config6.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 443 + listeners: + - protocol: auto + routes: [] + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem +EOF +agentgateway -f config6.yaml --validate-only +{{< /doc-test >}} + ## TLS Listeners For serving TLS traffic, the `protocol: TLS` can be used. @@ -122,14 +296,41 @@ TLS listeners can either _terminate_ or _passthrough_ TLS traffic. While both a TCP and TLS passthrough listener do not terminate TLS, the latter enables the use of routing based on the hostname (utilizing [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication)). ```yaml -listeners: -- hostname: passthrough.example.com - protocol: TLS - tcpRoutes: [] -- hostname: termination.example.com - protocol: TLS - tcpRoutes: [] - tls: - cert: examples/tls/certs/cert.pem - key: examples/tls/certs/key.pem +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 8443 + listeners: + - hostname: passthrough.example.com + protocol: TLS + tcpRoutes: [] + - hostname: termination.example.com + protocol: TLS + tcpRoutes: [] + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem ``` + +{{< doc-test paths="listeners" >}} +# WHAT THIS TEST VALIDATES: +# * The TLS listeners example config (passthrough + termination via SNI) is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That passthrough/termination behavior occurs at runtime — requires TLS client +# connections and backends the page does not exercise. +cat <<'EOF' > config7.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 8443 + listeners: + - hostname: passthrough.example.com + protocol: TLS + tcpRoutes: [] + - hostname: termination.example.com + protocol: TLS + tcpRoutes: [] + tls: + cert: examples/tls/certs/cert.pem + key: examples/tls/certs/key.pem +EOF +agentgateway -f config7.yaml --validate-only +{{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index bcabbdf75..36448a3db 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -2,17 +2,63 @@ title: Mirroring weight: 10 description: Send copies of requests to alternative backends for shadow testing. +test: + mirroring: + - file: content/docs/standalone/main/configuration/resiliency/mirroring.md + path: mirroring --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="mirroring" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alterative backend. These request will not be retried if they fail. ```yaml -requestMirror: - backend: - host: localhost:8080 - # Mirror 50% of request - percentage: 0.5 -``` \ No newline at end of file +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestMirror: + backend: + host: localhost:8080 + # Mirror 50% of requests + percentage: 0.5 + backends: + - host: localhost:8000 +``` + +{{< doc-test paths="mirroring" >}} +# WHAT THIS TEST VALIDATES: +# * The requestMirror example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That requests are actually mirrored at runtime — requires live primary +# and mirror backends the page omits to send to and inspect. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestMirror: + backend: + host: localhost:8080 + # Mirror 50% of requests + percentage: 0.5 + backends: + - host: localhost:8000 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index 494f99a60..761f5217c 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -2,10 +2,24 @@ title: Rate limiting weight: 10 description: Enforce budget and spend limits per key by controlling request and token usage. +test: + rate-limits: + - file: content/docs/standalone/main/configuration/resiliency/rate-limits.md + path: rate-limits --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="rate-limits" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Use rate limiting to enforce budget and spend limits per key: control the rate of requests and token usage on a route. Token-based limits let you cap usage per user, per API key, or per time window. Combined with API key authentication and observability, this gives you virtual key management. ## Rate limit types @@ -29,15 +43,45 @@ By default, agentgateway applies rate limits to requests. Therefore, each reques To explicitly set request-based rate limits, set the rate limiting type to `requests` as shown in the following example. ```yaml - policies: +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: localRateLimit: - - maxTokens: 10 - tokensPerFill: 1 - fillInterval: 60s - type: requests - + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + backends: + - host: localhost:8080 ``` +{{< doc-test paths="rate-limits" >}} +# WHAT THIS TEST VALIDATES: +# * The request-based localRateLimit example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That requests are actually limited at runtime — requires driving traffic +# past the configured bucket, which the page does not exercise. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + localRateLimit: + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ### Token-based rate limits @@ -45,15 +89,14 @@ To explicitly set request-based rate limits, set the rate limiting type to `requ For tokens, each token (prompt or completion) consumes 1 unit of capacity. Because the number of tokens that are used for the completion is not known at the time the request is sent, calculating the number of tokens can become tricky. To work around this issue, agentgateway checks token-based rate limits in two phases, at request time and at response time. -To enable token-based rate limiting, set the rate limiting type to `token` as shown in the following example. +To enable token-based rate limiting, set the rate limiting type to `tokens`. This example shows only the route-level `localRateLimit` policy; attach it to a route as shown in the complete examples in the [Configuration](#configuration) section. ```yaml - policies: - localRateLimit: - - maxTokens: 10 - tokensPerFill: 1 - fillInterval: 60s - type: tokens +localRateLimit: +- maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: tokens ``` #### At request time @@ -80,19 +123,60 @@ Local rate limiting uses a [Token bucket](https://en.wikipedia.org/wiki/Token_bu Below shows an example rate limit configuration that allows 5,000 tokens per hour, and 60 requests per second. ```yaml -localRateLimit: -- maxTokens: 5000 - # Every hour, refill 5000 tokens - tokensPerFill: 5000 - fillInterval: 1h - type: tokens -- maxTokens: 60 - # Every second, refill 1 token - tokensPerFill: 1 - fillInterval: 1s - type: requests +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + backends: + - host: localhost:8080 ``` +{{< doc-test paths="rate-limits" >}} +# WHAT THIS TEST VALIDATES: +# * The Local example config (5000 tokens/hour and 60 requests/second) is +# accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the token-bucket limits actually refill and throttle at runtime — +# requires sustained traffic over the fill intervals, which the page omits. +# * The token-based and failOpen fragments on this page are focused field- +# reference snippets, not standalone configs, so they are not tested here. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + backends: + - host: localhost:8080 +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} + > [!NOTE] > The term "tokens" is used for two distinct meanings. In `maxTokens` and `tokensPerFill`, it indicates the "token" in the token bucket counter. Each token can allow either 1 LLM token, or 1 HTTP request, based on the `type`. @@ -103,23 +187,68 @@ Instead, agentgateway is configured to connect to an external rate limit server, The rate limit server is responsible for defining, and enforcing, the appropriate limits matching the descriptors. ```yaml -remoteRateLimit: - # The address to access the rate limit server - host: localhost:9090 - # Arbitrary 'domain' to match limits on the rate limit server - domain: example.com - descriptors: - # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) - - entries: - - key: some-static-value - value: '"something"' - - key: organization - value: 'request.headers["x-organization"]' - - key: authenticated - value: 'has(jwt.sub)' - type: tokens # or 'requests' +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + backends: + - host: localhost:8080 ``` +{{< doc-test paths="rate-limits" >}} +# WHAT THIS TEST VALIDATES: +# * The Remote example config (remoteRateLimit with descriptors) is accepted +# by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That limits are actually enforced at runtime — requires an external Envoy +# rate limit server the page omits to define and enforce the descriptors. +# * The failOpen and backend-connection-policy snippets below are focused +# field-reference fragments, not standalone configs, so they are not tested. +cat <<'EOF' > config3.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + backends: + - host: localhost:8080 +EOF +agentgateway -f config3.yaml --validate-only +{{< /doc-test >}} + Each descriptor value is a [CEL expression]({{< link-hextra path="/configuration/traffic-management/transformations" >}}). #### Failure behavior diff --git a/content/docs/standalone/main/configuration/resiliency/retries.md b/content/docs/standalone/main/configuration/resiliency/retries.md index addbe856a..a24ee468a 100644 --- a/content/docs/standalone/main/configuration/resiliency/retries.md +++ b/content/docs/standalone/main/configuration/resiliency/retries.md @@ -2,24 +2,74 @@ title: Retries weight: 10 description: Configure automatic retry attempts for failed backend requests. +test: + retries: + - file: content/docs/standalone/main/configuration/resiliency/retries.md + path: retries --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="retries" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + When a backend request fails, agentgateway can be configured to *{{< gloss "Retry" >}}retry{{< /gloss >}}* the request. When a retry is attempted, a different backend will be preferred (if possible). ```yaml -retry: - # total number of attempts allowed. - # Note: 1 attempt implies no retries; the initial attempt is included in the content. - attempts: 3 - # Optional; if set, a delay between each additional attempt - backoff: 500ms - # A list of HTTP response codes to consider retry-able. - # In addition, retries are always permitted if the request to a backend was never started. - codes: [429, 500, 503] +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + retry: + # total number of attempts allowed. + # Note: 1 attempt implies no retries; the initial attempt is included in the count. + attempts: 3 + # Optional; if set, a delay between each additional attempt + backoff: 500ms + # A list of HTTP response codes to consider retry-able. + # In addition, retries are always permitted if the request to a backend was never started. + codes: [429, 500, 503] + backends: + - host: localhost:8080 ``` +{{< doc-test paths="retries" >}} +# WHAT THIS TEST VALIDATES: +# * The retry example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That failed requests are actually retried at runtime — requires a backend +# that returns the retry-able codes the page omits to drive the behavior. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + retry: + # total number of attempts allowed. + # Note: 1 attempt implies no retries; the initial attempt is included in the count. + attempts: 3 + # Optional; if set, a delay between each additional attempt + backoff: 500ms + # A list of HTTP response codes to consider retry-able. + # In addition, retries are always permitted if the request to a backend was never started. + codes: [429, 500, 503] + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + When a request has retries enabled and an HTTP body, the request body will be buffered. If the total body size exceeds a threshold size, retries are disabled. \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index 0d8c72063..21682f264 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -2,10 +2,24 @@ title: Timeouts weight: 10 description: Set request and backend timeouts to prevent long-running requests. +test: + timeouts: + - file: content/docs/standalone/main/configuration/resiliency/timeouts.md + path: timeouts --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="timeouts" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Request {{< gloss "Timeout" >}}timeouts{{< /gloss >}} allow returning an error for requests that take too long to complete. ## Route Timeouts @@ -20,10 +34,39 @@ You can configure two types of timeouts on a route. For example: ```yaml -timeout: - requestTimeout: 1s +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + timeout: + requestTimeout: 1s + backends: + - host: localhost:8080 ``` +{{< doc-test paths="timeouts" >}} +# WHAT THIS TEST VALIDATES: +# * The route-level timeout example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That requests actually time out at runtime — requires a slow backend the +# page omits to exceed the configured deadline. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + timeout: + requestTimeout: 1s + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ## Backend Timeouts In addition to route level timeouts, you can configure per-backend timeouts within the backend configuration section. @@ -34,8 +77,43 @@ In addition to route level timeouts, you can configure per-backend timeouts with | `connectTimeout` | The time from the start of a TCP connection to a backend until the connection is established. | ```yaml -http: - requestTimeout: 1s -tcp: - connectTimeout: 10s +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8080 + policies: + http: + requestTimeout: 1s + tcp: + connectTimeout: + secs: 10 + nanos: 0 ``` + +{{< doc-test paths="timeouts" >}} +# WHAT THIS TEST VALIDATES: +# * The backend-level http/tcp timeout example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That backend request and connect timeouts actually fire at runtime — +# requires a slow/unreachable backend the page omits to trigger them. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8080 + policies: + http: + requestTimeout: 1s + tcp: + connectTimeout: + secs: 10 + nanos: 0 +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index 13208d142..aac5abd55 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -2,10 +2,24 @@ title: API Key authentication weight: 17 description: Authenticate requests using API keys with configurable validation modes. +test: + apikey-authn: + - file: content/docs/standalone/main/configuration/security/apikey-authn.md + path: apikey-authn --- Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="apikey-authn" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + {{< gloss "API Key" >}}API key{{< /gloss >}} {{< gloss "Authentication (AuthN)" >}}authentication{{< /gloss >}} enables authenticating requests based on a user-provided API key. > [!TIP] @@ -20,23 +34,105 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This setting is useful for usage of claims in later steps such as authorization or logging. *Warning*: This allows requests without an API key! +The following example shows a complete configuration that enforces API key authentication on the listener before forwarding requests to a backend. + ```yaml -apiKey: - mode: strict - keys: - - key: sk-testkey-1 - metadata: - user: test - role: admin +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + routes: + - backends: + - host: localhost:8080 ``` -Later policies can now operate on the metadata associated with the API key. +{{< doc-test paths="apikey-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The apiKey listener-level authentication example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That a request with the given key is actually authenticated at runtime — +# requires a backend the page omits to forward to. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + routes: + - backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} -For example, you can set a custom `x-authenticated-user` header with the authenticated user from the API key metadata. +Later policies can now operate on the metadata associated with the API key. For example, you can set a custom `x-authenticated-user` header with the authenticated user from the API key metadata by adding a route-level transformation. ```yaml -transformations: - request: - set: - x-authenticated-user: apiKey.user +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + routes: + - policies: + transformations: + request: + set: + x-authenticated-user: apiKey.user + backends: + - host: localhost:8080 ``` + +{{< doc-test paths="apikey-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The apiKey config combined with a route-level transformation that sets a +# header from API key metadata is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the x-authenticated-user header is actually set at runtime — +# requires a backend the page omits to forward to and inspect. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + routes: + - policies: + transformations: + request: + set: + x-authenticated-user: apiKey.user + backends: + - host: localhost:8080 +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index f8a46a783..06e6229e9 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -1,21 +1,69 @@ ---- -title: Backend authentication -weight: 10 -description: Attach authentication tokens to outgoing backend requests. +--- +title: Backend authentication +weight: 10 +description: Attach authentication tokens to outgoing backend requests. +test: + backend-authn: + - file: content/docs/standalone/main/configuration/security/backend-authn.md + path: backend-authn --- Attaches to: {{< badge content="Backend" path="/configuration/backends/" >}} +{{< doc-test paths="backend-authn" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +export MY_API_KEY="${MY_API_KEY:-dummy}" +{{< /doc-test >}} + When connecting to a backend, an authentication token can be attached to each request using the backend authentication policy. -To attach a static key as an `Authorization` value, use `key`: +To attach a static key as an `Authorization` value, use `key`. The following example shows a complete configuration that attaches the policy to a backend. ```yaml -backendAuth: - key: - value: $MY_API_KEY +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8080 + policies: + backendAuth: + key: + value: $MY_API_KEY ``` +{{< doc-test paths="backend-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The static-key backendAuth example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * The other backendAuth snippets on this page (file path, location, +# passthrough, gcp, aws) are field-reference fragments with no `binds:`, +# so they are not standalone configs and are not tested here. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8080 + policies: + backendAuth: + key: + value: $MY_API_KEY +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + +The remaining examples on this page show only the `backendAuth` policy. Attach each one to a backend under `backends[].policies`, as shown in the complete example above. + A file path can also be used: ```yaml @@ -25,7 +73,7 @@ backendAuth: file: /path/to/my/key ``` -By default, the proxy retrieves the key from the `Authorization` header value. To use a different header name, use the `location` field as shown in the following example: +By default, the proxy retrieves the key from the `Authorization` header value. To use a different header name, use the `location` field as shown in the following example: ```yaml backendAuth: @@ -58,8 +106,8 @@ backendAuth: name: api_key ``` -When using any form of incoming authentication, such as [JWT]({{< link-hextra path="/configuration/security/jwt-authn/" >}}), [API key]({{< link-hextra path="/configuration/security/apikey-authn/" >}}), or [basic auth]({{< link-hextra path="/configuration/security/basic-authn/" >}}), the original credential is removed from the request by default before forwarding to the backend. -To pass the original credential through to the backend, use the `passthrough` method: +When using any form of incoming authentication, such as [JWT]({{< link-hextra path="/configuration/security/jwt-authn/" >}}), [API key]({{< link-hextra path="/configuration/security/apikey-authn/" >}}), or [basic auth]({{< link-hextra path="/configuration/security/basic-authn/" >}}), the original credential is removed from the request by default before forwarding to the backend. +To pass the original credential through to the backend, use the `passthrough` method: ```yaml backendAuth: diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index 2e02891c1..5452d556a 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -2,24 +2,86 @@ title: Backend TLS weight: 10 description: Configure TLS for secure connections to backend services. +test: + backend-tls: + - file: content/docs/standalone/main/configuration/security/backend-tls.md + path: backend-tls --- Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="backend-tls" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + +{{< doc-test paths="backend-tls" >}} +# Create self-signed certs referenced by the example +mkdir -p certs +openssl req -x509 -newkey rsa:2048 -keyout certs/key.pem -out certs/cert.pem -days 365 -nodes -subj "/CN=localhost" 2>/dev/null +cp certs/cert.pem certs/root-cert.pem +{{< /doc-test >}} + By default, requests to backends use HTTP. To use HTTPS, configure a backend {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}} policy. +The following example shows a complete configuration that connects to a backend over HTTPS with a backend TLS policy. + ```yaml -backendTLS: - # A file containing the root certificate to verify. - # If unset, the system trust bundle will be used. - root: ./certs/root-cert.pem - # For mutual TLS, the client certificate to use - cert: ./certs/cert.pem - # For mutual TLS, the client certificate key to use. - key: ./certs/key.pem - # If set, hostname verification is disabled - # insecureHost: true - # If set, all TLS verification is disabled - # insecure: true -``` \ No newline at end of file +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8443 + policies: + backendTLS: + # A file containing the root certificate to verify. + # If unset, the system trust bundle will be used. + root: ./certs/root-cert.pem + # For mutual TLS, the client certificate to use + cert: ./certs/cert.pem + # For mutual TLS, the client certificate key to use. + key: ./certs/key.pem + # If set, hostname verification is disabled + # insecureHost: true + # If set, all TLS verification is disabled + # insecure: true +``` + +{{< doc-test paths="backend-tls" >}} +# WHAT THIS TEST VALIDATES: +# * The backendTLS example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the TLS handshake to the backend succeeds at runtime — requires an +# HTTPS backend on localhost:8443 the page omits. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8443 + policies: + backendTLS: + # A file containing the root certificate to verify. + # If unset, the system trust bundle will be used. + root: ./certs/root-cert.pem + # For mutual TLS, the client certificate to use + cert: ./certs/cert.pem + # For mutual TLS, the client certificate key to use. + key: ./certs/key.pem + # If set, hostname verification is disabled + # insecureHost: true + # If set, all TLS verification is disabled + # insecure: true +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index 367bf0027..9147e8320 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -2,10 +2,24 @@ title: Basic authentication weight: 16 description: Configure simple username and password authentication for your routes. +test: + basic-authn: + - file: content/docs/standalone/main/configuration/security/basic-authn.md + path: basic-authn --- Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="basic-authn" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + [Basic authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Authentication#basic_authentication_scheme) enables a simple username/password authentication mechanism. > [!WARNING] @@ -20,19 +34,58 @@ Additionally, authentication can run in two different modes: * **Optional** (default): If a username/password pair exists, validate it. *Warning*: This allows requests without a username/password pair! +The following example shows a complete configuration that enforces basic authentication on the listener before forwarding requests to a backend. + ```yaml -basicAuth: - mode: strict - # Generated with `htpasswd -nb -B user1 agentgateway` - # You can also use: - # htpasswd: - # file: /path/to/htpasswd - # With inline configuration, $ must be escaped to $$. - htpasswd: | - user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa - realm: example.com +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + routes: + - backends: + - host: localhost:8080 ``` +{{< doc-test paths="basic-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The basicAuth listener-level authentication example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That credentials are actually enforced at runtime — requires a backend +# the page omits to forward to. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + routes: + - backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + Now to send requests, include the username and password. ```shell diff --git a/content/docs/standalone/main/configuration/security/csrf.md b/content/docs/standalone/main/configuration/security/csrf.md index fcdbb6a1b..4c49c8ff6 100644 --- a/content/docs/standalone/main/configuration/security/csrf.md +++ b/content/docs/standalone/main/configuration/security/csrf.md @@ -2,10 +2,24 @@ title: CSRF weight: 11 description: Protect against cross-site request forgery attacks with origin validation. +test: + csrf: + - file: content/docs/standalone/main/configuration/security/csrf.md + path: csrf --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="csrf" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + ## About CSRF protection According to [OWASP](https://owasp.org/www-community/attacks/csrf), CSRF is defined as follows: @@ -72,21 +86,52 @@ Blocked requests, which receive a `403 Forbidden` response with the message "CSR {{< reuse "agw-docs/snippets/review-configuration.md" >}} ```yaml -policies: - csrf: - additionalOrigins: - - "https://www.example.com" - - "https://trusted.domain.com" +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + csrf: + additionalOrigins: + - "https://www.example.com" + - "https://trusted.domain.com" + backends: + - host: localhost:8080 ``` +{{< doc-test paths="csrf" >}} +# WHAT THIS TEST VALIDATES: +# * The csrf route-level policy with an additionalOrigins list is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That cross-site requests are actually blocked/allowed at runtime — requires +# a backend the page omits to forward to. +# * The standalone `additionalOrigins: []` snippet later on the page is a +# fragment (no binds:), so it is intentionally not tested. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + csrf: + additionalOrigins: + - "https://www.example.com" + - "https://trusted.domain.com" + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + The `additionalOrigins` setting is a list of trusted origins allowed to make cross-site requests. - Format: `"scheme://host[:port]"` - Examples: `"https://www.example.com"`, `"http://localhost:3000"` -For strict CSRF protection to prevent all cross-site requests, set `additionalOrigins` to an empty list. +For strict CSRF protection to prevent all cross-site requests, set `additionalOrigins` to an empty list, as shown in the following route-level policy. ```yaml -... policies: csrf: additionalOrigins: [] diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index 5d2b701c2..839feb630 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -2,10 +2,24 @@ title: External authorization weight: 20 description: Delegate authorization decisions to external services like OPA. +test: + external-authz: + - file: content/docs/standalone/main/configuration/security/external-authz.md + path: external-authz --- Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="external-authz" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + When {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} decisions need to be made out-of-process, use an external authorization policy. This policy has agentgateway send the request to an external server, such as [Open Policy Agent](https://www.openpolicyagent.org/docs/envoy) which decides whether the request is allowed or denied. You can configure agentgateway to do this by using the [External Authorization gRPC service](https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto) or by using HTTP requests. @@ -20,19 +34,58 @@ Agentgateway is API-compatible with the Envoy External Authorization gRPC servic When an ExtAuthz server returns header modifications, agentgateway uses `insert` instead of `append` for response headers. This ensures headers are properly set rather than potentially duplicated. -Example configuration: +The following example shows a complete configuration that attaches a gRPC external authorization policy to a route. ```yaml -extAuthz: - host: localhost:9000 - protocol: - grpc: - # Optional: metadata to send to the external authorization service - # The value is a CEL expression - metadata: - dev.agentgateway.jwt: '{"claims": jwt}' +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + backends: + - host: localhost:8080 ``` +{{< doc-test paths="external-authz" >}} +# WHAT THIS TEST VALIDATES: +# * The gRPC extAuthz route-level policy example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That authorization decisions are actually enforced at runtime — requires a +# running external authorization service the page omits. +# * The bare `extAuthz:` snippets later on the page are focused fragments +# (no binds:), so they are not tested. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + +The remaining examples in this section show only the `extAuthz` policy. Attach each one to a listener, route, or backend as needed. + ### Cache authorization results You can cache gRPC external authorization decisions with `extAuthz.cache`. Caching is supported only for `protocol.grpc`; HTTP external authorization requests are always sent to the authorization service. @@ -154,6 +207,28 @@ binds: grpc: {} ``` +{{< doc-test paths="external-authz" >}} +# WHAT THIS TEST VALIDATES: +# * The backend-level extAuthz policy example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That backend-level authorization is actually enforced at runtime — +# requires a running external authorization service the page omits. +cat <<'EOF' > config2.yaml +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:8080 + policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: {} +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} + ## Conditional execution To choose between multiple external authorization servers based on the request, use the `conditional` field. For example, you can send admin paths to a stricter authorization server and route every other request to a standard one. For details, see [Conditional policies]({{< link-hextra path="/configuration/policies/conditional-policies" >}}). diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index 855d06036..7cfe4963b 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -2,10 +2,24 @@ title: HTTP authorization weight: 12 description: Define allow, deny, and require rules using CEL expressions. +test: + http-authz: + - file: content/docs/standalone/main/configuration/security/http-authz.md + path: http-authz --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="http-authz" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + HTTP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} allows defining rules to allow or deny requests based on their properties, using [CEL expressions]({{< link-hextra path="/reference/cel/" >}}). {{< callout type="info" >}} @@ -28,16 +42,55 @@ A CEL expression that cannot be evaluated is treated as `false`. For example, if - An `allow` expression that errors does not match, so it does not allow the request. {{< /callout >}} +The following example shows a complete configuration that attaches an HTTP authorization policy to a route. + ```yaml -authorization: - rules: - - allow: 'request.path == "/authz/public"' - - deny: 'request.path == "/authz/deny"' - - require: 'jwt.aud == "my-service"' - # legacy format; same as `allow: ...` - - 'request.headers["x-allow"] == "true"' +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + backends: + - host: localhost:8080 ``` +{{< doc-test paths="http-authz" >}} +# WHAT THIS TEST VALIDATES: +# * The authorization route-level policy with allow/deny/require and legacy +# rules is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That requests are actually allowed/denied at runtime — requires a backend +# and traffic the page omits. +# * The `### Require rules` snippets and the `llm:` example are focused +# fragments / simplified-mode examples (no binds:), so they are not tested. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ### Require rules The `require` rule type expresses mandatory conditions more clearly than double-negative `deny` rules, and it fails closed. For example: diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index 706f0711b..2ee0590c2 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -2,10 +2,32 @@ title: JWT authentication weight: 15 description: Verify JWT tokens from incoming requests using JWKS and configured issuers. +test: + jwt-authn: + - file: content/docs/standalone/main/configuration/security/jwt-authn.md + path: jwt-authn --- Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="jwt-authn" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + +{{< doc-test paths="jwt-authn" >}} +# Create the JWKS file referenced by the examples +mkdir -p manifests/jwt +cat <<'EOF' > manifests/jwt/pub-key +{"keys": [{"kty": "RSA", "kid": "test", "use": "sig", "alg": "RS256", "n": "teXe4sfDoHQR5YUos3nsY_Ax6J2xrgXnIfUziaTWJ4nljejLVyg8m0g6SK9zrSaCvLm9GxAhpaJ_48RalwqDt4spBPQ8uvr-54jHrECboAbTxhy2T-oXP80Duz0xauSDVlyA_xenoCA24MFJ1rgHppy1F1eYTD-CQ-IxhXLNm5mE3rJufP_pdnMy0q6acXSfPtEzMJY3BYNV5umqimkOgH9PqQWd1RAgYdE7z5fvdCb4T4K667rRRT75PqRB4GJgSY-zQrC4CEVCw_ql7bfdouFcxXwsyh7AfImIEamA1LMODvMXVZWkZ8V0w_VEK6NHqr-BGOBVAUfRqYAEPxfaIw", "e": "AQAB"}]} +EOF +{{< /doc-test >}} + {{< gloss "JWT (JSON Web Token)" >}}JWT tokens{{< /gloss >}} from incoming requests can be verified. JWT authentication requires a few parameters: @@ -21,21 +43,101 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This is useful for usage of claims in later steps (authorization, logging, etc). *Warning*: This allows requests without a JWT token! +The following example shows a complete configuration that verifies JWTs on the listener before forwarding requests to a backend. + ```yaml -jwtAuth: - mode: strict - issuer: agentgateway.dev - audiences: [test.agentgateway.dev] - jwks: - # Relative to the folder the binary runs from, not the config file - file: ./manifests/jwt/pub-key +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + # Relative to the folder the binary runs from, not the config file + file: ./manifests/jwt/pub-key + routes: + - backends: + - host: localhost:8080 ``` -It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. -For example: +{{< doc-test paths="jwt-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The jwtAuth listener example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That a token is actually verified at runtime — requires minting a signed +# JWT and a backend on localhost:8080 the page omits. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + # Relative to the folder the binary runs from, not the config file + file: ./manifests/jwt/pub-key + routes: + - backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + +It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. The following example verifies the JWT on the listener, then applies a route-level authorization rule that allows access to `/admin` only for tokens with the `admins` group claim. ```yaml -authorization: - rules: - - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' -``` \ No newline at end of file +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + routes: + - policies: + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + backends: + - host: localhost:8080 +``` + +{{< doc-test paths="jwt-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The jwtAuth + route-level authorization example config is accepted by +# agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the authorization rule actually allows/denies at runtime — requires +# minting a signed JWT with the `admins` group and a backend the page omits. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + routes: + - policies: + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + backends: + - host: localhost:8080 +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index 947cef440..dfcb17cd9 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -29,40 +29,44 @@ In this mode, agentgateway: - Returns `401 Unauthorized` with appropriate `WWW-Authenticate` headers for unauthenticated requests ```yaml -routes: -- backends: - - mcp: - targets: - - name: tools - stdio: - cmd: npx - args: ["@modelcontextprotocol/server-everything"] - matches: - - path: - exact: /mcp - - path: - exact: /.well-known/oauth-protected-resource/mcp - - path: - exact: /.well-known/oauth-authorization-server/mcp - - path: - exact: /.well-known/oauth-authorization-server/mcp/client-registration - policies: - mcpAuthentication: - issuer: http://localhost:7080/realms/mcp - jwks: - url: http://localhost:7080/realms/mcp/protocol/openid-connect/certs - provider: - keycloak: {} - resourceMetadata: - resource: http://localhost:3000/mcp - scopesSupported: - - read:all - bearerMethodsSupported: - - header - - body - - query - resourceDocumentation: http://localhost:3000/stdio/docs - resourcePolicyUri: http://localhost:3000/stdio/policies +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + matches: + - path: + exact: /mcp + - path: + exact: /.well-known/oauth-protected-resource/mcp + - path: + exact: /.well-known/oauth-authorization-server/mcp + - path: + exact: /.well-known/oauth-authorization-server/mcp/client-registration + policies: + mcpAuthentication: + issuer: http://localhost:7080/realms/mcp + jwks: + url: http://localhost:7080/realms/mcp/protocol/openid-connect/certs + provider: + keycloak: {} + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + resourceDocumentation: http://localhost:3000/stdio/docs + resourcePolicyUri: http://localhost:3000/stdio/policies ``` ## Resource Server Only @@ -70,32 +74,36 @@ routes: Agentgateway acts solely as a resource server, validating tokens issued by an external authorization server. ```yaml -routes: -- backends: - - mcp: - targets: - - name: tools - stdio: - cmd: npx - args: ["@modelcontextprotocol/server-everything"] - matches: - - path: - exact: /mcp - - path: - exact: /.well-known/oauth-protected-resource/mcp - policies: - mcpAuthentication: - issuer: http://localhost:9000 - jwks: - url: http://localhost:9000/.well-known/jwks.json - resourceMetadata: - resource: http://localhost:3000/mcp - scopesSupported: - - read:all - bearerMethodsSupported: - - header - - body - - query +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + matches: + - path: + exact: /mcp + - path: + exact: /.well-known/oauth-protected-resource/mcp + policies: + mcpAuthentication: + issuer: http://localhost:9000 + jwks: + url: http://localhost:9000/.well-known/jwks.json + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query ``` ## Authentication mode diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 223dbb069..22f808dca 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -2,10 +2,24 @@ title: MCP authorization weight: 40 description: Define authorization rules for MCP method invocations using CEL expressions. +test: + mcp-authz-config: + - file: content/docs/standalone/main/configuration/security/mcp-authz.md + path: mcp-authz-config --- Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} (MCP Backends only) +{{< doc-test paths="mcp-authz-config" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + The MCP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} policy works similarly to [HTTP authorization]({{< link-hextra path="/configuration/security/http-authz" >}}), but runs in the context of an MCP request. > [!NOTE] @@ -15,17 +29,91 @@ Instead of running against an HTTP request, MCP authorization policies run again If a tool or other resource is not allowed, the gateway automatically filters it from the `list` response. +The following example shows a complete configuration that attaches an MCP authorization policy to an MCP backend target. + ```yaml -mcpAuthorization: - rules: - # Allow anyone to call 'echo' - - 'mcp.tool.name == "echo"' - # Only the test-user can call 'add' - - 'jwt.sub == "test-user" && mcp.tool.name == "add"' - # Any authenticated user with the claim `nested.key == value` can access 'printEnv' - - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + policies: + mcpAuthorization: + rules: + # Allow anyone to call 'echo' + - 'mcp.tool.name == "echo"' + # Only the test-user can call 'add' + - 'jwt.sub == "test-user" && mcp.tool.name == "add"' + # Any authenticated user with the claim `nested.key == value` can access 'printEnv' + - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' ``` +{{< doc-test paths="mcp-authz-config" >}} +# WHAT THIS TEST VALIDATES: +# * The MCP authorization example config loads and the gateway serves the +# stdio MCP server: the /mcp endpoint accepts an initialize request. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That unauthorized tools are actually filtered — would require an +# authenticated tools/list call with a JWT carrying the right claims. +# * The tool-arguments fragment later on the page is not a standalone config. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + policies: + mcpAuthorization: + rules: + # Allow anyone to call 'echo' + - 'mcp.tool.name == "echo"' + # Only the test-user can call 'add' + - 'jwt.sub == "test-user" && mcp.tool.name == "add"' + # Any authenticated user with the claim `nested.key == value` can access 'printEnv' + - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' +EOF +{{< /doc-test >}} + +{{< doc-test paths="mcp-authz-config" >}} +agentgateway -f config.yaml & +AGW_PID=$! +trap 'kill $AGW_PID 2>/dev/null' EXIT +sleep 3 +{{< /doc-test >}} + +{{< doc-test paths="mcp-authz-config" >}} +YAMLTest -f - <<'EOF' +- name: MCP endpoint accepts initialize request + http: + url: "http://localhost:3000" + path: /mcp + method: POST + headers: + content-type: application/json + accept: "application/json, text/event-stream" + body: | + {"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1} + source: + type: local + expect: + statusCode: 200 +EOF +{{< /doc-test >}} + {{< callout type="info" >}} Try out CEL expressions in the built-in [CEL playground]({{< link-hextra path="/reference/cel/playground/" >}}) in the agentgateway admin UI before using them in your configuration. {{< /callout >}} @@ -58,4 +146,4 @@ mcpAuthorization: - 'mcp.tool.name == "fetch" && mcp.tool.arguments.url.startsWith("https://internal.")' ``` -Refer to the [CEL reference]({{< link-hextra path="/configuration/traffic-management/transformations" >}}) for additional variables. +Refer to the [CEL reference]({{< link-hextra path="/reference/cel/" >}}) for additional variables. diff --git a/content/docs/standalone/main/configuration/security/oidc.md b/content/docs/standalone/main/configuration/security/oidc.md index 8e2a8824a..e893efeab 100644 --- a/content/docs/standalone/main/configuration/security/oidc.md +++ b/content/docs/standalone/main/configuration/security/oidc.md @@ -80,18 +80,28 @@ binds: ### Keycloak example -Review the following example for a Keycloak IdP. +Review the following complete example for a Keycloak IdP. ```yaml -policies: - oidc: - issuer: http://keycloak.example.com/realms/myrealm - clientId: agentgateway-browser - clientSecret: my-client-secret - redirectURI: http://localhost:3000/oauth/callback - scopes: - - profile - - email +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - host: localhost:18080 + matches: + - path: + pathPrefix: / + policies: + oidc: + issuer: http://keycloak.example.com/realms/myrealm + clientId: agentgateway-browser + clientSecret: my-client-secret + redirectURI: http://localhost:3000/oauth/callback + scopes: + - profile + - email ``` ## Fields diff --git a/content/docs/standalone/main/configuration/traffic-management/direct-response.md b/content/docs/standalone/main/configuration/traffic-management/direct-response.md index 752a97311..e7a829a8d 100644 --- a/content/docs/standalone/main/configuration/traffic-management/direct-response.md +++ b/content/docs/standalone/main/configuration/traffic-management/direct-response.md @@ -2,21 +2,81 @@ title: Direct Response weight: 14 description: Return custom responses directly without forwarding to a backend. +test: + direct-response: + - file: content/docs/standalone/main/configuration/traffic-management/direct-response.md + path: direct-response --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} Directly respond to a request with a custom response using {{< gloss "Direct Response" >}}direct response{{< /gloss >}}, without forwarding to any backend. +{{< doc-test paths="direct-response" >}} +# WHAT THIS TEST VALIDATES: +# * The direct response example config loads and serves: the gateway returns +# the configured 404 status directly, without a backend. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * The conditional-execution variant — requires config/traffic the page omits +# (the `conditional` field is documented on a separate page). +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} For example, the following configuration returns a `404 Not found!` response. ```yaml -directResponse: - body: "Not found!" - status: 404 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + directResponse: + body: "Not found!" + status: 404 ``` +{{< doc-test paths="direct-response" >}} +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + directResponse: + body: "Not found!" + status: 404 +EOF +{{< /doc-test >}} + +{{< doc-test paths="direct-response" >}} +agentgateway -f config.yaml & +AGW_PID=$! +trap 'kill $AGW_PID 2>/dev/null' EXIT +sleep 3 +{{< /doc-test >}} + +{{< doc-test paths="direct-response" >}} +YAMLTest -f - <<'EOF' +- name: Direct response returns configured 404 + http: + url: "http://localhost:3000" + path: / + method: GET + source: + type: local + expect: + statusCode: 404 +EOF +{{< /doc-test >}} + ## Conditional execution To return a direct response only when a CEL expression matches, use the `conditional` field. For example, you can return `410 Gone` on deprecated paths and let every other request reach the backend. For details, see [Conditional policies]({{< link-hextra path="/configuration/policies/conditional-policies" >}}). diff --git a/content/docs/standalone/main/configuration/traffic-management/manipulation.md b/content/docs/standalone/main/configuration/traffic-management/manipulation.md index e3122de39..13fa036f3 100644 --- a/content/docs/standalone/main/configuration/traffic-management/manipulation.md +++ b/content/docs/standalone/main/configuration/traffic-management/manipulation.md @@ -2,10 +2,24 @@ title: Header manipulation weight: 10 description: Add, set, or remove HTTP request and response headers. +test: + manipulation: + - file: content/docs/standalone/main/configuration/traffic-management/manipulation.md + path: manipulation --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="manipulation" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + There are a few different policies that offer manipulation of HTTP requests and responses. The `requestHeaderModifier` and `responseHeaderModifier` modify request and response headers respectively. @@ -13,13 +27,45 @@ These allow you to `add`, `set`, or `remove` headers. `add` and `set` differ in the case the header already exists; `set` will replace it while `add` will append. ```yaml -requestHeaderModifier: - add: - x-req-added: value - remove: - - x-remove-me +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestHeaderModifier: + add: + x-req-added: value + remove: + - x-remove-me + backends: + - host: localhost:8080 ``` +{{< doc-test paths="manipulation" >}} +# WHAT THIS TEST VALIDATES: +# * The requestHeaderModifier example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That headers are actually added/removed at runtime — requires a backend +# the page omits to forward to and inspect. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestHeaderModifier: + add: + x-req-added: value + remove: + - x-remove-me + backends: + - host: localhost:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + More advanced operations are available with the [`transformation` policy](../transformations). Like the `HeaderModifier` policies, this can also `add`, `set`, or `remove` headers, but can also manipulate HTTP bodies. Additionally, each modification is based on a [CEL expression]({{< link-hextra path="/configuration/traffic-management/transformations" >}}) rather than static strings. \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/traffic-management/matching.md b/content/docs/standalone/main/configuration/traffic-management/matching.md index 91eb9c52e..07f465bec 100644 --- a/content/docs/standalone/main/configuration/traffic-management/matching.md +++ b/content/docs/standalone/main/configuration/traffic-management/matching.md @@ -2,10 +2,24 @@ title: Request matching weight: 9 description: Match incoming requests by path, headers, methods, and query parameters. +test: + matching: + - file: content/docs/standalone/main/configuration/traffic-management/matching.md + path: matching --- Based on the route schema (see the [configuration reference]({{< link-hextra path="/reference/configuration/" >}}) for the full field reference and [schema validation]({{< link-hextra path="/reference/configuration/validation/" >}}) for IDE integration), you can configure the following {{< gloss "Matching" >}}matching{{< /gloss >}} conditions for HTTP or TCP routes. +{{< doc-test paths="matching" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + ## HTTP routes For routes configured with [HTTP or HTTPS listeners]({{< link-hextra path="/configuration/listeners/" >}}), you can configure the following matching conditions. These matching conditions do not apply to [TLS listeners]({{< link-hextra path="/configuration/listeners#tls-listeners" >}}), which use TCP routes and only support hostname-based matching. @@ -31,35 +45,47 @@ Only one of `exact`, `pathPrefix`, or `regex` can be specified per path matcher. {{< tabs >}} {{< tab name="Exact path matching" >}} ```yaml -routes: -- name: api-exact - matches: - - path: - exact: "/api/v1/users" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: api-exact + matches: + - path: + exact: "/api/v1/users" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Prefix path matching" >}} ```yaml -routes: -- name: api-prefix - matches: - - path: - pathPrefix: "/api/v1" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: api-prefix + matches: + - path: + pathPrefix: "/api/v1" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Regex path matching" >}} ```yaml -routes: -- name: api-regex - matches: - - path: - regex: ["^/api/v[0-9]+/users$", 0] - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: api-regex + matches: + - path: + regex: ["^/api/v[0-9]+/users$", 0] + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< /tabs >}} @@ -78,50 +104,62 @@ Match incoming requests based on HTTP headers included in the request. {{< tabs >}} {{< tab name="Exact header matching" >}} ```yaml -routes: -- name: auth-exact - matches: - - path: - pathPrefix: "/api" - headers: - - name: "Authorization" - value: - exact: "Bearer abc123token" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: auth-exact + matches: + - path: + pathPrefix: "/api" + headers: + - name: "Authorization" + value: + exact: "Bearer abc123token" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Regex header matching" >}} ```yaml -routes: -- name: auth-regex - matches: - - path: - pathPrefix: "/api" - headers: - - name: "Authorization" - value: - regex: "^Bearer .*" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: auth-regex + matches: + - path: + pathPrefix: "/api" + headers: + - name: "Authorization" + value: + regex: "^Bearer .*" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Multiple header matching" >}} ```yaml -routes: -- name: multi-header - matches: - - path: - pathPrefix: "/api" - headers: - - name: "Authorization" - value: - regex: "^Bearer .*" - - name: "Content-Type" - value: - exact: "application/json" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: multi-header + matches: + - path: + pathPrefix: "/api" + headers: + - name: "Authorization" + value: + regex: "^Bearer .*" + - name: "Content-Type" + value: + exact: "application/json" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< /tabs >}} @@ -139,45 +177,57 @@ Optionally restrict matches to specific HTTP methods. {{< tabs >}} {{< tab name="GET method matching" >}} ```yaml -routes: -- name: get-only - matches: - - path: - pathPrefix: "/api" - method: "GET" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: get-only + matches: + - path: + pathPrefix: "/api" + method: "GET" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="POST method matching" >}} ```yaml -routes: -- name: post-only - matches: - - path: - pathPrefix: "/api/users" - method: "POST" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: post-only + matches: + - path: + pathPrefix: "/api/users" + method: "POST" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Multiple methods with different backends" >}} ```yaml -routes: -- name: read-operations - matches: - - path: - pathPrefix: "/api/users" - method: "GET" - backends: - - host: read-api.example.com:8080 -- name: write-operations - matches: - - path: - pathPrefix: "/api/users" - method: "POST" - backends: - - host: write-api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: read-operations + matches: + - path: + pathPrefix: "/api/users" + method: "GET" + backends: + - host: read-api.example.com:8080 + - name: write-operations + matches: + - path: + pathPrefix: "/api/users" + method: "POST" + backends: + - host: write-api.example.com:8080 ``` {{< /tab >}} {{< /tabs >}} @@ -196,50 +246,62 @@ Match on query parameters, either by exact value or regex. {{< tabs >}} {{< tab name="Exact query parameter matching" >}} ```yaml -routes: -- name: version-exact - matches: - - path: - pathPrefix: "/api" - query: - - name: "version" - value: - exact: "v1" - backends: - - host: api-v1.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: version-exact + matches: + - path: + pathPrefix: "/api" + query: + - name: "version" + value: + exact: "v1" + backends: + - host: api-v1.example.com:8080 ``` {{< /tab >}} {{< tab name="Regex query parameter matching" >}} ```yaml -routes: -- name: version-regex - matches: - - path: - pathPrefix: "/api" - query: - - name: "version" - value: - regex: "^v[0-9]+$" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: version-regex + matches: + - path: + pathPrefix: "/api" + query: + - name: "version" + value: + regex: "^v[0-9]+$" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< tab name="Multiple query parameters" >}} ```yaml -routes: -- name: multi-query - matches: - - path: - pathPrefix: "/api" - query: - - name: "version" - value: - exact: "v1" - - name: "format" - value: - regex: "^(json|xml)$" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: multi-query + matches: + - path: + pathPrefix: "/api" + query: + - name: "version" + value: + exact: "v1" + - name: "format" + value: + regex: "^(json|xml)$" + backends: + - host: api.example.com:8080 ``` {{< /tab >}} {{< /tabs >}} @@ -249,24 +311,61 @@ routes: You can combine multiple matching conditions to create a more specific route, such as the following example. ```yaml -routes: -- name: comprehensive-match - matches: - - path: - pathPrefix: "/api/v1" - method: "GET" - headers: - - name: "Authorization" - value: - regex: "^Bearer .*" - query: - - name: "format" - value: - exact: "json" - backends: - - host: api.example.com:8080 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: comprehensive-match + matches: + - path: + pathPrefix: "/api/v1" + method: "GET" + headers: + - name: "Authorization" + value: + regex: "^Bearer .*" + query: + - name: "format" + value: + exact: "json" + backends: + - host: api.example.com:8080 ``` +{{< doc-test paths="matching" >}} +# WHAT THIS TEST VALIDATES: +# * The combined-matching example config (path + method + header + query) is +# accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime match behavior — requires a backend the page omits to route to. +# * The other match-type variants on this page (exact/prefix/regex path, +# header, method, query) are structurally analogous and not individually tested. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - name: comprehensive-match + matches: + - path: + pathPrefix: "/api/v1" + method: "GET" + headers: + - name: "Authorization" + value: + regex: "^Bearer .*" + query: + - name: "format" + value: + exact: "json" + backends: + - host: api.example.com:8080 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + ## TCP routes For routes configured with [TCP listeners]({{< link-hextra path="/configuration/routes#tcp-routes" >}}), you can configure the following matching conditions. @@ -276,12 +375,18 @@ For routes configured with [TCP listeners]({{< link-hextra path="/configuration/ Match incoming requests based on the hostname included in the request. This is primarily used for TLS termination scenarios. ```yaml -tcpRoutes: -- name: database-backend - hostnames: - - "db.example.com" - backends: - - host: postgres.example.com:5432 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 5432 + listeners: + - name: database-proxy + protocol: TCP + tcpRoutes: + - name: database-backend + hostnames: + - "db.example.com" + backends: + - host: postgres.example.com:5432 ``` ### Backend routing @@ -295,13 +400,47 @@ In the following example, traffic is load balanced across the three backends in If no weight is specified, the default is 1. Backends with a weight of 0 receive no traffic. Each incoming TCP connection maintains a 1:1 mapping with an outgoing backend connection; once a connection is established, it remains bound to its assigned backend for the lifetime of that connection. ```yaml -tcpRoutes: -- name: redis-cluster - backends: - - host: redis-1.example.com:6379 - weight: 1 - - host: redis-2.example.com:6379 - weight: 2 - - host: redis-3.example.com:6379 - weight: 1 +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 6379 + listeners: + - name: redis-proxy + protocol: TCP + tcpRoutes: + - name: redis-cluster + backends: + - host: redis-1.example.com:6379 + weight: 1 + - host: redis-2.example.com:6379 + weight: 2 + - host: redis-3.example.com:6379 + weight: 1 ``` + +{{< doc-test paths="matching" >}} +# WHAT THIS TEST VALIDATES: +# * The TCP backend-routing example config (weighted multi-backend tcpRoutes) +# is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime weighted load balancing — requires live TCP backends the page omits. +# * The hostname-matching TCP variant on this page is structurally analogous +# and not individually tested. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 6379 + listeners: + - name: redis-proxy + protocol: TCP + tcpRoutes: + - name: redis-cluster + backends: + - host: redis-1.example.com:6379 + weight: 1 + - host: redis-2.example.com:6379 + weight: 2 + - host: redis-3.example.com:6379 + weight: 1 +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/traffic-management/redirects.md b/content/docs/standalone/main/configuration/traffic-management/redirects.md index 60b3d3a1c..90db4e4f1 100644 --- a/content/docs/standalone/main/configuration/traffic-management/redirects.md +++ b/content/docs/standalone/main/configuration/traffic-management/redirects.md @@ -2,20 +2,64 @@ title: Redirects weight: 11 description: Return direct redirect responses to send users to another location. +test: + redirects: + - file: content/docs/standalone/main/configuration/traffic-management/redirects.md + path: redirects --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< doc-test paths="redirects" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Request {{< gloss "Redirect" >}}redirects{{< /gloss >}} allow returning a direct response redirecting users to another location. For example, the following configuration will return a `307 Temporary Redirect` response with the header `location: https://example.com/new-path`: ```yaml -requestRedirect: - scheme: https - authority: - full: example.com - path: - full: /new-path - status: 307 -``` \ No newline at end of file +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestRedirect: + scheme: https + authority: + full: example.com + path: + full: /new-path + status: 307 +``` + +{{< doc-test paths="redirects" >}} +# WHAT THIS TEST VALIDATES: +# * The requestRedirect example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That a 307 redirect is actually returned at runtime — requires sending a +# request and inspecting the response, which the page does not demonstrate. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + requestRedirect: + scheme: https + authority: + full: example.com + path: + full: /new-path + status: 307 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/traffic-management/rewrites.md b/content/docs/standalone/main/configuration/traffic-management/rewrites.md index b8f5b1726..bd34ded29 100644 --- a/content/docs/standalone/main/configuration/traffic-management/rewrites.md +++ b/content/docs/standalone/main/configuration/traffic-management/rewrites.md @@ -2,18 +2,64 @@ title: Rewrites weight: 13 description: Modify URL hostnames and paths of incoming requests dynamically. +test: + rewrites: + - file: content/docs/standalone/main/configuration/traffic-management/rewrites.md + path: rewrites --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="rewrites" >}} +# Install agentgateway binary +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Modify URLs of incoming requests with {{< gloss "Rewrite" >}}rewrite{{< /gloss >}} policies. For example, the following configuration modifies the request hostname to `example.com` and the request path to `/new-path`. ```yaml -urlRewrite: - authority: - full: example.com - path: - full: /new-path -``` \ No newline at end of file +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + urlRewrite: + authority: + full: example.com + path: + full: /new-path + backends: + - host: example.com:443 +``` + +{{< doc-test paths="rewrites" >}} +# WHAT THIS TEST VALIDATES: +# * The urlRewrite example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * That the hostname/path are actually rewritten at runtime — requires a +# backend the page omits to forward to and inspect. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + urlRewrite: + authority: + full: example.com + path: + full: /new-path + backends: + - host: example.com:443 +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 103a78e98..4a0e48da0 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -2,10 +2,25 @@ title: Transformations weight: 12 description: Modify header and body information for requests and responses. +test: + transformations: + - file: content/docs/standalone/main/configuration/traffic-management/transformations.md + path: transformations --- Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< doc-test paths="transformations" >}} +# Install agentgateway binary +export OPEN_AI_APIKEY="${OPEN_AI_APIKEY:-dummy}" +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /doc-test >}} + Agentgateway uses {{< gloss "Transformation" >}}transformation{{< /gloss >}} templates that are written in {{< gloss "CEL (Common Expression Language)" >}}Common Expression Language (CEL){{< /gloss >}}. CEL is a fast, portable, and safely executable language that goes beyond declarative configurations. CEL lets you develop more complex expressions in a readable, developer-friendly syntax. To learn more about how to use CEL, refer to the following resources: @@ -63,6 +78,48 @@ binds: - x-content-type-options ``` +{{< doc-test paths="transformations" >}} +# WHAT THIS TEST VALIDATES: +# * The route-level header transformation example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime header rewriting and the AI backend call — requires a live OpenAI +# backend and a real API key the page omits. +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - ai: + name: openai + provider: + openAI: + # Optional; overrides the model in requests + model: gpt-3.5-turbo + policies: + backendAuth: + key: "$OPEN_AI_APIKEY" + cors: + allowOrigins: + - "*" + allowHeaders: + - "*" + transformations: + request: + add: + x-request-path: request.path + x-client-ip: source.address + response: + add: + x-response-code: 'string(response.code)' + remove: + - server + - x-content-type-options +EOF +agentgateway -f config.yaml --validate-only +{{< /doc-test >}} + #### Listener-level header transformation Transform headers before route selection by attaching the policy at the listener level: @@ -88,6 +145,35 @@ binds: model: gpt-3.5-turbo ``` +{{< doc-test paths="transformations" >}} +# WHAT THIS TEST VALIDATES: +# * The listener-level header transformation example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime header injection and the AI backend call — requires a live OpenAI +# backend and a real API key the page omits. +cat <<'EOF' > config2.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - policies: + transformations: + request: + add: + x-gateway: '"agentgateway"' + backendAuth: + key: "$OPEN_AI_APIKEY" + routes: + - backends: + - ai: + name: openai + provider: + openAI: + model: gpt-3.5-turbo +EOF +agentgateway -f config2.yaml --validate-only +{{< /doc-test >}} + ### Body transformation You can provide a custom body for a request or response. @@ -97,15 +183,49 @@ To provide a specific string value, add your string in single quotes `'` followe {{< /callout >}} ```yaml -transformations: - request: - body: | - "Hello " + default(request.headers["x-user-name"], "guest") - response: - body: | - "Response code: " + string(response.code) +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + backends: + - host: localhost:8080 ``` +{{< doc-test paths="transformations" >}} +# WHAT THIS TEST VALIDATES: +# * The body transformation example config is accepted by agentgateway. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime body rewriting — requires a backend the page omits to forward to +# and inspect. +cat <<'EOF' > config3.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + backends: + - host: localhost:8080 +EOF +agentgateway -f config3.yaml --validate-only +{{< /doc-test >}} + ## Conditional execution To run a transformation only when a CEL expression matches, use the `conditional` field. For example, you can transform internal traffic only and leave external traffic untouched. For details, see [Conditional policies]({{< link-hextra path="/configuration/policies/conditional-policies" >}}). From 7bb1d3054d00cd80ddfbf42e944963e8173e767e Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 09:30:52 -0400 Subject: [PATCH 02/20] Install agw from image Signed-off-by: Kristin Brown --- assets/agw-docs/snippets/install-agentgateway.md | 11 +++++++++++ .../docs/standalone/main/configuration/backends.md | 8 +------- .../docs/standalone/main/configuration/listeners.md | 8 +------- .../main/configuration/resiliency/mirroring.md | 8 +------- .../main/configuration/resiliency/rate-limits.md | 8 +------- .../main/configuration/resiliency/retries.md | 8 +------- .../main/configuration/resiliency/timeouts.md | 8 +------- .../main/configuration/security/apikey-authn.md | 8 +------- .../main/configuration/security/backend-authn.md | 8 +------- .../main/configuration/security/backend-tls.md | 8 +------- .../main/configuration/security/basic-authn.md | 8 +------- .../standalone/main/configuration/security/csrf.md | 8 +------- .../main/configuration/security/external-authz.md | 8 +------- .../main/configuration/security/http-authz.md | 8 +------- .../main/configuration/security/jwt-authn.md | 8 +------- .../main/configuration/security/mcp-authz.md | 8 +------- .../traffic-management/direct-response.md | 8 +------- .../configuration/traffic-management/manipulation.md | 8 +------- .../main/configuration/traffic-management/matching.md | 8 +------- .../configuration/traffic-management/redirects.md | 8 +------- .../main/configuration/traffic-management/rewrites.md | 8 +------- .../traffic-management/transformations.md | 8 +------- 22 files changed, 32 insertions(+), 147 deletions(-) create mode 100644 assets/agw-docs/snippets/install-agentgateway.md diff --git a/assets/agw-docs/snippets/install-agentgateway.md b/assets/agw-docs/snippets/install-agentgateway.md new file mode 100644 index 000000000..48cc03921 --- /dev/null +++ b/assets/agw-docs/snippets/install-agentgateway.md @@ -0,0 +1,11 @@ +# Install the agentgateway binary from the latest main (nightly) build. +# The nightly build publishes a container image tagged 'latest-dev'; extract the +# binary from that image. The GitHub release assets only exist for tagged +# releases, not for the in-development 'main' version. +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +docker rm -f agw-extract >/dev/null 2>&1 || true +docker create --name agw-extract cr.agentgateway.dev/agentgateway:latest-dev +docker cp agw-extract:/app/agentgateway "$HOME/.local/bin/agentgateway" +docker rm agw-extract +chmod +x "$HOME/.local/bin/agentgateway" diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 170341f85..b339c737f 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -13,13 +13,7 @@ Agentgateway {{< gloss "Backend" >}}backends{{< /gloss >}} control where traffic Agentgateway supports a variety of backends, such as simple hostnames and IP addresses, {{< gloss "Provider" >}}LLM providers{{< /gloss >}}, and MCP servers. {{< doc-test paths="backends" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export OPENAI_API_KEY="${OPENAI_API_KEY:-dummy}" {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/listeners.md b/content/docs/standalone/main/configuration/listeners.md index 757e83b6b..5340747bf 100644 --- a/content/docs/standalone/main/configuration/listeners.md +++ b/content/docs/standalone/main/configuration/listeners.md @@ -12,13 +12,7 @@ Listeners are the entrypoints for traffic into agentgateway. Agentgateway supports both {{< gloss "HTTP (Hypertext Transfer Protocol)" >}}HTTP{{< /gloss >}} and {{< gloss "TCP (Transmission Control Protocol)" >}}TCP{{< /gloss >}} traffic, with and without {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}}. {{< doc-test paths="listeners" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} {{< doc-test paths="listeners" >}} diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index 36448a3db..17786535d 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="mirroring" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alterative backend. diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index 761f5217c..c11bd8ac7 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="rate-limits" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} Use rate limiting to enforce budget and spend limits per key: control the rate of requests and token usage on a route. Token-based limits let you cap usage per user, per API key, or per time window. Combined with API key authentication and observability, this gives you virtual key management. diff --git a/content/docs/standalone/main/configuration/resiliency/retries.md b/content/docs/standalone/main/configuration/resiliency/retries.md index a24ee468a..4b24d3af6 100644 --- a/content/docs/standalone/main/configuration/resiliency/retries.md +++ b/content/docs/standalone/main/configuration/resiliency/retries.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="retries" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} When a backend request fails, agentgateway can be configured to *{{< gloss "Retry" >}}retry{{< /gloss >}}* the request. diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index 21682f264..7a297038b 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="timeouts" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} Request {{< gloss "Timeout" >}}timeouts{{< /gloss >}} allow returning an error for requests that take too long to complete. diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index aac5abd55..a410ddde6 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="apikey-authn" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} {{< gloss "API Key" >}}API key{{< /gloss >}} {{< gloss "Authentication (AuthN)" >}}authentication{{< /gloss >}} enables authenticating requests based on a user-provided API key. diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index 06e6229e9..f073bbbd6 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/" >}} {{< doc-test paths="backend-authn" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export MY_API_KEY="${MY_API_KEY:-dummy}" {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index 5452d556a..1463b5f6e 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="backend-tls" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} {{< doc-test paths="backend-tls" >}} diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index 9147e8320..b42306286 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="basic-authn" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} [Basic authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Authentication#basic_authentication_scheme) enables a simple username/password authentication mechanism. diff --git a/content/docs/standalone/main/configuration/security/csrf.md b/content/docs/standalone/main/configuration/security/csrf.md index 4c49c8ff6..cc5a00d25 100644 --- a/content/docs/standalone/main/configuration/security/csrf.md +++ b/content/docs/standalone/main/configuration/security/csrf.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="csrf" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} ## About CSRF protection diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index 839feb630..3e02c00fe 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="external-authz" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} When {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} decisions need to be made out-of-process, use an external authorization policy. diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index 7cfe4963b..f8cad69d1 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="http-authz" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} HTTP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} allows defining rules to allow or deny requests based on their properties, using [CEL expressions]({{< link-hextra path="/reference/cel/" >}}). diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index 2ee0590c2..e7bd9e2b1 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="jwt-authn" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} {{< doc-test paths="jwt-authn" >}} diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 22f808dca..2a28e7032 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} (MCP Backends only) {{< doc-test paths="mcp-authz-config" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} The MCP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} policy works similarly to [HTTP authorization]({{< link-hextra path="/configuration/security/http-authz" >}}), but runs in the context of an MCP request. diff --git a/content/docs/standalone/main/configuration/traffic-management/direct-response.md b/content/docs/standalone/main/configuration/traffic-management/direct-response.md index e7a829a8d..77459f7d9 100644 --- a/content/docs/standalone/main/configuration/traffic-management/direct-response.md +++ b/content/docs/standalone/main/configuration/traffic-management/direct-response.md @@ -19,13 +19,7 @@ Directly respond to a request with a custom response using {{< gloss "Direct Res # WHAT THIS TEST DOES NOT VALIDATE (and why): # * The conditional-execution variant — requires config/traffic the page omits # (the `conditional` field is documented on a separate page). -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} For example, the following configuration returns a `404 Not found!` response. diff --git a/content/docs/standalone/main/configuration/traffic-management/manipulation.md b/content/docs/standalone/main/configuration/traffic-management/manipulation.md index 13fa036f3..afa119586 100644 --- a/content/docs/standalone/main/configuration/traffic-management/manipulation.md +++ b/content/docs/standalone/main/configuration/traffic-management/manipulation.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="manipulation" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} There are a few different policies that offer manipulation of HTTP requests and responses. diff --git a/content/docs/standalone/main/configuration/traffic-management/matching.md b/content/docs/standalone/main/configuration/traffic-management/matching.md index 07f465bec..c3262e9bd 100644 --- a/content/docs/standalone/main/configuration/traffic-management/matching.md +++ b/content/docs/standalone/main/configuration/traffic-management/matching.md @@ -11,13 +11,7 @@ test: Based on the route schema (see the [configuration reference]({{< link-hextra path="/reference/configuration/" >}}) for the full field reference and [schema validation]({{< link-hextra path="/reference/configuration/validation/" >}}) for IDE integration), you can configure the following {{< gloss "Matching" >}}matching{{< /gloss >}} conditions for HTTP or TCP routes. {{< doc-test paths="matching" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} ## HTTP routes diff --git a/content/docs/standalone/main/configuration/traffic-management/redirects.md b/content/docs/standalone/main/configuration/traffic-management/redirects.md index 90db4e4f1..60e1f69de 100644 --- a/content/docs/standalone/main/configuration/traffic-management/redirects.md +++ b/content/docs/standalone/main/configuration/traffic-management/redirects.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} {{< doc-test paths="redirects" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} Request {{< gloss "Redirect" >}}redirects{{< /gloss >}} allow returning a direct response redirecting users to another location. diff --git a/content/docs/standalone/main/configuration/traffic-management/rewrites.md b/content/docs/standalone/main/configuration/traffic-management/rewrites.md index bd34ded29..6daabc24b 100644 --- a/content/docs/standalone/main/configuration/traffic-management/rewrites.md +++ b/content/docs/standalone/main/configuration/traffic-management/rewrites.md @@ -11,13 +11,7 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="rewrites" >}} -# Install agentgateway binary -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} Modify URLs of incoming requests with {{< gloss "Rewrite" >}}rewrite{{< /gloss >}} policies. diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 4a0e48da0..907e8227e 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -11,14 +11,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< doc-test paths="transformations" >}} -# Install agentgateway binary +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export OPEN_AI_APIKEY="${OPEN_AI_APIKEY:-dummy}" -mkdir -p "$HOME/.local/bin" -export PATH="$HOME/.local/bin:$PATH" -VERSION="v{{< reuse "agw-docs/versions/n-patch.md" >}}" -BINARY_URL="https://github.com/agentgateway/agentgateway/releases/download/${VERSION}/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" -curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" -chmod +x "$HOME/.local/bin/agentgateway" {{< /doc-test >}} Agentgateway uses {{< gloss "Transformation" >}}transformation{{< /gloss >}} templates that are written in {{< gloss "CEL (Common Expression Language)" >}}Common Expression Language (CEL){{< /gloss >}}. CEL is a fast, portable, and safely executable language that goes beyond declarative configurations. CEL lets you develop more complex expressions in a readable, developer-friendly syntax. From bbfa7c51efd6169c62ddbb2ccdec49149e4e244a Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 09:42:06 -0400 Subject: [PATCH 03/20] Test fixes Signed-off-by: Kristin Brown --- .../main/configuration/listeners.md | 23 ++++--------------- .../main/configuration/resiliency/timeouts.md | 4 ++++ .../traffic-management/transformations.md | 14 ++++++----- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/content/docs/standalone/main/configuration/listeners.md b/content/docs/standalone/main/configuration/listeners.md index 5340747bf..0a22357d2 100644 --- a/content/docs/standalone/main/configuration/listeners.md +++ b/content/docs/standalone/main/configuration/listeners.md @@ -259,25 +259,10 @@ binds: key: examples/tls/certs/key.pem ``` -{{< doc-test paths="listeners" >}} -# WHAT THIS TEST VALIDATES: -# * The auto-detect protocol listener example config is accepted by agentgateway. -# WHAT THIS TEST DOES NOT VALIDATE (and why): -# * That the gateway actually dispatches TLS vs HTTP per connection at runtime — -# requires client connections the page does not exercise. -cat <<'EOF' > config6.yaml -# yaml-language-server: $schema=https://agentgateway.dev/schema/config -binds: -- port: 443 - listeners: - - protocol: auto - routes: [] - tls: - cert: examples/tls/certs/cert.pem - key: examples/tls/certs/key.pem -EOF -agentgateway -f config6.yaml --validate-only -{{< /doc-test >}} + ## TLS Listeners diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index 7a297038b..ad5ddd8f1 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -85,6 +85,8 @@ binds: connectTimeout: secs: 10 nanos: 0 + # Required when setting tcp connection options; {} keeps keepalive defaults + keepalives: {} ``` {{< doc-test paths="timeouts" >}} @@ -108,6 +110,8 @@ binds: connectTimeout: secs: 10 nanos: 0 + # Required when setting tcp connection options; {} keeps keepalive defaults + keepalives: {} EOF agentgateway -f config2.yaml --validate-only {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 907e8227e..cf3ee2a57 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -128,10 +128,11 @@ binds: request: add: x-gateway: '"agentgateway"' - backendAuth: - key: "$OPEN_AI_APIKEY" routes: - - backends: + - policies: + backendAuth: + key: "$OPEN_AI_APIKEY" + backends: - ai: name: openai provider: @@ -155,10 +156,11 @@ binds: request: add: x-gateway: '"agentgateway"' - backendAuth: - key: "$OPEN_AI_APIKEY" routes: - - backends: + - policies: + backendAuth: + key: "$OPEN_AI_APIKEY" + backends: - ai: name: openai provider: From 86cabe3a5e3a1a2e97bdbcf8e2d9e7982005c481 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 09:43:01 -0400 Subject: [PATCH 04/20] Test fix Signed-off-by: Kristin Brown --- content/docs/standalone/main/configuration/backends.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index b339c737f..cbfafd313 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -109,7 +109,7 @@ agentgateway -f config2.yaml --validate-only ### Session routing -By default, MCP backends use stateful session routing, where the gateway tracks session IDs and routes subsequent requests to the same upstream. For upstreams that do not maintain server-side session state, you can set `statefulMode: Stateless`. In stateless mode, the gateway automatically wraps each request with an initialization sequence, so the upstream server processes every request independently. +By default, MCP backends use stateful session routing, where the gateway tracks session IDs and routes subsequent requests to the same upstream. For upstreams that do not maintain server-side session state, you can set `statefulMode: stateless`. In stateless mode, the gateway automatically wraps each request with an initialization sequence, so the upstream server processes every request independently. ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config @@ -119,7 +119,7 @@ binds: - routes: - backends: - mcp: - statefulMode: Stateless + statefulMode: stateless targets: - name: openapi-server openapi: @@ -141,7 +141,7 @@ binds: - routes: - backends: - mcp: - statefulMode: Stateless + statefulMode: stateless targets: - name: openapi-server openapi: From 80d30aeed92382da590902a1d9c37bbb94741230 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 09:54:55 -0400 Subject: [PATCH 05/20] Added host Signed-off-by: Kristin Brown --- content/docs/standalone/main/configuration/backends.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index cbfafd313..583f605ff 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -123,6 +123,7 @@ binds: targets: - name: openapi-server openapi: + host: petstore3.swagger.io:443 schema: url: https://petstore3.swagger.io/api/v3/openapi.json ``` @@ -145,6 +146,7 @@ binds: targets: - name: openapi-server openapi: + host: petstore3.swagger.io:443 schema: url: https://petstore3.swagger.io/api/v3/openapi.json EOF From 4b7b41c30f54795fa7bcbf8e25637cce3bd424d2 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 10:03:29 -0400 Subject: [PATCH 06/20] Removed complete Signed-off-by: Kristin Brown --- .../standalone/main/configuration/security/apikey-authn.md | 2 -- .../standalone/main/configuration/security/backend-authn.md | 2 +- .../standalone/main/configuration/security/backend-tls.md | 2 -- .../standalone/main/configuration/security/basic-authn.md | 2 -- .../standalone/main/configuration/security/external-authz.md | 2 -- .../standalone/main/configuration/security/http-authz.md | 2 -- .../docs/standalone/main/configuration/security/jwt-authn.md | 5 ++--- .../docs/standalone/main/configuration/security/mcp-authz.md | 2 -- content/docs/standalone/main/configuration/security/oidc.md | 2 +- 9 files changed, 4 insertions(+), 17 deletions(-) diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index a410ddde6..0f297d543 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -28,8 +28,6 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This setting is useful for usage of claims in later steps such as authorization or logging. *Warning*: This allows requests without an API key! -The following example shows a complete configuration that enforces API key authentication on the listener before forwarding requests to a backend. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index f073bbbd6..1d89a46de 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -17,7 +17,7 @@ export MY_API_KEY="${MY_API_KEY:-dummy}" When connecting to a backend, an authentication token can be attached to each request using the backend authentication policy. -To attach a static key as an `Authorization` value, use `key`. The following example shows a complete configuration that attaches the policy to a backend. +To attach a static key as an `Authorization` value, use `key`: ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index 1463b5f6e..a8a2b13c0 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -24,8 +24,6 @@ cp certs/cert.pem certs/root-cert.pem By default, requests to backends use HTTP. To use HTTPS, configure a backend {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}} policy. -The following example shows a complete configuration that connects to a backend over HTTPS with a backend TLS policy. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index b42306286..c4f37f57f 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -28,8 +28,6 @@ Additionally, authentication can run in two different modes: * **Optional** (default): If a username/password pair exists, validate it. *Warning*: This allows requests without a username/password pair! -The following example shows a complete configuration that enforces basic authentication on the listener before forwarding requests to a backend. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index 3e02c00fe..a05226ac2 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -28,8 +28,6 @@ Agentgateway is API-compatible with the Envoy External Authorization gRPC servic When an ExtAuthz server returns header modifications, agentgateway uses `insert` instead of `append` for response headers. This ensures headers are properly set rather than potentially duplicated. -The following example shows a complete configuration that attaches a gRPC external authorization policy to a route. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index f8cad69d1..2edbbb4d4 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -36,8 +36,6 @@ A CEL expression that cannot be evaluated is treated as `false`. For example, if - An `allow` expression that errors does not match, so it does not allow the request. {{< /callout >}} -The following example shows a complete configuration that attaches an HTTP authorization policy to a route. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index e7bd9e2b1..bdacef953 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -37,8 +37,6 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This is useful for usage of claims in later steps (authorization, logging, etc). *Warning*: This allows requests without a JWT token! -The following example shows a complete configuration that verifies JWTs on the listener before forwarding requests to a backend. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -83,7 +81,8 @@ EOF agentgateway -f config.yaml --validate-only {{< /doc-test >}} -It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. The following example verifies the JWT on the listener, then applies a route-level authorization rule that allows access to `/admin` only for tokens with the `admins` group claim. +It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. +For example: ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 2a28e7032..7a3eac56d 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -23,8 +23,6 @@ Instead of running against an HTTP request, MCP authorization policies run again If a tool or other resource is not allowed, the gateway automatically filters it from the `list` response. -The following example shows a complete configuration that attaches an MCP authorization policy to an MCP backend target. - ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/oidc.md b/content/docs/standalone/main/configuration/security/oidc.md index e893efeab..b1abfb764 100644 --- a/content/docs/standalone/main/configuration/security/oidc.md +++ b/content/docs/standalone/main/configuration/security/oidc.md @@ -80,7 +80,7 @@ binds: ### Keycloak example -Review the following complete example for a Keycloak IdP. +Review the following example for a Keycloak IdP. ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config From 92181f7db034c789833db795ecd5b9a207bf27a3 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 14:38:50 -0400 Subject: [PATCH 07/20] Fixes Signed-off-by: Kristin Brown --- .../standalone/main/configuration/backends.md | 72 +++++++++++- .../main/configuration/listeners.md | 2 + .../configuration/resiliency/mirroring.md | 45 +++++++- .../configuration/resiliency/rate-limits.md | 80 +++++++++++++- .../main/configuration/resiliency/retries.md | 53 ++++++++- .../main/configuration/resiliency/timeouts.md | 39 ++++++- .../configuration/security/apikey-authn.md | 88 ++++++++++++++- .../configuration/security/backend-authn.md | 41 ++++++- .../configuration/security/backend-tls.md | 59 +++++++++- .../configuration/security/basic-authn.md | 100 ++++++++++++++++- .../main/configuration/security/cors.md | 34 +++++- .../main/configuration/security/csrf.md | 46 +++++++- .../configuration/security/external-authz.md | 92 +++++++++++++++- .../main/configuration/security/http-authz.md | 93 +++++++++++++++- .../main/configuration/security/jwt-authn.md | 88 ++++++++++++++- .../main/configuration/security/mcp-authn.md | 35 ++++++ .../main/configuration/security/oidc.md | 47 ++++++++ .../traffic-management/direct-response.md | 38 +++++++ .../traffic-management/manipulation.md | 45 +++++++- .../traffic-management/matching.md | 2 + .../traffic-management/redirects.md | 49 ++++++++- .../traffic-management/rewrites.md | 45 +++++++- .../traffic-management/transformations.md | 104 +++++++++++++++++- 23 files changed, 1265 insertions(+), 32 deletions(-) diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 583f605ff..9ea035d15 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -63,6 +63,25 @@ The MCP backend allows you to connect to an MCP server. Below shows a simple example, exposing a local and remote MCP server. See the [MCP connectivity guide]({{< link-hextra path="/mcp/" >}}) for more information. +Agentgateway supports more than one configuration style. The following tabs show the same MCP targets in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + targets: + - name: stdio-server + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + - name: http-server + mcp: + host: https://example.com/mcp +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -80,10 +99,13 @@ binds: mcp: host: https://example.com/mcp ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="backends" >}} # WHAT THIS TEST VALIDATES: -# * The MCP backend example config (stdio + remote MCP targets) is accepted by agentgateway. +# * The MCP backend example (stdio + remote MCP targets) is accepted by +# agentgateway in both the routing-based (binds) and simplified MCP (mcp) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the MCP targets actually start/connect at runtime — requires the npx # command and remote server the page does not stand up. @@ -105,6 +127,21 @@ binds: host: https://example.com/mcp EOF agentgateway -f config2.yaml --validate-only + +cat <<'EOF' > config2-simplified.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + targets: + - name: stdio-server + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + - name: http-server + mcp: + host: https://example.com/mcp +EOF +agentgateway -f config2-simplified.yaml --validate-only {{< /doc-test >}} ### Session routing @@ -159,6 +196,22 @@ Agentgateway natively supports connecting to LLM providers, such as OpenAI and A Below shows a simple example, connecting to OpenAI. See the [LLM consumption guide]({{< link-hextra path="/llm/" >}}) for more information. +Agentgateway supports more than one configuration style. The following tabs show the same OpenAI provider in the routing-based form (`binds`) and in the simplified `llm` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + models: + - name: openai + provider: openAI + params: + model: gpt-3.5-turbo + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -175,10 +228,13 @@ binds: backendAuth: key: "$OPENAI_API_KEY" ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="backends" >}} # WHAT THIS TEST VALIDATES: -# * The OpenAI LLM provider (ai backend) example config is accepted by agentgateway. +# * The OpenAI LLM provider example is accepted by agentgateway in both the +# routing-based (ai backend) and simplified LLM (llm.models) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That requests are actually proxied to OpenAI at runtime — requires a real # OPENAI_API_KEY and live LLM traffic the page omits. @@ -199,4 +255,16 @@ binds: key: "$OPENAI_API_KEY" EOF agentgateway -f config4.yaml --validate-only + +cat <<'EOF' > config4-simplified.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + models: + - name: openai + provider: openAI + params: + model: gpt-3.5-turbo + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config4-simplified.yaml --validate-only {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/listeners.md b/content/docs/standalone/main/configuration/listeners.md index 0a22357d2..7a66ffd1e 100644 --- a/content/docs/standalone/main/configuration/listeners.md +++ b/content/docs/standalone/main/configuration/listeners.md @@ -11,6 +11,8 @@ test: Listeners are the entrypoints for traffic into agentgateway. Agentgateway supports both {{< gloss "HTTP (Hypertext Transfer Protocol)" >}}HTTP{{< /gloss >}} and {{< gloss "TCP (Transmission Control Protocol)" >}}TCP{{< /gloss >}} traffic, with and without {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}}. +The following examples use routing-based configuration with `binds`. If you only route to LLM or MCP backends, the simplified `llm` and `mcp` modes set the listener port and TLS directly through `llm.port`, `llm.tls`, and `mcp.port`. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + {{< doc-test paths="listeners" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index 17786535d..8358e78b2 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -17,6 +17,28 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alterative backend. These request will not be retried if they fail. +Agentgateway supports more than one configuration style. The following tabs show the same `requestMirror` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestMirror: + backend: + host: localhost:8080 + # Mirror 50% of requests + percentage: 0.5 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -32,10 +54,13 @@ binds: backends: - host: localhost:8000 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="mirroring" >}} # WHAT THIS TEST VALIDATES: -# * The requestMirror example config is accepted by agentgateway. +# * The requestMirror policy is accepted by agentgateway in both the +# routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That requests are actually mirrored at runtime — requires live primary # and mirror backends the page omits to send to and inspect. @@ -55,4 +80,22 @@ binds: - host: localhost:8000 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestMirror: + backend: + host: localhost:8080 + # Mirror 50% of requests + percentage: 0.5 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index c11bd8ac7..d4b791b17 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -36,6 +36,45 @@ By default, agentgateway applies rate limits to requests. Therefore, each reques To explicitly set request-based rate limits, set the rate limiting type to `requests` as shown in the following example. +Agentgateway supports more than one configuration style. The following tabs show the same `localRateLimit` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + localRateLimit: + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + localRateLimit: + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -51,10 +90,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="rate-limits" >}} # WHAT THIS TEST VALIDATES: -# * The request-based localRateLimit example config is accepted by agentgateway. +# * The request-based localRateLimit policy is accepted by agentgateway in the +# routing-based (binds), simplified LLM (llm.policies), and simplified MCP +# (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That requests are actually limited at runtime — requires driving traffic # past the configured bucket, which the page does not exercise. @@ -74,9 +117,42 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only -{{< /doc-test >}} +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + localRateLimit: + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + localRateLimit: + - maxTokens: 10 + tokensPerFill: 1 + fillInterval: 60s + type: requests + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only +{{< /doc-test >}} ### Token-based rate limits diff --git a/content/docs/standalone/main/configuration/resiliency/retries.md b/content/docs/standalone/main/configuration/resiliency/retries.md index 4b24d3af6..fb2452441 100644 --- a/content/docs/standalone/main/configuration/resiliency/retries.md +++ b/content/docs/standalone/main/configuration/resiliency/retries.md @@ -17,6 +17,32 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} When a backend request fails, agentgateway can be configured to *{{< gloss "Retry" >}}retry{{< /gloss >}}* the request. When a retry is attempted, a different backend will be preferred (if possible). +Agentgateway supports more than one configuration style. The following tabs show the same `retry` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + retry: + # total number of attempts allowed. + # Note: 1 attempt implies no retries; the initial attempt is included in the count. + attempts: 3 + # Optional; if set, a delay between each additional attempt + backoff: 500ms + # A list of HTTP response codes to consider retry-able. + # In addition, retries are always permitted if the request to a backend was never started. + codes: [429, 500, 503] + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -36,10 +62,13 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="retries" >}} # WHAT THIS TEST VALIDATES: -# * The retry example config is accepted by agentgateway. +# * The retry policy is accepted by agentgateway in both the routing-based +# (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That failed requests are actually retried at runtime — requires a backend # that returns the retry-able codes the page omits to drive the behavior. @@ -63,6 +92,28 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + retry: + # total number of attempts allowed. + # Note: 1 attempt implies no retries; the initial attempt is included in the count. + attempts: 3 + # Optional; if set, a delay between each additional attempt + backoff: 500ms + # A list of HTTP response codes to consider retry-able. + # In addition, retries are always permitted if the request to a backend was never started. + codes: [429, 500, 503] + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} When a request has retries enabled and an HTTP body, the request body will be buffered. diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index ad5ddd8f1..3ddfb9c11 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -25,8 +25,25 @@ You can configure two types of timeouts on a route. |`requestTimeout`|The time from the start of an incoming request, until the end of the response headers is received. Note if there are retries, this includes the total time across retries.| |`backendRequestTimeout`|The time from the start of a request to a backend, until the end of the response headers are completed. Note this is per-request, so with retries this is a per-retry timeout.| -For example: +Agentgateway supports more than one configuration style. The following tabs show the same `timeout` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + timeout: + requestTimeout: 1s + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -39,10 +56,13 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="timeouts" >}} # WHAT THIS TEST VALIDATES: -# * The route-level timeout example config is accepted by agentgateway. +# * The route-level timeout policy is accepted by agentgateway in both the +# routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That requests actually time out at runtime — requires a slow backend the # page omits to exceed the configured deadline. @@ -59,6 +79,21 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + timeout: + requestTimeout: 1s + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} ## Backend Timeouts diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index 0f297d543..12273cdf3 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -28,6 +28,49 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This setting is useful for usage of claims in later steps such as authorization or logging. *Warning*: This allows requests without an API key! +Agentgateway supports more than one configuration style. The following tabs show the same `apiKey` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -45,10 +88,14 @@ binds: - backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="apikey-authn" >}} # WHAT THIS TEST VALIDATES: -# * The apiKey listener-level authentication example config is accepted by agentgateway. +# * The apiKey authentication policy is accepted by agentgateway in all three +# configuration forms: routing-based (binds), simplified LLM (llm.policies), +# and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That a request with the given key is actually authenticated at runtime — # requires a backend the page omits to forward to. @@ -70,6 +117,45 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} Later policies can now operate on the metadata associated with the API key. For example, you can set a custom `x-authenticated-user` header with the authenticated user from the API key metadata by adding a route-level transformation. diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index 1d89a46de..cbc11afd5 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -19,6 +19,26 @@ When connecting to a backend, an authentication token can be attached to each re To attach a static key as an `Authorization` value, use `key`: +Agentgateway supports more than one configuration style. The following tabs show the same `backendAuth` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + backendAuth: + key: + value: $MY_API_KEY + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -32,10 +52,13 @@ binds: key: value: $MY_API_KEY ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="backend-authn" >}} # WHAT THIS TEST VALIDATES: -# * The static-key backendAuth example config is accepted by agentgateway. +# * The static-key backendAuth example config is accepted by agentgateway in +# both the routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * The other backendAuth snippets on this page (file path, location, # passthrough, gcp, aws) are field-reference fragments with no `binds:`, @@ -54,6 +77,22 @@ binds: value: $MY_API_KEY EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + backendAuth: + key: + value: $MY_API_KEY + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} The remaining examples on this page show only the `backendAuth` policy. Attach each one to a backend under `backends[].policies`, as shown in the complete example above. diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index a8a2b13c0..42dccb24b 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -24,6 +24,35 @@ cp certs/cert.pem certs/root-cert.pem By default, requests to backends use HTTP. To use HTTPS, configure a backend {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}} policy. +Agentgateway supports more than one configuration style. The following tabs show the same `backendTLS` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + backendTLS: + # A file containing the root certificate to verify. + # If unset, the system trust bundle will be used. + root: ./certs/root-cert.pem + # For mutual TLS, the client certificate to use + cert: ./certs/cert.pem + # For mutual TLS, the client certificate key to use. + key: ./certs/key.pem + # If set, hostname verification is disabled + # insecureHost: true + # If set, all TLS verification is disabled + # insecure: true + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -46,10 +75,13 @@ binds: # If set, all TLS verification is disabled # insecure: true ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="backend-tls" >}} # WHAT THIS TEST VALIDATES: -# * The backendTLS example config is accepted by agentgateway. +# * The backendTLS example config is accepted by agentgateway in both the +# routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the TLS handshake to the backend succeeds at runtime — requires an # HTTPS backend on localhost:8443 the page omits. @@ -76,4 +108,29 @@ binds: # insecure: true EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + backendTLS: + # A file containing the root certificate to verify. + # If unset, the system trust bundle will be used. + root: ./certs/root-cert.pem + # For mutual TLS, the client certificate to use + cert: ./certs/cert.pem + # For mutual TLS, the client certificate key to use. + key: ./certs/key.pem + # If set, hostname verification is disabled + # insecureHost: true + # If set, all TLS verification is disabled + # insecure: true + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index c4f37f57f..8d8276e00 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -28,6 +28,55 @@ Additionally, authentication can run in two different modes: * **Optional** (default): If a username/password pair exists, validate it. *Warning*: This allows requests without a username/password pair! +Agentgateway supports more than one configuration style. The following tabs show the same `basicAuth` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -48,10 +97,14 @@ binds: - backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="basic-authn" >}} # WHAT THIS TEST VALIDATES: -# * The basicAuth listener-level authentication example config is accepted by agentgateway. +# * The basicAuth authentication policy is accepted by agentgateway in all +# three configuration forms: routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That credentials are actually enforced at runtime — requires a backend # the page omits to forward to. @@ -76,6 +129,51 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + basicAuth: + mode: strict + # Generated with `htpasswd -nb -B user1 agentgateway` + # You can also use: + # htpasswd: + # file: /path/to/htpasswd + # With inline configuration, $ must be escaped to $$. + htpasswd: | + user1:$$2y$$05$$LMZ.8WGNqvagmtJz2Gw6VuiE6khXc2zc0FDTHrfWJyLT66HM8BMAa + realm: example.com + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} Now to send requests, include the username and password. diff --git a/content/docs/standalone/main/configuration/security/cors.md b/content/docs/standalone/main/configuration/security/cors.md index a28a28ce6..68bbae16d 100644 --- a/content/docs/standalone/main/configuration/security/cors.md +++ b/content/docs/standalone/main/configuration/security/cors.md @@ -48,7 +48,7 @@ CORS policies are typically implemented to limit access to server resources for > [!TIP] > Requests that violate the CORS policy will still have responses returned, but the browser will reject them. As such, usage of tools like `curl` with `cors` can be confusing, as `curl` does not respect CORS headers. -The same CORS fields are supported in both simplified LLM and route-based configurations: +Agentgateway supports more than one configuration style. The following tabs show the same `cors` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). The same CORS fields are supported in every form: - `allowOrigins` - `allowMethods` - `allowHeaders` @@ -57,8 +57,7 @@ The same CORS fields are supported in both simplified LLM and route-based config - `maxAge` {{< tabs >}} -{{< tab name="Simplified LLM" >}} - +{{< tab name="Simplified (LLM)" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config llm: @@ -83,8 +82,33 @@ llm: apiKey: "$OPENAI_API_KEY" ``` {{< /tab >}} -{{< tab name="Route-based" >}} - +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + cors: + allowOrigins: + - https://chat.example.com + allowMethods: + - POST + - OPTIONS + allowHeaders: + - authorization + - content-type + exposeHeaders: + - x-request-id + allowCredentials: true + maxAge: 10m + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: diff --git a/content/docs/standalone/main/configuration/security/csrf.md b/content/docs/standalone/main/configuration/security/csrf.md index cc5a00d25..bffb1244e 100644 --- a/content/docs/standalone/main/configuration/security/csrf.md +++ b/content/docs/standalone/main/configuration/security/csrf.md @@ -22,7 +22,6 @@ According to [OWASP](https://owasp.org/www-community/attacks/csrf), CSRF is defi To help prevent CSRF attacks, the CSRF policy implements a multi-layered validation approach to allow or block requests based on their properties. The policy checks that the request's origin matches its destination. If the origin and destination do not match, a 403 Forbidden error code is returned. Unlike CORS, CSRF protection works with all HTTP clients, not just browsers. - Review the following diagram to see an example CSRF request flow: ```mermaid sequenceDiagram @@ -73,12 +72,31 @@ Blocked requests, which receive a `403 Forbidden` response with the message "CSR > [!NOTE] > Note that because CSRF attacks specifically target state-changing requests, the filter only acts on HTTP requests that have a state-changing method such as `POST` or `PUT`. - - ## Configuration {{< reuse "agw-docs/snippets/review-configuration.md" >}} +Agentgateway supports more than one configuration style. The following tabs show the same `csrf` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + csrf: + additionalOrigins: + - "https://www.example.com" + - "https://trusted.domain.com" + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -93,10 +111,13 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="csrf" >}} # WHAT THIS TEST VALIDATES: -# * The csrf route-level policy with an additionalOrigins list is accepted by agentgateway. +# * The csrf policy with an additionalOrigins list is accepted by agentgateway +# in both the routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That cross-site requests are actually blocked/allowed at runtime — requires # a backend the page omits to forward to. @@ -117,6 +138,23 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + csrf: + additionalOrigins: + - "https://www.example.com" + - "https://trusted.domain.com" + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} The `additionalOrigins` setting is a list of trusted origins allowed to make cross-site requests. diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index a05226ac2..0bd9e85bf 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -28,6 +28,51 @@ Agentgateway is API-compatible with the Envoy External Authorization gRPC servic When an ExtAuthz server returns header modifications, agentgateway uses `insert` instead of `append` for response headers. This ensures headers are properly set rather than potentially duplicated. +Agentgateway supports more than one configuration style. The following tabs show the same `extAuthz` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -46,10 +91,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="external-authz" >}} # WHAT THIS TEST VALIDATES: -# * The gRPC extAuthz route-level policy example config is accepted by agentgateway. +# * The gRPC extAuthz policy example config is accepted by agentgateway in all +# three configuration forms: routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That authorization decisions are actually enforced at runtime — requires a # running external authorization service the page omits. @@ -74,6 +123,47 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + extAuthz: + host: localhost:9000 + protocol: + grpc: + # Optional: metadata to send to the external authorization service + # The value is a CEL expression + metadata: + dev.agentgateway.jwt: '{"claims": jwt}' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} The remaining examples in this section show only the `extAuthz` policy. Attach each one to a listener, route, or backend as needed. diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index 2edbbb4d4..a8646769e 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -36,6 +36,49 @@ A CEL expression that cannot be evaluated is treated as `false`. For example, if - An `allow` expression that errors does not match, so it does not allow the request. {{< /callout >}} +Agentgateway supports more than one configuration style. The following tabs show the same `authorization` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -53,16 +96,19 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="http-authz" >}} # WHAT THIS TEST VALIDATES: -# * The authorization route-level policy with allow/deny/require and legacy -# rules is accepted by agentgateway. +# * The authorization policy with allow/deny/require and legacy rules is +# accepted by agentgateway in all three configuration forms: routing-based +# (binds), simplified LLM (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That requests are actually allowed/denied at runtime — requires a backend # and traffic the page omits. -# * The `### Require rules` snippets and the `llm:` example are focused -# fragments / simplified-mode examples (no binds:), so they are not tested. +# * The `### Require rules` snippets and the model-layer `llm:` example are +# focused fragments, so they are not tested. cat <<'EOF' > config.yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -81,6 +127,45 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + authorization: + rules: + - allow: 'request.path == "/authz/public"' + - deny: 'request.path == "/authz/deny"' + - require: 'jwt.aud == "my-service"' + # legacy format; same as `allow: ...` + - 'request.headers["x-allow"] == "true"' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} ### Require rules diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index bdacef953..0030e14d0 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -37,6 +37,49 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This is useful for usage of claims in later steps (authorization, logging, etc). *Warning*: This allows requests without a JWT token! +Agentgateway supports more than one configuration style. The following tabs show the same `jwtAuth` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + # Relative to the folder the binary runs from, not the config file + file: ./manifests/jwt/pub-key + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + # Relative to the folder the binary runs from, not the config file + file: ./manifests/jwt/pub-key + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -54,13 +97,17 @@ binds: - backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="jwt-authn" >}} # WHAT THIS TEST VALIDATES: -# * The jwtAuth listener example config is accepted by agentgateway. +# * The jwtAuth policy is accepted by agentgateway in all three configuration +# forms: routing-based (binds), simplified LLM (llm.policies), and +# simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That a token is actually verified at runtime — requires minting a signed -# JWT and a backend on localhost:8080 the page omits. +# JWT and a backend the page omits. cat <<'EOF' > config.yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -79,6 +126,43 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index dfcb17cd9..759c11cd9 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -28,6 +28,39 @@ In this mode, agentgateway: - Validates tokens using the authorization server's JWKS - Returns `401 Unauthorized` with appropriate `WWW-Authenticate` headers for unauthenticated requests +Agentgateway supports more than one configuration style. The following tabs show the same `mcpAuthentication` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + mcpAuthentication: + issuer: http://localhost:7080/realms/mcp + jwks: + url: http://localhost:7080/realms/mcp/protocol/openid-connect/certs + provider: + keycloak: {} + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + resourceDocumentation: http://localhost:3000/stdio/docs + resourcePolicyUri: http://localhost:3000/stdio/policies + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -68,6 +101,8 @@ binds: resourceDocumentation: http://localhost:3000/stdio/docs resourcePolicyUri: http://localhost:3000/stdio/policies ``` +{{< /tab >}} +{{< /tabs >}} ## Resource Server Only diff --git a/content/docs/standalone/main/configuration/security/oidc.md b/content/docs/standalone/main/configuration/security/oidc.md index b1abfb764..870671ef3 100644 --- a/content/docs/standalone/main/configuration/security/oidc.md +++ b/content/docs/standalone/main/configuration/security/oidc.md @@ -56,6 +56,51 @@ Review the following details about session management. Add the `oidc` policy to a route to protect it with browser-based OIDC authentication. +Agentgateway supports more than one configuration style. The following tabs show the same `oidc` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + oidc: + issuer: http://localhost:7080/realms/agentgateway + clientId: agentgateway-browser + clientSecret: agentgateway-secret + redirectURI: http://localhost:3000/oauth/callback + scopes: + - profile + - email + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + oidc: + issuer: http://localhost:7080/realms/agentgateway + clientId: agentgateway-browser + clientSecret: agentgateway-secret + redirectURI: http://localhost:3000/oauth/callback + scopes: + - profile + - email + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -77,6 +122,8 @@ binds: - profile - email ``` +{{< /tab >}} +{{< /tabs >}} ### Keycloak example diff --git a/content/docs/standalone/main/configuration/traffic-management/direct-response.md b/content/docs/standalone/main/configuration/traffic-management/direct-response.md index 77459f7d9..bc3539e66 100644 --- a/content/docs/standalone/main/configuration/traffic-management/direct-response.md +++ b/content/docs/standalone/main/configuration/traffic-management/direct-response.md @@ -24,6 +24,26 @@ Directly respond to a request with a custom response using {{< gloss "Direct Res For example, the following configuration returns a `404 Not found!` response. +Agentgateway supports more than one configuration style. The following tabs show the same `directResponse` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + directResponse: + body: "Not found!" + status: 404 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -35,6 +55,8 @@ binds: body: "Not found!" status: 404 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="direct-response" >}} cat <<'EOF' > config.yaml @@ -48,6 +70,22 @@ binds: body: "Not found!" status: 404 EOF + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + directResponse: + body: "Not found!" + status: 404 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} {{< doc-test paths="direct-response" >}} diff --git a/content/docs/standalone/main/configuration/traffic-management/manipulation.md b/content/docs/standalone/main/configuration/traffic-management/manipulation.md index afa119586..963d66cd7 100644 --- a/content/docs/standalone/main/configuration/traffic-management/manipulation.md +++ b/content/docs/standalone/main/configuration/traffic-management/manipulation.md @@ -20,6 +20,28 @@ The `requestHeaderModifier` and `responseHeaderModifier` modify request and resp These allow you to `add`, `set`, or `remove` headers. `add` and `set` differ in the case the header already exists; `set` will replace it while `add` will append. +Agentgateway supports more than one configuration style. The following tabs show the same `requestHeaderModifier` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestHeaderModifier: + add: + x-req-added: value + remove: + - x-remove-me + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -35,10 +57,13 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="manipulation" >}} # WHAT THIS TEST VALIDATES: -# * The requestHeaderModifier example config is accepted by agentgateway. +# * The requestHeaderModifier example config is accepted by agentgateway in +# both the routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That headers are actually added/removed at runtime — requires a backend # the page omits to forward to and inspect. @@ -58,6 +83,24 @@ binds: - host: localhost:8080 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestHeaderModifier: + add: + x-req-added: value + remove: + - x-remove-me + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} More advanced operations are available with the [`transformation` policy](../transformations). diff --git a/content/docs/standalone/main/configuration/traffic-management/matching.md b/content/docs/standalone/main/configuration/traffic-management/matching.md index c3262e9bd..301117a01 100644 --- a/content/docs/standalone/main/configuration/traffic-management/matching.md +++ b/content/docs/standalone/main/configuration/traffic-management/matching.md @@ -10,6 +10,8 @@ test: Based on the route schema (see the [configuration reference]({{< link-hextra path="/reference/configuration/" >}}) for the full field reference and [schema validation]({{< link-hextra path="/reference/configuration/validation/" >}}) for IDE integration), you can configure the following {{< gloss "Matching" >}}matching{{< /gloss >}} conditions for HTTP or TCP routes. +Request matching is a routing-based feature: routes and their match conditions are configured under `binds`. The simplified `llm` configuration supports header-based model matching (`llm.models[].matches`), but path, method, and query matching require routing-based configuration. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + {{< doc-test paths="matching" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/traffic-management/redirects.md b/content/docs/standalone/main/configuration/traffic-management/redirects.md index 60e1f69de..170f62ea7 100644 --- a/content/docs/standalone/main/configuration/traffic-management/redirects.md +++ b/content/docs/standalone/main/configuration/traffic-management/redirects.md @@ -18,6 +18,30 @@ Request {{< gloss "Redirect" >}}redirects{{< /gloss >}} allow returning a direct For example, the following configuration will return a `307 Temporary Redirect` response with the header `location: https://example.com/new-path`: +Agentgateway supports more than one configuration style. The following tabs show the same `requestRedirect` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestRedirect: + scheme: https + authority: + full: example.com + path: + full: /new-path + status: 307 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -33,10 +57,13 @@ binds: full: /new-path status: 307 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="redirects" >}} # WHAT THIS TEST VALIDATES: -# * The requestRedirect example config is accepted by agentgateway. +# * The requestRedirect example config is accepted by agentgateway in both the +# routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That a 307 redirect is actually returned at runtime — requires sending a # request and inspecting the response, which the page does not demonstrate. @@ -56,4 +83,24 @@ binds: status: 307 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + requestRedirect: + scheme: https + authority: + full: example.com + path: + full: /new-path + status: 307 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/traffic-management/rewrites.md b/content/docs/standalone/main/configuration/traffic-management/rewrites.md index 6daabc24b..a5c7ee595 100644 --- a/content/docs/standalone/main/configuration/traffic-management/rewrites.md +++ b/content/docs/standalone/main/configuration/traffic-management/rewrites.md @@ -18,6 +18,28 @@ Modify URLs of incoming requests with {{< gloss "Rewrite" >}}rewrite{{< /gloss > For example, the following configuration modifies the request hostname to `example.com` and the request path to `/new-path`. +Agentgateway supports more than one configuration style. The following tabs show the same `urlRewrite` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + urlRewrite: + authority: + full: example.com + path: + full: /new-path + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -33,10 +55,13 @@ binds: backends: - host: example.com:443 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="rewrites" >}} # WHAT THIS TEST VALIDATES: -# * The urlRewrite example config is accepted by agentgateway. +# * The urlRewrite example config is accepted by agentgateway in both the +# routing-based (binds) and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the hostname/path are actually rewritten at runtime — requires a # backend the page omits to forward to and inspect. @@ -56,4 +81,22 @@ binds: - host: example.com:443 EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + urlRewrite: + authority: + full: example.com + path: + full: /new-path + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index cf3ee2a57..513736e60 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -38,6 +38,57 @@ To provide a specific string value, add your string in single quotes `'` followe Transform headers after route selection: +Agentgateway supports more than one configuration style. The following tabs show the same `transformations` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + add: + x-request-path: request.path + x-client-ip: source.address + response: + add: + x-response-code: 'string(response.code)' + remove: + - server + - x-content-type-options + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + add: + x-request-path: request.path + x-client-ip: source.address + response: + add: + x-response-code: 'string(response.code)' + remove: + - server + - x-content-type-options + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -71,10 +122,14 @@ binds: - server - x-content-type-options ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="transformations" >}} # WHAT THIS TEST VALIDATES: -# * The route-level header transformation example config is accepted by agentgateway. +# * The route-level header transformation example config is accepted by +# agentgateway in all three configuration forms: routing-based (binds), +# simplified LLM (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * Runtime header rewriting and the AI backend call — requires a live OpenAI # backend and a real API key the page omits. @@ -112,6 +167,53 @@ binds: - x-content-type-options EOF agentgateway -f config.yaml --validate-only + +cat <<'EOF' > config-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + add: + x-request-path: request.path + x-client-ip: source.address + response: + add: + x-response-code: 'string(response.code)' + remove: + - server + - x-content-type-options + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +EOF +agentgateway -f config-llm.yaml --validate-only + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + add: + x-request-path: request.path + x-client-ip: source.address + response: + add: + x-response-code: 'string(response.code)' + remove: + - server + - x-content-type-options + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} #### Listener-level header transformation From 0a4f8122815f0e279e99cee562974e0198a3d919 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 14:51:18 -0400 Subject: [PATCH 08/20] Added tabs Signed-off-by: Kristin Brown --- .../standalone/main/configuration/backends.md | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 9ea035d15..87d8f1811 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -19,7 +19,7 @@ export OPENAI_API_KEY="${OPENAI_API_KEY:-dummy}" ## Static Hosts -The simplest form of backend is a static hostname or IP address. For example: +The simplest form of backend is a static hostname or IP address. Static hosts are a routing-based backend, so they are configured under `binds`; the simplified `llm` and `mcp` modes model only LLM providers and MCP targets. For example: ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config @@ -148,6 +148,22 @@ agentgateway -f config2-simplified.yaml --validate-only By default, MCP backends use stateful session routing, where the gateway tracks session IDs and routes subsequent requests to the same upstream. For upstreams that do not maintain server-side session state, you can set `statefulMode: stateless`. In stateless mode, the gateway automatically wraps each request with an initialization sequence, so the upstream server processes every request independently. +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + statefulMode: stateless + targets: + - name: openapi-server + openapi: + host: petstore3.swagger.io:443 + schema: + url: https://petstore3.swagger.io/api/v3/openapi.json +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -164,10 +180,13 @@ binds: schema: url: https://petstore3.swagger.io/api/v3/openapi.json ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="backends" >}} # WHAT THIS TEST VALIDATES: -# * The stateless session-routing MCP backend example config is accepted by agentgateway. +# * The stateless session-routing MCP backend example is accepted by agentgateway +# in both the routing-based (binds) and simplified MCP (mcp) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That stateless wrapping actually occurs at runtime — requires the OpenAPI # upstream and live MCP traffic the page omits. @@ -188,6 +207,20 @@ binds: url: https://petstore3.swagger.io/api/v3/openapi.json EOF agentgateway -f config3.yaml --validate-only + +cat <<'EOF' > config3-simplified.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + statefulMode: stateless + targets: + - name: openapi-server + openapi: + host: petstore3.swagger.io:443 + schema: + url: https://petstore3.swagger.io/api/v3/openapi.json +EOF +agentgateway -f config3-simplified.yaml --validate-only {{< /doc-test >}} ## LLM Providers From 147b4c413272b46e9e29ff47054a0bdb7ccf24ae Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:09:25 -0400 Subject: [PATCH 09/20] Added tabs Signed-off-by: Kristin Brown --- .../configuration/resiliency/rate-limits.md | 222 +++++++++++++++++- .../configuration/security/apikey-authn.md | 106 ++++++++- .../main/configuration/security/jwt-authn.md | 97 +++++++- .../main/configuration/security/mcp-authn.md | 31 +++ .../main/configuration/security/mcp-authz.md | 50 ++++ .../main/configuration/security/oidc.md | 47 ++++ .../traffic-management/transformations.md | 164 ++++++++++++- 7 files changed, 709 insertions(+), 8 deletions(-) diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index d4b791b17..1b1be46ef 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -192,6 +192,57 @@ Local rate limiting uses a [Token bucket](https://en.wikipedia.org/wiki/Token_bu Below shows an example rate limit configuration that allows 5,000 tokens per hour, and 60 requests per second. +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -213,11 +264,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="rate-limits" >}} # WHAT THIS TEST VALIDATES: # * The Local example config (5000 tokens/hour and 60 requests/second) is -# accepted by agentgateway. +# accepted by agentgateway in the routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the token-bucket limits actually refill and throttle at runtime — # requires sustained traffic over the fill intervals, which the page omits. @@ -245,6 +299,53 @@ binds: - host: localhost:8080 EOF agentgateway -f config2.yaml --validate-only + +cat <<'EOF' > config2-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config2-llm.yaml --validate-only + +cat <<'EOF' > config2-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + localRateLimit: + - maxTokens: 5000 + # Every hour, refill 5000 tokens + tokensPerFill: 5000 + fillInterval: 1h + type: tokens + - maxTokens: 60 + # Every second, refill 1 token + tokensPerFill: 1 + fillInterval: 1s + type: requests + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config2-mcp.yaml --validate-only {{< /doc-test >}} > [!NOTE] @@ -256,6 +357,65 @@ Remote rate limits are not defined directly in agentgateway. Instead, agentgateway is configured to connect to an external rate limit server, and which "descriptors" to send to the server. The rate limit server is responsible for defining, and enforcing, the appropriate limits matching the descriptors. +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -281,11 +441,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="rate-limits" >}} # WHAT THIS TEST VALIDATES: # * The Remote example config (remoteRateLimit with descriptors) is accepted -# by agentgateway. +# by agentgateway in the routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies) forms. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That limits are actually enforced at runtime — requires an external Envoy # rate limit server the page omits to define and enforce the descriptors. @@ -317,6 +480,61 @@ binds: - host: localhost:8080 EOF agentgateway -f config3.yaml --validate-only + +cat <<'EOF' > config3-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config3-llm.yaml --validate-only + +cat <<'EOF' > config3-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + remoteRateLimit: + # The address to access the rate limit server + host: localhost:9090 + # Arbitrary 'domain' to match limits on the rate limit server + domain: example.com + descriptors: + # Rate limit requests based on a header, whether the user is authenticated, and a static value (used to match a specific rate limit rule on the rate limit server) + - entries: + - key: some-static-value + value: '"something"' + - key: organization + value: 'request.headers["x-organization"]' + - key: authenticated + value: 'has(jwt.sub)' + type: tokens # or 'requests' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config3-mcp.yaml --validate-only {{< /doc-test >}} Each descriptor value is a [CEL expression]({{< link-hextra path="/configuration/traffic-management/transformations" >}}). diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index 12273cdf3..01c74c27d 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -160,6 +160,57 @@ agentgateway -f config-mcp.yaml --validate-only Later policies can now operate on the metadata associated with the API key. For example, you can set a custom `x-authenticated-user` header with the authenticated user from the API key metadata by adding a route-level transformation. +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + transformations: + request: + set: + x-authenticated-user: apiKey.user + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + transformations: + request: + set: + x-authenticated-user: apiKey.user + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -182,11 +233,15 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="apikey-authn" >}} # WHAT THIS TEST VALIDATES: -# * The apiKey config combined with a route-level transformation that sets a -# header from API key metadata is accepted by agentgateway. +# * The apiKey config combined with a transformation that sets a header from +# API key metadata is accepted by agentgateway in all three configuration +# forms: routing-based (binds), simplified LLM (llm.policies), and simplified +# MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the x-authenticated-user header is actually set at runtime — # requires a backend the page omits to forward to and inspect. @@ -213,4 +268,51 @@ binds: - host: localhost:8080 EOF agentgateway -f config2.yaml --validate-only + +cat <<'EOF' > config2-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + transformations: + request: + set: + x-authenticated-user: apiKey.user + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config2-llm.yaml --validate-only + +cat <<'EOF' > config2-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + apiKey: + mode: strict + keys: + - key: sk-testkey-1 + metadata: + user: test + role: admin + transformations: + request: + set: + x-authenticated-user: apiKey.user + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config2-mcp.yaml --validate-only {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index 0030e14d0..caa0cc705 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -168,6 +168,53 @@ agentgateway -f config-mcp.yaml --validate-only It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. For example: +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -188,11 +235,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="jwt-authn" >}} # WHAT THIS TEST VALIDATES: -# * The jwtAuth + route-level authorization example config is accepted by -# agentgateway. +# * The jwtAuth + authorization example config is accepted by agentgateway in +# all three configuration forms: routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That the authorization rule actually allows/denies at runtime — requires # minting a signed JWT with the `admins` group and a backend the page omits. @@ -217,4 +267,47 @@ binds: - host: localhost:8080 EOF agentgateway -f config2.yaml --validate-only + +cat <<'EOF' > config2-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +EOF +agentgateway -f config2-llm.yaml --validate-only + +cat <<'EOF' > config2-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + jwtAuth: + mode: strict + issuer: agentgateway.dev + audiences: [test.agentgateway.dev] + jwks: + file: ./manifests/jwt/pub-key + authorization: + rules: + - allow: 'request.path == "/admin" && jwt.groups.contains("admins")' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config2-mcp.yaml --validate-only {{< /doc-test >}} \ No newline at end of file diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index 759c11cd9..b32e52b17 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -108,6 +108,35 @@ binds: Agentgateway acts solely as a resource server, validating tokens issued by an external authorization server. +The same `mcpAuthentication` policy is available in the simplified `mcp` form. + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + mcpAuthentication: + issuer: http://localhost:9000 + jwks: + url: http://localhost:9000/.well-known/jwks.json + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -140,6 +169,8 @@ binds: - body - query ``` +{{< /tab >}} +{{< /tabs >}} ## Authentication mode diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 7a3eac56d..4c62aa16d 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -23,6 +23,31 @@ Instead of running against an HTTP request, MCP authorization policies run again If a tool or other resource is not allowed, the gateway automatically filters it from the `list` response. +Agentgateway supports more than one configuration style. The following tabs show the same `mcpAuthorization` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). + +{{< tabs >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + policies: + mcpAuthorization: + rules: + # Allow anyone to call 'echo' + - 'mcp.tool.name == "echo"' + # Only the test-user can call 'add' + - 'jwt.sub == "test-user" && mcp.tool.name == "add"' + # Any authenticated user with the claim `nested.key == value` can access 'printEnv' + - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -46,11 +71,15 @@ binds: # Any authenticated user with the claim `nested.key == value` can access 'printEnv' - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="mcp-authz-config" >}} # WHAT THIS TEST VALIDATES: # * The MCP authorization example config loads and the gateway serves the # stdio MCP server: the /mcp endpoint accepts an initialize request. +# * The same policy is accepted in the simplified MCP (mcp) form via +# --validate-only. # WHAT THIS TEST DOES NOT VALIDATE (and why): # * That unauthorized tools are actually filtered — would require an # authenticated tools/list call with a JWT carrying the right claims. @@ -78,6 +107,27 @@ binds: # Any authenticated user with the claim `nested.key == value` can access 'printEnv' - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' EOF + +cat <<'EOF' > config-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + policies: + mcpAuthorization: + rules: + # Allow anyone to call 'echo' + - 'mcp.tool.name == "echo"' + # Only the test-user can call 'add' + - 'jwt.sub == "test-user" && mcp.tool.name == "add"' + # Any authenticated user with the claim `nested.key == value` can access 'printEnv' + - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"' +EOF +agentgateway -f config-mcp.yaml --validate-only {{< /doc-test >}} {{< doc-test paths="mcp-authz-config" >}} diff --git a/content/docs/standalone/main/configuration/security/oidc.md b/content/docs/standalone/main/configuration/security/oidc.md index 870671ef3..2e9de4b4a 100644 --- a/content/docs/standalone/main/configuration/security/oidc.md +++ b/content/docs/standalone/main/configuration/security/oidc.md @@ -129,6 +129,51 @@ binds: Review the following example for a Keycloak IdP. +The same `oidc` policy is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + oidc: + issuer: http://keycloak.example.com/realms/myrealm + clientId: agentgateway-browser + clientSecret: my-client-secret + redirectURI: http://localhost:3000/oauth/callback + scopes: + - profile + - email + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPENAI_API_KEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + oidc: + issuer: http://keycloak.example.com/realms/myrealm + clientId: agentgateway-browser + clientSecret: my-client-secret + redirectURI: http://localhost:3000/oauth/callback + scopes: + - profile + - email + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -150,6 +195,8 @@ binds: - profile - email ``` +{{< /tab >}} +{{< /tabs >}} ## Fields diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 513736e60..851052c0c 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -220,6 +220,43 @@ agentgateway -f config-mcp.yaml --validate-only Transform headers before route selection by attaching the policy at the listener level: +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + add: + x-gateway: '"agentgateway"' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + add: + x-gateway: '"agentgateway"' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -241,10 +278,14 @@ binds: openAI: model: gpt-3.5-turbo ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="transformations" >}} # WHAT THIS TEST VALIDATES: -# * The listener-level header transformation example config is accepted by agentgateway. +# * The listener-level header transformation example config is accepted by +# agentgateway in all three configuration forms: routing-based (binds), +# simplified LLM (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * Runtime header injection and the AI backend call — requires a live OpenAI # backend and a real API key the page omits. @@ -270,6 +311,39 @@ binds: model: gpt-3.5-turbo EOF agentgateway -f config2.yaml --validate-only + +cat <<'EOF' > config2-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + add: + x-gateway: '"agentgateway"' + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +EOF +agentgateway -f config2-llm.yaml --validate-only + +cat <<'EOF' > config2-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + add: + x-gateway: '"agentgateway"' + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config2-mcp.yaml --validate-only {{< /doc-test >}} ### Body transformation @@ -280,6 +354,49 @@ You can provide a custom body for a request or response. To provide a specific string value, add your string in single quotes `'` followed by double quotes `"`. This way, the string is interpreted as a string value. If you provide the value without quotes or with double quotes only, it is interpreted as a CEL expression. {{< /callout >}} +The same configuration is available in the simplified `llm` and `mcp` forms. + +{{< tabs >}} +{{< tab name="Simplified (LLM)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +``` +{{< /tab >}} +{{< tab name="Simplified (MCP)" >}} +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` +{{< /tab >}} +{{< tab name="Routing-based" >}} ```yaml # yaml-language-server: $schema=https://agentgateway.dev/schema/config binds: @@ -297,10 +414,14 @@ binds: backends: - host: localhost:8080 ``` +{{< /tab >}} +{{< /tabs >}} {{< doc-test paths="transformations" >}} # WHAT THIS TEST VALIDATES: -# * The body transformation example config is accepted by agentgateway. +# * The body transformation example config is accepted by agentgateway in all +# three configuration forms: routing-based (binds), simplified LLM +# (llm.policies), and simplified MCP (mcp.policies). # WHAT THIS TEST DOES NOT VALIDATE (and why): # * Runtime body rewriting — requires a backend the page omits to forward to # and inspect. @@ -322,6 +443,45 @@ binds: - host: localhost:8080 EOF agentgateway -f config3.yaml --validate-only + +cat <<'EOF' > config3-llm.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +llm: + policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + models: + - name: "*" + provider: openAI + params: + apiKey: "$OPEN_AI_APIKEY" +EOF +agentgateway -f config3-llm.yaml --validate-only + +cat <<'EOF' > config3-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + transformations: + request: + body: | + "Hello " + default(request.headers["x-user-name"], "guest") + response: + body: | + "Response code: " + string(response.code) + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f config3-mcp.yaml --validate-only {{< /doc-test >}} ## Conditional execution From 6b06442528c44ee306497ba62c13bbcb8f383ce5 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:12:46 -0400 Subject: [PATCH 10/20] Fixed audiences Signed-off-by: Kristin Brown --- .../docs/standalone/main/configuration/security/mcp-authn.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index b32e52b17..d1ed46107 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -39,6 +39,7 @@ mcp: policies: mcpAuthentication: issuer: http://localhost:7080/realms/mcp + audiences: ["http://localhost:3000/mcp"] jwks: url: http://localhost:7080/realms/mcp/protocol/openid-connect/certs provider: @@ -86,6 +87,7 @@ binds: policies: mcpAuthentication: issuer: http://localhost:7080/realms/mcp + audiences: ["http://localhost:3000/mcp"] jwks: url: http://localhost:7080/realms/mcp/protocol/openid-connect/certs provider: @@ -119,6 +121,7 @@ mcp: policies: mcpAuthentication: issuer: http://localhost:9000 + audiences: ["http://localhost:3000/mcp"] jwks: url: http://localhost:9000/.well-known/jwks.json resourceMetadata: @@ -158,6 +161,7 @@ binds: policies: mcpAuthentication: issuer: http://localhost:9000 + audiences: ["http://localhost:3000/mcp"] jwks: url: http://localhost:9000/.well-known/jwks.json resourceMetadata: @@ -189,6 +193,7 @@ policies: mcpAuthentication: mode: permissive issuer: http://localhost:9000 + audiences: ["http://localhost:3000/mcp"] jwks: url: http://localhost:9000/.well-known/jwks.json resourceMetadata: From d9084e627bf1cd72320bee9e6d3a3b20fe75429c Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:16:53 -0400 Subject: [PATCH 11/20] Added doc tests Signed-off-by: Kristin Brown --- .../main/configuration/security/mcp-authn.md | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index d1ed46107..cf5355ce2 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -2,6 +2,10 @@ title: MCP authentication weight: 30 description: Configure OAuth 2.0 protection for MCP servers with JWT validation. +test: + mcp-authn: + - file: content/docs/standalone/main/configuration/security/mcp-authn.md + path: mcp-authn --- Attaches to: {{< badge content="Route" path="/configuration/routes/">}} @@ -17,6 +21,19 @@ MCP authentication uses a connect-time model: the OAuth flow happens once when t There are three deployment scenarios. +{{< doc-test paths="mcp-authn" >}} +{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< /doc-test >}} + +{{< doc-test paths="mcp-authn" >}} +# Create the local JWKS file that the tests reference in place of the IdP URL, +# so they validate the policy structure without a live identity provider. +mkdir -p manifests/jwt +cat <<'EOF' > manifests/jwt/pub-key +{"keys": [{"kty": "RSA", "kid": "test", "use": "sig", "alg": "RS256", "n": "teXe4sfDoHQR5YUos3nsY_Ax6J2xrgXnIfUziaTWJ4nljejLVyg8m0g6SK9zrSaCvLm9GxAhpaJ_48RalwqDt4spBPQ8uvr-54jHrECboAbTxhy2T-oXP80Duz0xauSDVlyA_xenoCA24MFJ1rgHppy1F1eYTD-CQ-IxhXLNm5mE3rJufP_pdnMy0q6acXSfPtEzMJY3BYNV5umqimkOgH9PqQWd1RAgYdE7z5fvdCb4T4K667rRRT75PqRB4GJgSY-zQrC4CEVCw_ql7bfdouFcxXwsyh7AfImIEamA1LMODvMXVZWkZ8V0w_VEK6NHqr-BGOBVAUfRqYAEPxfaIw", "e": "AQAB"}]} +EOF +{{< /doc-test >}} + ## Authorization Server Proxy Agentgateway can adapt traffic for authorization servers that don't fully comply with OAuth standards. @@ -106,6 +123,91 @@ binds: {{< /tab >}} {{< /tabs >}} +{{< doc-test paths="mcp-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The Authorization Server Proxy mcpAuthentication example (issuer, audiences, +# keycloak provider, resourceMetadata, jwks) is accepted by agentgateway in +# both the simplified MCP (mcp) and routing-based (binds) forms. +# * The test points jwks at a local file instead of the displayed IdP URL so it +# runs without a live identity provider. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime token verification, the 401/WWW-Authenticate challenge, and the +# proxied authorization-server metadata — require a real IdP and a signed JWT +# the page does not stand up. +cat <<'EOF' > proxy-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + mcpAuthentication: + issuer: http://localhost:7080/realms/mcp + audiences: ["http://localhost:3000/mcp"] + jwks: + file: ./manifests/jwt/pub-key + provider: + keycloak: {} + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + resourceDocumentation: http://localhost:3000/stdio/docs + resourcePolicyUri: http://localhost:3000/stdio/policies + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f proxy-mcp.yaml --validate-only + +cat <<'EOF' > proxy-routing.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + matches: + - path: + exact: /mcp + - path: + exact: /.well-known/oauth-protected-resource/mcp + - path: + exact: /.well-known/oauth-authorization-server/mcp + - path: + exact: /.well-known/oauth-authorization-server/mcp/client-registration + policies: + mcpAuthentication: + issuer: http://localhost:7080/realms/mcp + audiences: ["http://localhost:3000/mcp"] + jwks: + file: ./manifests/jwt/pub-key + provider: + keycloak: {} + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + resourceDocumentation: http://localhost:3000/stdio/docs + resourcePolicyUri: http://localhost:3000/stdio/policies +EOF +agentgateway -f proxy-routing.yaml --validate-only +{{< /doc-test >}} + ## Resource Server Only Agentgateway acts solely as a resource server, validating tokens issued by an external authorization server. @@ -176,6 +278,80 @@ binds: {{< /tab >}} {{< /tabs >}} +{{< doc-test paths="mcp-authn" >}} +# WHAT THIS TEST VALIDATES: +# * The Resource Server Only mcpAuthentication example (issuer, audiences, jwks, +# resourceMetadata) is accepted by agentgateway in both the simplified MCP +# (mcp) and routing-based (binds) forms. +# * The test points jwks at a local file instead of the displayed IdP URL so it +# runs without a live identity provider. +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * Runtime token verification and the 401/WWW-Authenticate challenge — require +# a real authorization server and a signed JWT the page does not stand up. +# * The permissive-mode snippet below is a focused field-reference fragment, not +# a standalone config, so it is not tested here. +cat <<'EOF' > rsonly-mcp.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + policies: + mcpAuthentication: + issuer: http://localhost:9000 + audiences: ["http://localhost:3000/mcp"] + jwks: + file: ./manifests/jwt/pub-key + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +agentgateway -f rsonly-mcp.yaml --validate-only + +cat <<'EOF' > rsonly-routing.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +binds: +- port: 3000 + listeners: + - routes: + - backends: + - mcp: + targets: + - name: tools + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] + matches: + - path: + exact: /mcp + - path: + exact: /.well-known/oauth-protected-resource/mcp + policies: + mcpAuthentication: + issuer: http://localhost:9000 + audiences: ["http://localhost:3000/mcp"] + jwks: + file: ./manifests/jwt/pub-key + resourceMetadata: + resource: http://localhost:3000/mcp + scopesSupported: + - read:all + bearerMethodsSupported: + - header + - body + - query +EOF +agentgateway -f rsonly-routing.yaml --validate-only +{{< /doc-test >}} + ## Authentication mode You can control how agentgateway handles requests that lack valid credentials by setting the `mode` field. The following modes are supported: From e874b4198d3775e29198059bde6ad4bbaa031990 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:21:31 -0400 Subject: [PATCH 12/20] Updated Signed-off-by: Kristin Brown --- .github/workflows/doc-tests.yaml | 3 +++ .../agw-docs/snippets/install-agentgateway.md | 18 +++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/doc-tests.yaml b/.github/workflows/doc-tests.yaml index 73bc5e01c..1ea42c21b 100644 --- a/.github/workflows/doc-tests.yaml +++ b/.github/workflows/doc-tests.yaml @@ -140,6 +140,9 @@ jobs: DEBUG_MODE: true OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} PYTHONUNBUFFERED: '1' + # Used by the install-agentgateway snippet's `gh run download` of the + # nightly release-binary-linux artifact from agentgateway/agentgateway. + GH_TOKEN: ${{ github.token }} run: | FAILED=0 TEST_INDEX=0 diff --git a/assets/agw-docs/snippets/install-agentgateway.md b/assets/agw-docs/snippets/install-agentgateway.md index 48cc03921..65c239727 100644 --- a/assets/agw-docs/snippets/install-agentgateway.md +++ b/assets/agw-docs/snippets/install-agentgateway.md @@ -1,11 +1,11 @@ -# Install the agentgateway binary from the latest main (nightly) build. -# The nightly build publishes a container image tagged 'latest-dev'; extract the -# binary from that image. The GitHub release assets only exist for tagged -# releases, not for the in-development 'main' version. +# Install the agentgateway nightly build, following the documented "Nightly build" +# steps (https://agentgateway.dev/docs/standalone/latest/quickstart/llm/). CI runs +# on Linux, so this downloads the release-binary-linux artifact from the latest +# successful nightly workflow run. Requires an authenticated `gh` with read access +# to the agentgateway/agentgateway repo's Actions artifacts. +RUN_ID=$(gh run list -R agentgateway/agentgateway --workflow nightly.yml --status success --limit 1 --json databaseId --jq '.[0].databaseId') +gh run download "$RUN_ID" -R agentgateway/agentgateway -n release-binary-linux +chmod +x agentgateway mkdir -p "$HOME/.local/bin" export PATH="$HOME/.local/bin:$PATH" -docker rm -f agw-extract >/dev/null 2>&1 || true -docker create --name agw-extract cr.agentgateway.dev/agentgateway:latest-dev -docker cp agw-extract:/app/agentgateway "$HOME/.local/bin/agentgateway" -docker rm agw-extract -chmod +x "$HOME/.local/bin/agentgateway" +mv agentgateway "$HOME/.local/bin/agentgateway" From 4b29f438bde619adf4de655effae0c8082e54686 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:38:37 -0400 Subject: [PATCH 13/20] Added note Signed-off-by: Kristin Brown --- assets/agw-docs/snippets/config-styles-note.md | 3 +++ content/docs/standalone/main/configuration/backends.md | 6 ++---- .../standalone/main/configuration/resiliency/mirroring.md | 4 ++-- .../main/configuration/resiliency/rate-limits.md | 8 ++------ .../standalone/main/configuration/resiliency/retries.md | 4 ++-- .../standalone/main/configuration/resiliency/timeouts.md | 4 ++-- .../main/configuration/security/apikey-authn.md | 6 ++---- .../main/configuration/security/backend-authn.md | 4 ++-- .../standalone/main/configuration/security/backend-tls.md | 4 ++-- .../standalone/main/configuration/security/basic-authn.md | 4 ++-- .../docs/standalone/main/configuration/security/cors.md | 3 ++- .../docs/standalone/main/configuration/security/csrf.md | 4 ++-- .../main/configuration/security/external-authz.md | 5 ++--- .../standalone/main/configuration/security/http-authz.md | 4 ++-- .../standalone/main/configuration/security/jwt-authn.md | 6 ++---- .../standalone/main/configuration/security/mcp-authn.md | 6 ++---- .../standalone/main/configuration/security/mcp-authz.md | 4 ++-- .../docs/standalone/main/configuration/security/oidc.md | 6 ++---- .../configuration/traffic-management/direct-response.md | 4 ++-- .../main/configuration/traffic-management/manipulation.md | 4 ++-- .../main/configuration/traffic-management/redirects.md | 4 ++-- .../main/configuration/traffic-management/rewrites.md | 4 ++-- .../configuration/traffic-management/transformations.md | 8 ++------ 23 files changed, 47 insertions(+), 62 deletions(-) create mode 100644 assets/agw-docs/snippets/config-styles-note.md diff --git a/assets/agw-docs/snippets/config-styles-note.md b/assets/agw-docs/snippets/config-styles-note.md new file mode 100644 index 000000000..cc9f5a050 --- /dev/null +++ b/assets/agw-docs/snippets/config-styles-note.md @@ -0,0 +1,3 @@ +{{< callout type="info" >}} +Agentgateway supports more than one configuration style. Where a feature can also be configured in the simplified `llm` or `mcp` modes, the examples on this page show each option in tabs. For more information, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). +{{< /callout >}} diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 87d8f1811..214acbe62 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -12,6 +12,8 @@ test: Agentgateway {{< gloss "Backend" >}}backends{{< /gloss >}} control where traffic is routed to. Agentgateway supports a variety of backends, such as simple hostnames and IP addresses, {{< gloss "Provider" >}}LLM providers{{< /gloss >}}, and MCP servers. +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="backends" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export OPENAI_API_KEY="${OPENAI_API_KEY:-dummy}" @@ -63,8 +65,6 @@ The MCP backend allows you to connect to an MCP server. Below shows a simple example, exposing a local and remote MCP server. See the [MCP connectivity guide]({{< link-hextra path="/mcp/" >}}) for more information. -Agentgateway supports more than one configuration style. The following tabs show the same MCP targets in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml @@ -229,8 +229,6 @@ Agentgateway natively supports connecting to LLM providers, such as OpenAI and A Below shows a simple example, connecting to OpenAI. See the [LLM consumption guide]({{< link-hextra path="/llm/" >}}) for more information. -Agentgateway supports more than one configuration style. The following tabs show the same OpenAI provider in the routing-based form (`binds`) and in the simplified `llm` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index 8358e78b2..a906cc827 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="mirroring" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -17,8 +19,6 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alterative backend. These request will not be retried if they fail. -Agentgateway supports more than one configuration style. The following tabs show the same `requestMirror` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index 1b1be46ef..8f2dd9cac 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="rate-limits" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -36,8 +38,6 @@ By default, agentgateway applies rate limits to requests. Therefore, each reques To explicitly set request-based rate limits, set the rate limiting type to `requests` as shown in the following example. -Agentgateway supports more than one configuration style. The following tabs show the same `localRateLimit` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -192,8 +192,6 @@ Local rate limiting uses a [Token bucket](https://en.wikipedia.org/wiki/Token_bu Below shows an example rate limit configuration that allows 5,000 tokens per hour, and 60 requests per second. -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -357,8 +355,6 @@ Remote rate limits are not defined directly in agentgateway. Instead, agentgateway is configured to connect to an external rate limit server, and which "descriptors" to send to the server. The rate limit server is responsible for defining, and enforcing, the appropriate limits matching the descriptors. -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/resiliency/retries.md b/content/docs/standalone/main/configuration/resiliency/retries.md index fb2452441..6919f11b3 100644 --- a/content/docs/standalone/main/configuration/resiliency/retries.md +++ b/content/docs/standalone/main/configuration/resiliency/retries.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="retries" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -17,8 +19,6 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} When a backend request fails, agentgateway can be configured to *{{< gloss "Retry" >}}retry{{< /gloss >}}* the request. When a retry is attempted, a different backend will be preferred (if possible). -Agentgateway supports more than one configuration style. The following tabs show the same `retry` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index 3ddfb9c11..499adfb59 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="timeouts" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -25,8 +27,6 @@ You can configure two types of timeouts on a route. |`requestTimeout`|The time from the start of an incoming request, until the end of the response headers is received. Note if there are retries, this includes the total time across retries.| |`backendRequestTimeout`|The time from the start of a request to a backend, until the end of the response headers are completed. Note this is per-request, so with retries this is a per-retry timeout.| -Agentgateway supports more than one configuration style. The following tabs show the same `timeout` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index 01c74c27d..30cacb556 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="apikey-authn" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -28,8 +30,6 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This setting is useful for usage of claims in later steps such as authorization or logging. *Warning*: This allows requests without an API key! -Agentgateway supports more than one configuration style. The following tabs show the same `apiKey` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -160,8 +160,6 @@ agentgateway -f config-mcp.yaml --validate-only Later policies can now operate on the metadata associated with the API key. For example, you can set a custom `x-authenticated-user` header with the authenticated user from the API key metadata by adding a route-level transformation. -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index cbc11afd5..16610363b 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/" >}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="backend-authn" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export MY_API_KEY="${MY_API_KEY:-dummy}" @@ -19,8 +21,6 @@ When connecting to a backend, an authentication token can be attached to each re To attach a static key as an `Authorization` value, use `key`: -Agentgateway supports more than one configuration style. The following tabs show the same `backendAuth` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index 42dccb24b..3c9efa568 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="backend-tls" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -24,8 +26,6 @@ cp certs/cert.pem certs/root-cert.pem By default, requests to backends use HTTP. To use HTTPS, configure a backend {{< gloss "TLS (Transport Layer Security)" >}}TLS{{< /gloss >}} policy. -Agentgateway supports more than one configuration style. The following tabs show the same `backendTLS` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index 8d8276e00..d63e145f2 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="basic-authn" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -28,8 +30,6 @@ Additionally, authentication can run in two different modes: * **Optional** (default): If a username/password pair exists, validate it. *Warning*: This allows requests without a username/password pair! -Agentgateway supports more than one configuration style. The following tabs show the same `basicAuth` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/cors.md b/content/docs/standalone/main/configuration/security/cors.md index 68bbae16d..5160c0b70 100644 --- a/content/docs/standalone/main/configuration/security/cors.md +++ b/content/docs/standalone/main/configuration/security/cors.md @@ -6,6 +6,8 @@ description: Configure Cross-Origin Resource Sharing policies to control cross-d Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + ## About CORS {{< gloss "CORS (Cross-Origin Resource Sharing)" >}}Cross-origin resource sharing (CORS){{< /gloss >}} is a browser security mechanism which allows a server to control which origins can request and interact with resources that are hosted on a different domain. By default, web browsers only allow requests to resources that are hosted on the same domain as the web page that served the original request. Access to web pages or resources that are hosted on a different domain is restricted to prevent potential security vulnerabilities, such as cross-site request forgery (CRSF). @@ -48,7 +50,6 @@ CORS policies are typically implemented to limit access to server resources for > [!TIP] > Requests that violate the CORS policy will still have responses returned, but the browser will reject them. As such, usage of tools like `curl` with `cors` can be confusing, as `curl` does not respect CORS headers. -Agentgateway supports more than one configuration style. The following tabs show the same `cors` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). The same CORS fields are supported in every form: - `allowOrigins` - `allowMethods` - `allowHeaders` diff --git a/content/docs/standalone/main/configuration/security/csrf.md b/content/docs/standalone/main/configuration/security/csrf.md index bffb1244e..7f84aee65 100644 --- a/content/docs/standalone/main/configuration/security/csrf.md +++ b/content/docs/standalone/main/configuration/security/csrf.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="csrf" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -76,8 +78,6 @@ Blocked requests, which receive a `403 Forbidden` response with the message "CSR {{< reuse "agw-docs/snippets/review-configuration.md" >}} -Agentgateway supports more than one configuration style. The following tabs show the same `csrf` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index 0bd9e85bf..e19299943 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="external-authz" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -28,8 +30,6 @@ Agentgateway is API-compatible with the Envoy External Authorization gRPC servic When an ExtAuthz server returns header modifications, agentgateway uses `insert` instead of `append` for response headers. This ensures headers are properly set rather than potentially duplicated. -Agentgateway supports more than one configuration style. The following tabs show the same `extAuthz` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -243,7 +243,6 @@ For example, configure `redirect` to redirect users to a sign-in page, and `meta |`includeRequestBody.maxRequestBytes`|Maximum size of request body to buffer (default: 8192)| |`includeRequestBody.allowPartialMessage`|If true, send partial body when max_request_bytes is reached| - ## Backend connection policies You can configure connection policies on the `extAuthz` field to secure or tune how agentgateway connects to the external authorization service. This includes TLS, authentication, and connection timeouts. diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index a8646769e..4c4c205a3 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="http-authz" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -36,8 +38,6 @@ A CEL expression that cannot be evaluated is treated as `false`. For example, if - An `allow` expression that errors does not match, so it does not allow the request. {{< /callout >}} -Agentgateway supports more than one configuration style. The following tabs show the same `authorization` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index caa0cc705..8d5873ba1 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="jwt-authn" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -37,8 +39,6 @@ Additionally, authentication can run in three different modes: * **Permissive**: Requests are never rejected. This is useful for usage of claims in later steps (authorization, logging, etc). *Warning*: This allows requests without a JWT token! -Agentgateway supports more than one configuration style. The following tabs show the same `jwtAuth` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -168,8 +168,6 @@ agentgateway -f config-mcp.yaml --validate-only It is common to pair `jwtAuth` with `authorization`, using the `claims` from the verified JWT. For example: -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index cf5355ce2..09008a4e0 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + MCP authentication enables OAuth 2.0 protection for MCP servers, helping to implement the [MCP Authorization specification](https://modelcontextprotocol.io/specification/draft/basic/authorization). Agentgateway can act as a resource server, validating JWT tokens and exposing protected resource metadata. MCP authentication is configured at the route level under `policies.mcpAuthentication`. Because the policy runs at the route level, you can use JWT claims from MCP auth in other route-level policies, such as authorization, rate limiting, and transformations. @@ -45,8 +47,6 @@ In this mode, agentgateway: - Validates tokens using the authorization server's JWKS - Returns `401 Unauthorized` with appropriate `WWW-Authenticate` headers for unauthenticated requests -Agentgateway supports more than one configuration style. The following tabs show the same `mcpAuthentication` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml @@ -212,8 +212,6 @@ agentgateway -f proxy-routing.yaml --validate-only Agentgateway acts solely as a resource server, validating tokens issued by an external authorization server. -The same `mcpAuthentication` policy is available in the simplified `mcp` form. - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 4c62aa16d..28f6cac7a 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} (MCP Backends only) +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="mcp-authz-config" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -23,8 +25,6 @@ Instead of running against an HTTP request, MCP authorization policies run again If a tool or other resource is not allowed, the gateway automatically filters it from the `list` response. -Agentgateway supports more than one configuration style. The following tabs show the same `mcpAuthorization` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/security/oidc.md b/content/docs/standalone/main/configuration/security/oidc.md index 2e9de4b4a..7df75f686 100644 --- a/content/docs/standalone/main/configuration/security/oidc.md +++ b/content/docs/standalone/main/configuration/security/oidc.md @@ -6,6 +6,8 @@ description: Enable browser-based OpenID Connect authentication with encrypted s Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + OIDC browser authentication provides built-in OpenID Connect login for browser-based clients. Unauthenticated requests are automatically redirected to the identity provider's login page. After successful authentication, the user's session is maintained with encrypted cookies. The OIDC policy uses the OAuth 2.0 Authorization Code Flow with PKCE (Proof Key for Code Exchange) for secure browser-based authentication without requiring a separate proxy like oauth2-proxy. @@ -56,8 +58,6 @@ Review the following details about session management. Add the `oidc` policy to a route to protect it with browser-based OIDC authentication. -Agentgateway supports more than one configuration style. The following tabs show the same `oidc` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -129,8 +129,6 @@ binds: Review the following example for a Keycloak IdP. -The same `oidc` policy is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/traffic-management/direct-response.md b/content/docs/standalone/main/configuration/traffic-management/direct-response.md index bc3539e66..f33dd86d7 100644 --- a/content/docs/standalone/main/configuration/traffic-management/direct-response.md +++ b/content/docs/standalone/main/configuration/traffic-management/direct-response.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + Directly respond to a request with a custom response using {{< gloss "Direct Response" >}}direct response{{< /gloss >}}, without forwarding to any backend. {{< doc-test paths="direct-response" >}} @@ -24,8 +26,6 @@ Directly respond to a request with a custom response using {{< gloss "Direct Res For example, the following configuration returns a `404 Not found!` response. -Agentgateway supports more than one configuration style. The following tabs show the same `directResponse` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/traffic-management/manipulation.md b/content/docs/standalone/main/configuration/traffic-management/manipulation.md index 963d66cd7..e5a5e9a1e 100644 --- a/content/docs/standalone/main/configuration/traffic-management/manipulation.md +++ b/content/docs/standalone/main/configuration/traffic-management/manipulation.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="manipulation" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -20,8 +22,6 @@ The `requestHeaderModifier` and `responseHeaderModifier` modify request and resp These allow you to `add`, `set`, or `remove` headers. `add` and `set` differ in the case the header already exists; `set` will replace it while `add` will append. -Agentgateway supports more than one configuration style. The following tabs show the same `requestHeaderModifier` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/traffic-management/redirects.md b/content/docs/standalone/main/configuration/traffic-management/redirects.md index 170f62ea7..9d134397d 100644 --- a/content/docs/standalone/main/configuration/traffic-management/redirects.md +++ b/content/docs/standalone/main/configuration/traffic-management/redirects.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badge content="Backend" path="/configuration/backends/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="redirects" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -18,8 +20,6 @@ Request {{< gloss "Redirect" >}}redirects{{< /gloss >}} allow returning a direct For example, the following configuration will return a `307 Temporary Redirect` response with the header `location: https://example.com/new-path`: -Agentgateway supports more than one configuration style. The following tabs show the same `requestRedirect` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/traffic-management/rewrites.md b/content/docs/standalone/main/configuration/traffic-management/rewrites.md index a5c7ee595..ecc5522ee 100644 --- a/content/docs/standalone/main/configuration/traffic-management/rewrites.md +++ b/content/docs/standalone/main/configuration/traffic-management/rewrites.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="rewrites" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} @@ -18,8 +20,6 @@ Modify URLs of incoming requests with {{< gloss "Rewrite" >}}rewrite{{< /gloss > For example, the following configuration modifies the request hostname to `example.com` and the request path to `/new-path`. -Agentgateway supports more than one configuration style. The following tabs show the same `urlRewrite` policy in the routing-based form (`binds`) and in the simplified `mcp` form. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (MCP)" >}} ```yaml diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 851052c0c..88f37c6f2 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -10,6 +10,8 @@ test: Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{< badge content="Route" path="/configuration/routes/">}} +{{< reuse "agw-docs/snippets/config-styles-note.md" >}} + {{< doc-test paths="transformations" >}} {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} export OPEN_AI_APIKEY="${OPEN_AI_APIKEY:-dummy}" @@ -38,8 +40,6 @@ To provide a specific string value, add your string in single quotes `'` followe Transform headers after route selection: -Agentgateway supports more than one configuration style. The following tabs show the same `transformations` policy in the routing-based form (`binds`) and in the simplified `llm` and `mcp` forms. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -220,8 +220,6 @@ agentgateway -f config-mcp.yaml --validate-only Transform headers before route selection by attaching the policy at the listener level: -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml @@ -354,8 +352,6 @@ You can provide a custom body for a request or response. To provide a specific string value, add your string in single quotes `'` followed by double quotes `"`. This way, the string is interpreted as a string value. If you provide the value without quotes or with double quotes only, it is interpreted as a CEL expression. {{< /callout >}} -The same configuration is available in the simplified `llm` and `mcp` forms. - {{< tabs >}} {{< tab name="Simplified (LLM)" >}} ```yaml From 5a551a243589aa5898ddf200ee169ca44924decb Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Fri, 26 Jun 2026 15:46:55 -0400 Subject: [PATCH 14/20] Typos Signed-off-by: Kristin Brown --- .../standalone/main/configuration/resiliency/mirroring.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index a906cc827..40f1e952d 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -16,8 +16,8 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg {{< reuse "agw-docs/snippets/install-agentgateway.md" >}} {{< /doc-test >}} -Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alterative backend. -These request will not be retried if they fail. +Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alternative backend. +These requests will not be retried if they fail. {{< tabs >}} {{< tab name="Simplified (MCP)" >}} From 7e4ecb5f31a8fe32fa5858c532c474bad391d200 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 06:38:28 -0400 Subject: [PATCH 15/20] Update content/docs/standalone/main/configuration/resiliency/rate-limits.md Co-authored-by: Art Signed-off-by: Kristin Brown --- .../standalone/main/configuration/resiliency/rate-limits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index 8f2dd9cac..a716e458d 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -159,7 +159,7 @@ agentgateway -f config-mcp.yaml --validate-only For tokens, each token (prompt or completion) consumes 1 unit of capacity. Because the number of tokens that are used for the completion is not known at the time the request is sent, calculating the number of tokens can become tricky. To work around this issue, agentgateway checks token-based rate limits in two phases, at request time and at response time. -To enable token-based rate limiting, set the rate limiting type to `tokens`. This example shows only the route-level `localRateLimit` policy; attach it to a route as shown in the complete examples in the [Configuration](#configuration) section. +To enable token-based rate limiting, set the rate limiting type to `tokens`. This example shows only the `localRateLimit` policy; attach it to a route as shown in the complete examples in the [Configuration](#configuration) section. ```yaml localRateLimit: From 77a1952d12294e32caf311ce29c06e6d86658d56 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 07:48:50 -0400 Subject: [PATCH 16/20] Updated binary snippet Signed-off-by: Kristin Brown --- .github/workflows/doc-tests.yaml | 2 +- ...eway.md => install-agentgateway-binary.md} | 10 +++++++++ .../standalone/main/configuration/backends.md | 2 +- .../main/configuration/listeners.md | 2 +- .../configuration/resiliency/mirroring.md | 2 +- .../configuration/resiliency/rate-limits.md | 2 +- .../main/configuration/resiliency/retries.md | 2 +- .../main/configuration/resiliency/timeouts.md | 2 +- .../configuration/security/apikey-authn.md | 2 +- .../configuration/security/backend-authn.md | 2 +- .../configuration/security/backend-tls.md | 2 +- .../configuration/security/basic-authn.md | 2 +- .../main/configuration/security/csrf.md | 2 +- .../configuration/security/external-authz.md | 2 +- .../main/configuration/security/http-authz.md | 2 +- .../main/configuration/security/jwt-authn.md | 2 +- .../main/configuration/security/mcp-authn.md | 2 +- .../main/configuration/security/mcp-authz.md | 2 +- .../traffic-management/direct-response.md | 2 +- .../traffic-management/manipulation.md | 2 +- .../traffic-management/matching.md | 2 +- .../traffic-management/redirects.md | 2 +- .../traffic-management/rewrites.md | 2 +- .../traffic-management/transformations.md | 2 +- scripts/doc_test_extract.py | 22 +++++++++++++------ 25 files changed, 48 insertions(+), 30 deletions(-) rename assets/agw-docs/snippets/{install-agentgateway.md => install-agentgateway-binary.md} (59%) diff --git a/.github/workflows/doc-tests.yaml b/.github/workflows/doc-tests.yaml index 1ea42c21b..9cabd07c5 100644 --- a/.github/workflows/doc-tests.yaml +++ b/.github/workflows/doc-tests.yaml @@ -140,7 +140,7 @@ jobs: DEBUG_MODE: true OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} PYTHONUNBUFFERED: '1' - # Used by the install-agentgateway snippet's `gh run download` of the + # Used by the install-agentgateway-binary snippet's `gh run download` of the # nightly release-binary-linux artifact from agentgateway/agentgateway. GH_TOKEN: ${{ github.token }} run: | diff --git a/assets/agw-docs/snippets/install-agentgateway.md b/assets/agw-docs/snippets/install-agentgateway-binary.md similarity index 59% rename from assets/agw-docs/snippets/install-agentgateway.md rename to assets/agw-docs/snippets/install-agentgateway-binary.md index 65c239727..490cdf5c1 100644 --- a/assets/agw-docs/snippets/install-agentgateway.md +++ b/assets/agw-docs/snippets/install-agentgateway-binary.md @@ -1,3 +1,4 @@ +{{< version include-if="main" >}} # Install the agentgateway nightly build, following the documented "Nightly build" # steps (https://agentgateway.dev/docs/standalone/latest/quickstart/llm/). CI runs # on Linux, so this downloads the release-binary-linux artifact from the latest @@ -9,3 +10,12 @@ chmod +x agentgateway mkdir -p "$HOME/.local/bin" export PATH="$HOME/.local/bin:$PATH" mv agentgateway "$HOME/.local/bin/agentgateway" +{{< /version >}} +{{< version exclude-if="main" >}} +# Install the latest released agentgateway binary to local bin without sudo. +mkdir -p "$HOME/.local/bin" +export PATH="$HOME/.local/bin:$PATH" +BINARY_URL="https://github.com/agentgateway/agentgateway/releases/latest/download/agentgateway-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/')" +curl -sL "$BINARY_URL" -o "$HOME/.local/bin/agentgateway" +chmod +x "$HOME/.local/bin/agentgateway" +{{< /version >}} diff --git a/content/docs/standalone/main/configuration/backends.md b/content/docs/standalone/main/configuration/backends.md index 214acbe62..7131d9140 100644 --- a/content/docs/standalone/main/configuration/backends.md +++ b/content/docs/standalone/main/configuration/backends.md @@ -15,7 +15,7 @@ Agentgateway supports a variety of backends, such as simple hostnames and IP add {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="backends" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} export OPENAI_API_KEY="${OPENAI_API_KEY:-dummy}" {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/listeners.md b/content/docs/standalone/main/configuration/listeners.md index 7a66ffd1e..6d1dd0401 100644 --- a/content/docs/standalone/main/configuration/listeners.md +++ b/content/docs/standalone/main/configuration/listeners.md @@ -14,7 +14,7 @@ Agentgateway supports both {{< gloss "HTTP (Hypertext Transfer Protocol)" >}}HTT The following examples use routing-based configuration with `binds`. If you only route to LLM or MCP backends, the simplified `llm` and `mcp` modes set the listener port and TLS directly through `llm.port`, `llm.tls`, and `mcp.port`. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). {{< doc-test paths="listeners" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} {{< doc-test paths="listeners" >}} diff --git a/content/docs/standalone/main/configuration/resiliency/mirroring.md b/content/docs/standalone/main/configuration/resiliency/mirroring.md index 40f1e952d..4203c4f9d 100644 --- a/content/docs/standalone/main/configuration/resiliency/mirroring.md +++ b/content/docs/standalone/main/configuration/resiliency/mirroring.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="mirroring" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} Request {{< gloss "Mirroring" >}}mirroring{{< /gloss >}} allows sending a copy of each request to an alternative backend. diff --git a/content/docs/standalone/main/configuration/resiliency/rate-limits.md b/content/docs/standalone/main/configuration/resiliency/rate-limits.md index a716e458d..6b8951b7c 100644 --- a/content/docs/standalone/main/configuration/resiliency/rate-limits.md +++ b/content/docs/standalone/main/configuration/resiliency/rate-limits.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="rate-limits" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} Use rate limiting to enforce budget and spend limits per key: control the rate of requests and token usage on a route. Token-based limits let you cap usage per user, per API key, or per time window. Combined with API key authentication and observability, this gives you virtual key management. diff --git a/content/docs/standalone/main/configuration/resiliency/retries.md b/content/docs/standalone/main/configuration/resiliency/retries.md index 6919f11b3..6aa671a0c 100644 --- a/content/docs/standalone/main/configuration/resiliency/retries.md +++ b/content/docs/standalone/main/configuration/resiliency/retries.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="retries" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} When a backend request fails, agentgateway can be configured to *{{< gloss "Retry" >}}retry{{< /gloss >}}* the request. diff --git a/content/docs/standalone/main/configuration/resiliency/timeouts.md b/content/docs/standalone/main/configuration/resiliency/timeouts.md index 499adfb59..e7be6f2ec 100644 --- a/content/docs/standalone/main/configuration/resiliency/timeouts.md +++ b/content/docs/standalone/main/configuration/resiliency/timeouts.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="timeouts" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} Request {{< gloss "Timeout" >}}timeouts{{< /gloss >}} allow returning an error for requests that take too long to complete. diff --git a/content/docs/standalone/main/configuration/security/apikey-authn.md b/content/docs/standalone/main/configuration/security/apikey-authn.md index 30cacb556..1ae2a328f 100644 --- a/content/docs/standalone/main/configuration/security/apikey-authn.md +++ b/content/docs/standalone/main/configuration/security/apikey-authn.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{ {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="apikey-authn" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} {{< gloss "API Key" >}}API key{{< /gloss >}} {{< gloss "Authentication (AuthN)" >}}authentication{{< /gloss >}} enables authenticating requests based on a user-provided API key. diff --git a/content/docs/standalone/main/configuration/security/backend-authn.md b/content/docs/standalone/main/configuration/security/backend-authn.md index 16610363b..9c4f4ee1b 100644 --- a/content/docs/standalone/main/configuration/security/backend-authn.md +++ b/content/docs/standalone/main/configuration/security/backend-authn.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Backend" path="/configuration/backends/" >}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="backend-authn" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} export MY_API_KEY="${MY_API_KEY:-dummy}" {{< /doc-test >}} diff --git a/content/docs/standalone/main/configuration/security/backend-tls.md b/content/docs/standalone/main/configuration/security/backend-tls.md index 3c9efa568..06f7ed095 100644 --- a/content/docs/standalone/main/configuration/security/backend-tls.md +++ b/content/docs/standalone/main/configuration/security/backend-tls.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="backend-tls" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} {{< doc-test paths="backend-tls" >}} diff --git a/content/docs/standalone/main/configuration/security/basic-authn.md b/content/docs/standalone/main/configuration/security/basic-authn.md index d63e145f2..5e9c81ff2 100644 --- a/content/docs/standalone/main/configuration/security/basic-authn.md +++ b/content/docs/standalone/main/configuration/security/basic-authn.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{ {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="basic-authn" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} [Basic authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Authentication#basic_authentication_scheme) enables a simple username/password authentication mechanism. diff --git a/content/docs/standalone/main/configuration/security/csrf.md b/content/docs/standalone/main/configuration/security/csrf.md index 7f84aee65..0f0479df9 100644 --- a/content/docs/standalone/main/configuration/security/csrf.md +++ b/content/docs/standalone/main/configuration/security/csrf.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="csrf" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} ## About CSRF protection diff --git a/content/docs/standalone/main/configuration/security/external-authz.md b/content/docs/standalone/main/configuration/security/external-authz.md index e19299943..f1b3cca26 100644 --- a/content/docs/standalone/main/configuration/security/external-authz.md +++ b/content/docs/standalone/main/configuration/security/external-authz.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{ {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="external-authz" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} When {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} decisions need to be made out-of-process, use an external authorization policy. diff --git a/content/docs/standalone/main/configuration/security/http-authz.md b/content/docs/standalone/main/configuration/security/http-authz.md index 4c4c205a3..96199901f 100644 --- a/content/docs/standalone/main/configuration/security/http-authz.md +++ b/content/docs/standalone/main/configuration/security/http-authz.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="http-authz" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} HTTP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} allows defining rules to allow or deny requests based on their properties, using [CEL expressions]({{< link-hextra path="/reference/cel/" >}}). diff --git a/content/docs/standalone/main/configuration/security/jwt-authn.md b/content/docs/standalone/main/configuration/security/jwt-authn.md index 8d5873ba1..5ac65f0ac 100644 --- a/content/docs/standalone/main/configuration/security/jwt-authn.md +++ b/content/docs/standalone/main/configuration/security/jwt-authn.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{ {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="jwt-authn" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} {{< doc-test paths="jwt-authn" >}} diff --git a/content/docs/standalone/main/configuration/security/mcp-authn.md b/content/docs/standalone/main/configuration/security/mcp-authn.md index 09008a4e0..7a2418193 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authn.md +++ b/content/docs/standalone/main/configuration/security/mcp-authn.md @@ -24,7 +24,7 @@ MCP authentication uses a connect-time model: the OAuth flow happens once when t There are three deployment scenarios. {{< doc-test paths="mcp-authn" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} {{< doc-test paths="mcp-authn" >}} diff --git a/content/docs/standalone/main/configuration/security/mcp-authz.md b/content/docs/standalone/main/configuration/security/mcp-authz.md index 28f6cac7a..42df944f4 100644 --- a/content/docs/standalone/main/configuration/security/mcp-authz.md +++ b/content/docs/standalone/main/configuration/security/mcp-authz.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Backend" path="/configuration/backends/">}} (MCP {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="mcp-authz-config" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} The MCP {{< gloss "Authorization (AuthZ)" >}}authorization{{< /gloss >}} policy works similarly to [HTTP authorization]({{< link-hextra path="/configuration/security/http-authz" >}}), but runs in the context of an MCP request. diff --git a/content/docs/standalone/main/configuration/traffic-management/direct-response.md b/content/docs/standalone/main/configuration/traffic-management/direct-response.md index f33dd86d7..f1c0284f7 100644 --- a/content/docs/standalone/main/configuration/traffic-management/direct-response.md +++ b/content/docs/standalone/main/configuration/traffic-management/direct-response.md @@ -21,7 +21,7 @@ Directly respond to a request with a custom response using {{< gloss "Direct Res # WHAT THIS TEST DOES NOT VALIDATE (and why): # * The conditional-execution variant — requires config/traffic the page omits # (the `conditional` field is documented on a separate page). -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} For example, the following configuration returns a `404 Not found!` response. diff --git a/content/docs/standalone/main/configuration/traffic-management/manipulation.md b/content/docs/standalone/main/configuration/traffic-management/manipulation.md index e5a5e9a1e..975eca2bd 100644 --- a/content/docs/standalone/main/configuration/traffic-management/manipulation.md +++ b/content/docs/standalone/main/configuration/traffic-management/manipulation.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="manipulation" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} There are a few different policies that offer manipulation of HTTP requests and responses. diff --git a/content/docs/standalone/main/configuration/traffic-management/matching.md b/content/docs/standalone/main/configuration/traffic-management/matching.md index 301117a01..2bcf7751f 100644 --- a/content/docs/standalone/main/configuration/traffic-management/matching.md +++ b/content/docs/standalone/main/configuration/traffic-management/matching.md @@ -13,7 +13,7 @@ Based on the route schema (see the [configuration reference]({{< link-hextra pat Request matching is a routing-based feature: routes and their match conditions are configured under `binds`. The simplified `llm` configuration supports header-based model matching (`llm.models[].matches`), but path, method, and query matching require routing-based configuration. For more information about the configuration styles, see [Routing-based configuration]({{< link-hextra path="/llm/configuration-modes/" >}}). {{< doc-test paths="matching" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} ## HTTP routes diff --git a/content/docs/standalone/main/configuration/traffic-management/redirects.md b/content/docs/standalone/main/configuration/traffic-management/redirects.md index 9d134397d..ad64a44ac 100644 --- a/content/docs/standalone/main/configuration/traffic-management/redirects.md +++ b/content/docs/standalone/main/configuration/traffic-management/redirects.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< badg {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="redirects" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} Request {{< gloss "Redirect" >}}redirects{{< /gloss >}} allow returning a direct response redirecting users to another location. diff --git a/content/docs/standalone/main/configuration/traffic-management/rewrites.md b/content/docs/standalone/main/configuration/traffic-management/rewrites.md index ecc5522ee..95a8cd466 100644 --- a/content/docs/standalone/main/configuration/traffic-management/rewrites.md +++ b/content/docs/standalone/main/configuration/traffic-management/rewrites.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Route" path="/configuration/routes/">}} {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="rewrites" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} {{< /doc-test >}} Modify URLs of incoming requests with {{< gloss "Rewrite" >}}rewrite{{< /gloss >}} policies. diff --git a/content/docs/standalone/main/configuration/traffic-management/transformations.md b/content/docs/standalone/main/configuration/traffic-management/transformations.md index 88f37c6f2..ce3e252bd 100644 --- a/content/docs/standalone/main/configuration/traffic-management/transformations.md +++ b/content/docs/standalone/main/configuration/traffic-management/transformations.md @@ -13,7 +13,7 @@ Attaches to: {{< badge content="Listener" path="/configuration/listeners/">}} {{ {{< reuse "agw-docs/snippets/config-styles-note.md" >}} {{< doc-test paths="transformations" >}} -{{< reuse "agw-docs/snippets/install-agentgateway.md" >}} +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} export OPEN_AI_APIKEY="${OPEN_AI_APIKEY:-dummy}" {{< /doc-test >}} diff --git a/scripts/doc_test_extract.py b/scripts/doc_test_extract.py index 00a9cd904..42c0d11c1 100644 --- a/scripts/doc_test_extract.py +++ b/scripts/doc_test_extract.py @@ -137,14 +137,22 @@ def _evaluate_version_block(self, params: str) -> bool: kv = self._parse_shortcode_params(params) include_if = [x.strip() for x in kv.get("include-if", "").split(",") if x.strip()] exclude_if = [x.strip() for x in kv.get("exclude-if", "").split(",") if x.strip()] - # Use the resolved canonical version string (e.g. "2.2.x") so that - # include-if values in asset files match regardless of whether the - # context.version was supplied as a linkVersion token ("latest") or - # directly as a version string ("2.2.x"). - version = self._resolved_version - if include_if and version not in include_if: + # Identifiers that represent the current version. We accept both the + # canonical version string (e.g. "2.2.x") AND the stable linkVersion + # token (e.g. "main"/"latest"). This lets include-if/exclude-if target a + # directory by its release-stable name ("main") instead of the version + # number, which rotates every release. Matching the canonical string + # still works regardless of whether context.version was supplied as a + # linkVersion token or directly as a version string. Mirrors the + # linkVersion matching in the Hugo version.html shortcode. + identifiers = {self.version, self._resolved_version} + for link_ver, ver in self._link_version_map.items(): + if ver == self._resolved_version: + identifiers.add(link_ver) + identifiers.discard(None) + if include_if and not identifiers.intersection(include_if): return False - if exclude_if and version in exclude_if: + if exclude_if and identifiers.intersection(exclude_if): return False return True From 0eb660f424cd13147b601d8782586693bfe02a6c Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 08:03:34 -0400 Subject: [PATCH 17/20] Updated go mod version Signed-off-by: Kristin Brown --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 60535b53e..91195abdc 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/agentgateway/website go 1.21 -require github.com/solo-io/docs-theme-extras v0.1.8 // indirect +require github.com/solo-io/docs-theme-extras v0.1.11-beta.1 // indirect diff --git a/go.sum b/go.sum index 737379c68..ae129af95 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,5 @@ github.com/solo-io/docs-theme-extras v0.1.7 h1:2wE6L5B4gbnBxniff+ngpsZpEHynhxjZB github.com/solo-io/docs-theme-extras v0.1.7/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= github.com/solo-io/docs-theme-extras v0.1.8 h1:SgQEO5w81uHtEe1kqs2HMOdlEvopXun9H/w1nxf7Ed8= github.com/solo-io/docs-theme-extras v0.1.8/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= +github.com/solo-io/docs-theme-extras v0.1.11-beta.1 h1:/iSgrIjnSZniAubpZRn8bXi8nYAD4jKIzJRVlPO/eNs= +github.com/solo-io/docs-theme-extras v0.1.11-beta.1/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= From ccaced5caf5ea594cc1d013a9b1892ca64d232d5 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 08:15:43 -0400 Subject: [PATCH 18/20] Fixed main image Signed-off-by: Kristin Brown --- .../snippets/install-agentgateway-binary.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/assets/agw-docs/snippets/install-agentgateway-binary.md b/assets/agw-docs/snippets/install-agentgateway-binary.md index 490cdf5c1..c66b29ca6 100644 --- a/assets/agw-docs/snippets/install-agentgateway-binary.md +++ b/assets/agw-docs/snippets/install-agentgateway-binary.md @@ -1,15 +1,15 @@ {{< version include-if="main" >}} -# Install the agentgateway nightly build, following the documented "Nightly build" -# steps (https://agentgateway.dev/docs/standalone/latest/quickstart/llm/). CI runs -# on Linux, so this downloads the release-binary-linux artifact from the latest -# successful nightly workflow run. Requires an authenticated `gh` with read access -# to the agentgateway/agentgateway repo's Actions artifacts. -RUN_ID=$(gh run list -R agentgateway/agentgateway --workflow nightly.yml --status success --limit 1 --json databaseId --jq '.[0].databaseId') -gh run download "$RUN_ID" -R agentgateway/agentgateway -n release-binary-linux -chmod +x agentgateway +# Install the agentgateway binary from the latest main (nightly) build. +# The nightly build publishes a container image tagged 'latest-dev'; extract the +# binary from that image. The GitHub release assets only exist for tagged +# releases, not for the in-development 'main' version. mkdir -p "$HOME/.local/bin" export PATH="$HOME/.local/bin:$PATH" -mv agentgateway "$HOME/.local/bin/agentgateway" +docker rm -f agw-extract >/dev/null 2>&1 || true +docker create --name agw-extract cr.agentgateway.dev/agentgateway:latest-dev +docker cp agw-extract:/app/agentgateway "$HOME/.local/bin/agentgateway" +docker rm agw-extract +chmod +x "$HOME/.local/bin/agentgateway" {{< /version >}} {{< version exclude-if="main" >}} # Install the latest released agentgateway binary to local bin without sudo. From 508b7fd7c556fc697783538d97c9237d8942dc36 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 09:26:23 -0400 Subject: [PATCH 19/20] Update docs-theme-extras version to v0.1.11 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 91195abdc..437631374 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/agentgateway/website go 1.21 -require github.com/solo-io/docs-theme-extras v0.1.11-beta.1 // indirect +require github.com/solo-io/docs-theme-extras v0.1.11 // indirect From b4f1f80a59a95fabb9b42b8767ecea2feb611d23 Mon Sep 17 00:00:00 2001 From: Kristin Brown Date: Mon, 29 Jun 2026 09:26:51 -0400 Subject: [PATCH 20/20] Update go.sum for docs-theme-extras version changes --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index ae129af95..6f90c2a3a 100644 --- a/go.sum +++ b/go.sum @@ -2,5 +2,5 @@ github.com/solo-io/docs-theme-extras v0.1.7 h1:2wE6L5B4gbnBxniff+ngpsZpEHynhxjZB github.com/solo-io/docs-theme-extras v0.1.7/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= github.com/solo-io/docs-theme-extras v0.1.8 h1:SgQEO5w81uHtEe1kqs2HMOdlEvopXun9H/w1nxf7Ed8= github.com/solo-io/docs-theme-extras v0.1.8/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= -github.com/solo-io/docs-theme-extras v0.1.11-beta.1 h1:/iSgrIjnSZniAubpZRn8bXi8nYAD4jKIzJRVlPO/eNs= -github.com/solo-io/docs-theme-extras v0.1.11-beta.1/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg= +github.com/solo-io/docs-theme-extras v0.1.11 h1:haOkSK1fHxd3sQ3F4t3WPI+34KbZcbpheEcvXBdrt8c= +github.com/solo-io/docs-theme-extras v0.1.11/go.mod h1:jjjYu/QoD+vMu30zgcpfEuTEGuJOJWs5qai/K18kltg=