把 AI Agent 的身份挂到 DNS 上:ANS 的 _ans 记录、SCITT 回执与离线校验
Agent Name Service(ANS)把 AI Agent 绑到一个域名上,让它的身份可以通过 DNS 被发现和验证。注册后的 agent 会拿到一份带版本号的 DNS 风格名字,例如 ans://v1.0.0.my-agent.example.com,并附带一串可公开审计的记录:append-only 的 Merkle 事件日志、证明某个时间点状态的 SCITT COSE_Sign1 回执、用于 agent 间 mTLS 的私有 CA 身份证书,以及可选的 BYOC 服务器证书和固定 TLSA 记录。
- 规范与组织:
- Go 参考实现:
- 机制说明:
- IETF draft:
- 论文:
为什么 agent card 需要一层命名
Agent 的自描述文档(agent card,JSON,含名字、版本、能力、endpoints)本身可以托管在任意 URL,按约定放在 /.well-known/agent-card.json。问题是名字、身份、证书之间没有绑定:一个 agent 声称自己是谁,没有可核验的锚点。
ANS 的做法是不引入专有命名空间,直接锚定域名。注册流程是:创建 agent card 并托管在 /.well-known/agent-card.json;在 _ans 与 _ans-badge 标签下发布 TXT 记录;为 DANE 添加 TLSA 记录;Silver/Gold 层级需要启用 DNSSEC;最后调用 ANS registry API 把注册封存进 Transparency Log,拿到密码学包含证明。
发现路径有三条:DNS 查询(_ans TXT 给出 agent card URL)、MCP server 集成(按能力查询 agent)、Trust Index API。
三个信任层级
| 层级 | 组成 | 校验内容 |
|---|---|---|
| Bronze | PKI | 域名持有有效 TLS 证书,检查证书链、有效期、吊销状态 |
| Silver | PKI + DANE | 证书指纹必须匹配 TLSA DNS 记录,依赖 DNSSEC |
| Gold | PKI + DANE + Transparency Log | 注册被封存,且带有有效的包含证明 |
DNS 记录长什么样
Phase 1(当前)用 TXT,任何 DNS 提供商都能用:
_ans.joes-barber.com IN TXT "v=ans1; version=v1.0; ..."
_ans-badge.joes-barber.com IN TXT "v=ans-badge1; version=v1.0.0; url=https://tl.godaddy.com/v1/agents/abc123"
_ans-identity._tls.joes-barber.com IN TLSA 3 0 1
Phase 2 走标准轨道:GoDaddy、Infoblox、agentcommunity.org 等正在收敛到 _ag 标签下的共享 SVCB 记录,每个协议一条记录。SVCB 行里携带的 descriptor URL 对应 key 65400,验证时会用到(见下文第 8 步)。Linux Foundation 已宣布有意在 2026 年 6 月将 ANS 作为开放标准推出,支持 DIDs 与 LEIs。
参考实现怎么跑
四个二进制:
| Binary | Port | 角色 |
|---|---|---|
ans-ra | 18080 | Registration Authority:接收注册、签发身份证书、跟踪生命周期 |
ans-tl | 18081 | Transparency Log:持久化 Merkle append 日志,提供 badge 与回执 |
ans-verify | — | 离线 CLI 校验器,校验 SCITT COSE 回执与状态令牌 |
ans-dns | 15353 | 仅开发用的权威 DNS 服务,带 install / clear 子命令做本地端到端 verify-dns 测试 |
两个 daemon 都在 /docs 暴露 Swagger UI,规格在 spec/api-spec-v2.yaml 与 spec/api-spec-tl-v2.yaml。RA 写入签名事件,TL 验证、摄取并发布。只跑 TL 可以做只读验证,两个都跑才是完整 registry。RA quickstart 静态 key 为 ans-dev-key-change-me,TL 为 tl-internal-key。
# 依赖:Go 1.26+、openssl、curl、jq
git clone https://github.com/agentnameservice/ans
cd ans
make build # bin/ans-ra, bin/ans-tl, bin/ans-verify, bin/ans-dns
scripts/demo/start.sh
scripts/demo/run-lifecycle.sh # 注册 agent 并端到端验证回执
预期输出:离线校验(bin/ans-verify)打印 Fetched 2 verification key(s) from /root-keys、VERIFIED (kid matched key directly)。清理用 scripts/demo/stop.sh [--clean]。
config/ra-local.yaml 里默认的 DNS 校验器是 noop(接受任意 DNS 状态)。要在不碰公网 DNS 的前提下跑真实查询校验:
bin/ans-dns serve --addr 127.0.0.1:15353
bin/ans-dns install --api-key http://localhost:18080
然后把 ra-local.yaml 改成 dns.type=lookup 并指向 127.0.0.1:15353,重跑 verify-dns,ans-tl 会观察到 AGENT_REGISTERED。清理用 bin/ans-dns clear 。
Docker 方式:make docker-build 后 docker compose up --build(RA + TL,带 healthcheck),持久化 ra-data、ra-keys、tl-data 三个 volume;docker compose down -v 会清空它们。ans-verify 和 ans-dns 是本地开发二进制,不在 compose 里。
配置由 koanf 读 YAML:config/ra-local.yaml、config/tl-local.yaml、config/ra-docker.yaml、config/tl-docker.yaml。每个 YAML key 都能用环境变量覆盖,规则是 _ 转 . 的点号形式,例如 ANS_RA_SERVER__PORT=18090。
鉴权方面,静态 API key(quickstart 用)同时接受 Authorization: Bearer 和 Authorization: sso-key :,静态 key 视为 admin。OIDC 走标准 bearer-token 校验,admin 组由 auth.oidc.admin-groups[] 指定。当 auth.public-read: true(TL quickstart 默认)时,/v1/agents/、/v1/log/ 下的所有 GET 以及 tlog-tiles 路径(/checkpoint、/root-keys、/tile/*)都是匿名的,校验方不需要凭据。
核心契约
线格式就是公开契约,离线校验器和 TL 客户端逐字节依赖它。
事件信封(RA 侧签名):
{"payload":{"logId":"","producer":{"event":{"ansId":"...","ansName":"ans://...","eventType":"AGENT_REGISTRATION",...},"keyId":"ans-ra-signer","signature":""}},"schemaVersion":"V1","signature":"","status":"ACTIVE"}
回执是 SCITT COSE_Sign1(RFC 8152 tag 18):
- Protected header:
{1:-7 (ES256), 4:, 395:1 (RFC 9162), 15:{1:, 6:}} - Unprotected header:
{396:{-1:treeSize, -2:leafIndex, -3:path[][], -4:rootHash}} - Payload:JCS 规范化后的事件字节,与计算 leaf hash 用的是同一份字节
- Signature:ES256,签在 RFC 8152 §4.4 的 Sig_structure 上
Leaf hash 按 RFC 6962 计算:SHA-256(0x00 || payload)。
GET /root-keys 输出 sumdb-note 格式的验证公钥,一行一个:
++
其中 keyhash-hex 是 SHA-256(SPKI-DER) 的前 4 字节,按零填充的大端十六进制表示。校验器拿它和回执保护头里的 kid 做匹配,实现 O(1) 公钥查找。TL 用单一 ECDSA P-256 key 签所有出站产物(checkpoint、attestation、回执、状态令牌),因此 /root-keys 只会宣告一行。
校验工作流:
ans-verify -url https://tl.example.com -agent
# 气隙环境
ans-verify -pubkey ./trusted-tl.pub -agent -url file://./receipt.cbor
- 拉取
/root-keys(或用固定的 PEM)。 - 拉取回执 CBOR。
- 解析 COSE_Sign1,从 label 396 取出包含证明。
- 用回执里的 4 字节
kidO(1) 映射到验证公钥。 - 从
SHA-256(0x00||payload)沿 Merkle 路径走到rootHash,不匹配即拒绝。 - 对 Sig_structure 做 ES256 验签。
- 交叉比对回执算出的 leaf hash 与 badge 的
merkleProof.leafHash。 - 对 leaf 承诺的每个 metadata hash,拉取被承诺 SVCB 行携带的 URL(key
65400)处的 descriptor,比对它的 SHA-256 与承诺值;不一致则校验失败,descriptor 不可达只上报不失败。-check-metadata=false可跳过第 8 步。
可插拔端口与生产替换
架构是 hexagonal / ports-and-adapters:领域模型(internal/domain)不依赖任何框架或存储;service 依赖 internal/port 的接口,由 internal/adapter 实现。调用链例如 cmd/ans-ra/main.go -> internal/ra/service -> port.AgentStore -> internal/adapter/store/sqlite、port.KeyManager -> internal/adapter/keymanager、port.DNSVerifier -> internal/adapter/dns;cmd/ans-verify/main.go -> internal/tl/receipt(Verify、ExtractKID、ComputeLeafHash);cmd/ans-dns/main.go 是 miekg/dns 权威服务器加 RA 驱动的记录 install/clear。
| 关注点 | 默认适配器 | 常见生产替换 |
|---|---|---|
| Auth | 静态 API key + OIDC | 对接自有 IdP 的 OIDC |
| 身份证书签发 | 文件自签 CA | Cloud KMS 支持的 CA |
| 服务器证书签发 | 自签 CA + BYOC PEM | ACME / 公共 CA / BYOC PEM |
| DNS 校验 | noop 与 lookup(真实 miekg/dns 查询,传播 DNSSEC AD 位) | 查询自有权威 DNS |
| 签名密钥 | 文件 ECDSA P-256 | Cloud KMS 适配器 |
| 存储 | SQLite | Postgres / 托管 RDBMS |
Cloud-KMS、Postgres、托管 DNS 适配器属于欢迎贡献的形态。
现状与坑
已交付:完整 V1 + V2 RA 接口(register、verify-acme、verify-dns、revoke、list、detail、identity/server cert GET + POST、CSR status、带 BYOC 与 CSR 路径及到期扫描的续期生命周期);TL 的 ingest、badge、audit、SCITT COSE 回执(tag 18、ES256)、SCITT 状态令牌(TTL 1 小时,感知终态)、/root-keys(sumdb-note 格式)、JSON 与 raw checkpoint、分页 checkpoint 历史、schema lookup、Merkle tiles;Producer-key 管理 CRUD(/internal/v1/producer-keys);CLI ans-verify;开发 DNS 服务 ans-dns。后续计划:cloud-KMS / Postgres / 托管 DNS 适配器、真实 ACME DNS-01 校验器接线、更多 schema 版本。License 为 MIT。
开发门禁:make test、make test-cover(仓库门槛 ≥90%)、make test-race、make check(fmt + vet + lint + test-cover)。覆盖率目标是 internal/domain 与 internal/crypto 100%,internal/ 整体 ≥90%,adapter 包是目前主要的缺口。
落地时要留意的几点:ans-dns 仅用于开发,生产走对既有权威 DNS 的 lookup;本地默认的 noop DNS 校验器会接受任意状态,别把它带进验证链路;quickstart 的静态 key 等同 admin,不能直接上线;compose 的 down -v 会清 volume;气隙校验需要固定 trusted-tl.pub。
相关规范
OWASP GenAI Security Project ANS v1.0(genai.owasp.org)给出 DNS 启发的框架、PKI、JSON schema,以及支持 A2A、MCP、ACP 的协议适配层,并用 MAESTRO 七层威胁模型覆盖 agent 冒充、注册表投毒、DoS。