跳到主要内容

上游身份认证

每个已注册的 Agent-to-Agent(A2A)Agent 都定义了 AISIX 是否以及如何向其上游进行身份认证。在获取 Agent Card 或转发 JSON-RPC 调用时,AISIX 会提供已配置的凭证(如有)。客户端使用调用方 API Key 向 AISIX 进行身份认证,默认情况下没有任何调用方请求头会到达该 Agent。需要看到某个请求头的 Agent(包括调用方自己的凭证),通过 forward_client_headers 显式开启。

这种分离方式让每个上游可以采用所需的身份认证方案,而调用方只需保留一个 AISIX 凭证。AISIX Cloud 和开源 AISIX 网关通过不同管理方式支持相同的模式。

前置条件

请完成 AISIX Cloud 或开源 AISIX 网关的配置 Agent 网关。如需执行可选的端到端验证,请保持同一个 Shell、网关、测试 Agent 和临时 Docker 网络运行。

身份认证模式

请选择与上游 Agent 要求相符的模式:

auth_type必填字段上游请求头
none不发送凭证。
bearersecretAuthorization: Bearer <secret>
api_keysecretx-api-key: <secret>

auth_type 默认为 none。在此模式下,不要设置 secretbearerapi_key 模式要求提供非空 secret

使用凭证的上游应采用 HTTPS。如果为 http:// URL 配置了 Bearer Token 或 API Key,网关会记录警告,因为凭证将以明文通过网络传输。

配置上游身份认证

以下示例为配置指南中已注册的 echo-agent 添加 Bearer 身份认证。将该条目改为指向需要凭证的上游时,还应替换它的 URL。如果上游要求 x-api-key,请改用 api_key。echo Agent 本身不验证凭证。如需在本地测试凭证转发,请跳过这些示例,继续阅读可选:使用本地测试代理验证;该部分会提供专用 Token 和最终资源更新。

AISIX Cloud

导出凭证,然后更新已注册 Agent:

export A2A_AGENT_TOKEN="YOUR_UPSTREAM_TOKEN"

curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF | jq
{
"auth_type": "bearer",
"secret": "${A2A_AGENT_TOKEN}"
}
EOF

该凭证为只写字段:AISIX Cloud 会对其进行静态加密,并且不会在创建、列表或更新响应中返回。发送新的 secret 会轮换凭证。从使用凭证的模式改为 none 会清除已存储的凭证。

开源 AISIX 网关

a2a_agents 中现有的 echo-agent 条目替换为以下更新后的条目。该条目引用网关环境变量。保留无关的 Agent 和集合:

resources.yaml(Agent 身份认证)
a2a_agents:
- name: echo-agent
url: http://aisix-a2a-echo:8080
protocol_version: "1.0"
auth_type: bearer
secret: ${A2A_AGENT_TOKEN}

加载文件前,请在网关进程环境中设置 A2A_AGENT_TOKEN。如果被引用的变量未设置或为空,验证将失败。如果该变量已存在于运行中的容器内,请验证完整文件并发送 SIGHUP

docker exec aisix-quickstart \
aisix validate --resources /etc/aisix/resources.yaml

docker kill --signal HUP aisix-quickstart

新增或修改容器环境变量时,需要使用新值重新创建该容器。有关验证和重新创建流程,请参阅重新加载资源文件

凭证失败

上游凭证绝不会传递给调用客户端。AISIX 提供的 Agent Card 包含上游 Agent 的元数据,并会将服务 URL 重写为网关路径,但不会包含已配置的凭证。

如果上游拒绝已过期、已轮换或已撤销的凭证,只有对该 Agent 的调用会失败。AISIX 返回 HTTP 502;上游状态会出现在 JSON-RPC 错误消息中,但上游响应正文不会代理给调用方。

向上游 Agent 转发调用方请求头

上面那份凭证属于网关。而按最终用户授权的内网 Agent 需要的是调用方自己的请求头,forward_client_headers 就是它获得该请求头的途径。它是一个请求头名称模式数组,默认为空,两种管理路径都支持。它对 /a2a/<name>/.well-known/agent-card.json 上的 Agent Card 拉取,以及 /a2a/<name> 上的每个 JSON-RPC 方法都生效,因此 message/sendmessage/stream 和各类 task 操作都会收到这些请求头。

通过 AISIX Cloud Admin API,可以在创建 Agent 时设置,也可以之后 PATCH。PATCH 是整体替换已存储的列表;传空数组即清空:

curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"forward_client_headers": ["authorization", "x-trace-*"]
}'

在控制台中,同一设置是 Agent 表单里 Advanced 下的 Forward client headers 输入框,每行填一个请求头名称或通配符。

在开源 AISIX 网关加载的资源文件中:

resources.yaml(把调用方凭证转发给内网 Agent)
a2a_agents:
- name: invoice-processor
url: https://agents.internal.example.com/a2a
auth_type: none
forward_client_headers:
- authorization
- x-trace-*

每个条目可以是精确的请求头名称,也可以是包含一个 * 通配符的名称,匹配不区分大小写。被转发的请求头会到达该 Agent,无论 AISIX 本来打算怎么处理它。

点名一个凭证槽位,会把调用方的凭证取代网关的凭证交给该 Agent,绝不会两个都发。bearer 填的槽位是 authorizationapi_key 填的槽位是 x-api-key。这正是让本就按最终用户 Authorization 授权的内网 Agent,在 AISIX 接入之后继续原样工作的方式。校验 aud 声明的 Agent 会拒绝签发给网关的 Token,因此只在你愿意把调用方取值托付给它的 Agent 上点名槽位。

凭证槽位以及链路上下文请求头 traceparenttracestate,只有在模式精确点名时才会转发。*x-* 这类通配符永远匹配不到它们,因为转发凭证或链路上下文是一个明确的动作,而不该被宽泛模式顺带扫进来。完整清单见必须精确点名的请求头,各个面上这个集合是一样的。

a2a-version 绝不会被转发。它是 AISIX 自己就该 Agent 在 protocol_version 中所固定的线格式版本做出的声明,调用方的副本会覆盖这个固定值。其余任何模式都触及不到的名称——host、逐跳请求头、x-aisix-* 命名空间,以及描述 AISIX 会重新序列化的请求体的那些请求头——列在 AISIX 绝不转发的调用方请求头中。

转发功能要求数据面运行 1.1.0 或更高版本。在更旧的网关上保存该字段时,AISIX Cloud 会给出提示;该网关仍会继续提供这个 Agent,只是不会额外中继任何请求头。

可选:使用本地测试代理验证

以上配置定义了 AISIX 应发送的凭证,但配置指南中的 echo Agent 不进行身份认证也会接受请求,因此无法证明网关提供了预期的 Token。如需进行本地端到端检查,请在 Agent 前放置一个使用 Bearer 身份认证的小型反向代理,并分别验证请求被接受和拒绝的情况。

该代理仅用于本地测试:它使用明文 HTTP,并会在转发已接受的请求到 echo Agent 前移除 Bearer Token。

以下辅助函数包含本地代理配置。请原样复制;后续步骤会配置和测试 AISIX。

启动本地 Bearer Token 验证代理

导出独立的上游 Token,然后在现有 Docker 网络上定义并启动测试代理:

export A2A_AGENT_TOKEN="a2a-upstream-test-token"

start_a2a_auth_proxy() {
docker rm -f aisix-a2a-auth >/dev/null 2>&1 || true
docker run -d --name aisix-a2a-auth \
--network aisix-a2a \
-e UPSTREAM_TOKEN="$1" \
caddy:2.11.4-alpine \
sh -c 'caddy run --config /dev/stdin --adapter caddyfile <<EOF
:8082 {
@authorized header Authorization "Bearer $UPSTREAM_TOKEN"
handle @authorized {
reverse_proxy aisix-a2a-echo:8080 {
header_up -Authorization
header_up Host {upstream_hostport}
}
}
handle {
respond "upstream authentication failed" 401
}
}
EOF'

for attempt in $(seq 1 30); do
docker logs aisix-a2a-auth 2>&1 |
grep -q "serving initial configuration" && return
sleep 1
done
docker logs aisix-a2a-auth >&2
return 1
}

start_a2a_auth_proxy "$A2A_AGENT_TOKEN"

配置 AISIX 使用代理

更新现有 echo-agent,使其使用 http://aisix-a2a-auth:8082、Bearer 身份认证,并将 A2A_AGENT_TOKEN 作为密钥。

对于 AISIX Cloud,请更新配置指南中创建的 Agent:

curl -fsS -X PATCH "$AISIX_CP/a2a_agents/$A2A_AGENT_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF | jq
{
"url": "http://aisix-a2a-auth:8082",
"auth_type": "bearer",
"secret": "${A2A_AGENT_TOKEN}"
}
EOF

对于开源 AISIX 网关,请替换现有 echo-agent 条目,并保留其他资源:

resources.yaml(已认证的 echo Agent)
a2a_agents:
- name: echo-agent
url: http://aisix-a2a-auth:8082
protocol_version: "1.0"
auth_type: bearer
secret: ${A2A_AGENT_TOKEN}

A2A_AGENT_TOKEN 添加到网关容器环境中。由于配置指南启动容器时没有提供该变量,请在设置了该变量的环境中验证完整文件,并使用同一个值重新创建容器。保留快速入门中的挂载、端口和其他环境变量。请参阅重新加载资源文件

对于开源路径,重新创建网关容器会将其与临时 A2A 网络断开。发送测试请求前,请连接替换后的容器:

docker network connect aisix-a2a "$AISIX_GATEWAY_CONTAINER"

验证有效凭证

AISIX Cloud 投射更新或开源网关重启后,向 Agent 发送请求:

A2A_RESPONSE=$(curl -fsS -X POST "$AISIX_PROXY/a2a/echo-agent" \
-H "Authorization: Bearer $AISIX_A2A_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "req-auth",
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-auth",
"role": "ROLE_USER",
"parts": [{"text": "Authenticated through AISIX"}]
}
}
}')

echo "$A2A_RESPONSE" | jq -e \
'.result.task.artifacts[].parts[] |
select(.text == "Authenticated through AISIX")'

该命令会打印匹配的文本部分。代理只接受携带网关所持 Token 的请求,因此该响应确认 AISIX 已将调用方的 Authorization 请求头替换为上游凭证。这是默认行为,forward_client_headers 改变的正是这一点。代理会在转发到 echo Agent 前移除该凭证。

验证被拒绝的凭证

让代理期待另一个 Token,但不更改 AISIX 中的凭证:

start_a2a_auth_proxy "deliberately-wrong-token"

curl -sS -o /tmp/aisix-a2a-auth-failure.json -w "%{http_code}\n" \
-X POST "$AISIX_PROXY/a2a/echo-agent" \
-H "Authorization: Bearer $AISIX_A2A_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "req-wrong-auth",
"method": "SendMessage",
"params": {
"message": {
"messageId": "msg-wrong-auth",
"role": "ROLE_USER",
"parts": [{"text": "This call should fail"}]
}
}
}'

jq -e \
'.error.code == -32000 and
.error.message == "upstream A2A request failed: upstream returned HTTP 401"' \
/tmp/aisix-a2a-auth-failure.json

if grep -qF "$A2A_AGENT_TOKEN" /tmp/aisix-a2a-auth-failure.json || \
grep -qF "$AISIX_A2A_KEY" /tmp/aisix-a2a-auth-failure.json; then
echo "credential found in client response" >&2
exit 1
fi

该请求会打印 HTTP 502jq 命令会打印 true,凭证检查不会产生输出。AISIX 会在 JSON-RPC 错误中包含上游状态,但不会代理上游响应正文。

恢复预期 Token,并移除临时响应文件:

start_a2a_auth_proxy "$A2A_AGENT_TOKEN"
rm /tmp/aisix-a2a-auth-failure.json

使用该本地身份认证配置时,请保持 aisix-a2a-auth 运行。在执行配置指南中的清理命令前移除它:

docker rm -f aisix-a2a-auth

后续步骤

你已配置 AISIX 如何向上游 Agent 进行身份认证。可以继续阅读以下指南,控制调用方和流量:

  • 控制 Agent 访问权限:将调用方 API Key 的权限范围限定为特定 Agent 或模式。
  • 限流和预算:应用请求和并发限制,并使用 AISIX Cloud 预算。
  • 可观测性:查看 A2A 调用生成的用量事件和指标。
  • 上游请求头:同一个 forward_client_headers 字段在 AISIX 其他代理面上的用法,以及任何模式都无法触及的完整请求头清单。