grpcurl:从服务描述到可审计 gRPC 调用
UNIMPLEMENTED 之前先核对描述符
grpcurl 把 JSON 转成线上 Protobuf 字节,前提是拿到与目标服务一致的 schema。来源只有三类:服务端 reflection、仓库中的 .proto,或构建产出的 protoset。三者必须记录目标环境、服务版本和生成 commit;“本地有一份 proto”不等于它描述了当前部署。
grpcurl api.example.test:443 list
grpcurl api.example.test:443 describe demo.order.v1.OrderService
grpcurl -d '{"id":"demo-order"}' \
api.example.test:443 demo.order.v1.OrderService/GetOrder关闭 reflection 后,显式提供契约:
grpcurl -import-path ./proto -proto order/v1/order.proto \
-d @ api.example.test:443 demo.order.v1.OrderService/GetOrder < request.json
grpcurl -protoset ./build/order.protoset \
api.example.test:443 listprotoset 需要包含传递依赖。list 能看到服务、describe 能看到全限定方法、最小调用仍返回 UNIMPLEMENTED 时,再检查网关路由和部署版本,而不是先改业务代码。
metadata 与 TLS 分层验证
gRPC metadata 是 HTTP/2 Header 语义,不是请求 message 的字段:
grpcurl -H "authorization: Bearer ${API_TOKEN}" \
-H 'x-tenant-id: demo' \
-cacert ./ca.pem \
-d @ api.example.test:443 \
demo.order.v1.OrderService/GetOrder < request.jsonmetadata 键名、测试主体、租户和 scope 可以进入脱敏证据,token 值不能。mTLS 再增加 -cert 与 -key;客户端私钥只从临时受控路径读取,任务结束立即清理。-insecure 只允许隔离对照实验,不能进入共享脚本。
明文开发端口使用 -plaintext,TLS 服务不要用该参数“碰碰运气”。若入口返回 HTML、HTTP/1.1 错误或重定向,说明流量可能没有到达 gRPC 服务;检查负载均衡、网关协议和后端日志。
status 是分层信号
| status | 先验证什么 |
|---|---|
UNAUTHENTICATED | metadata 是否进入正确入口、凭证是否有效 |
PERMISSION_DENIED | 已认证主体、租户、角色与 scope |
UNIMPLEMENTED | 全限定方法、描述符版本、路由与部署 |
DEADLINE_EXCEEDED | 客户端时限、网关时限、服务耗时 |
RESOURCE_EXHAUSTED | message size、并发、配额和限流 trailer |
UNAVAILABLE | 实例、连接、TLS 或代理中断证据 |
UNKNOWN 往往意味着服务异常映射不足。任何 status 都要与 request id、服务端 trace 和目标版本组合,不能独立当根因。
流式调用需要结束条件
grpcurl 支持 client、server 和双向流。交互终端可从 stdin 连续输入,但 CI 必须固定输入、deadline 和退出条件,避免无限占用连接。取消后还要观察服务端 context 是否终止、资源是否回落。写入型或非幂等 RPC 不可盲目重试。
稳定 smoke 保存 proto/protoset 来源、假数据请求、预期 status 与脱敏输出;工具版本固定在 runner。reflection 是否对生产开放由服务 owner 与安全 owner共同决定,关闭它时仍应能通过受控 protoset 排障。
