# 密钥轮换留在提供方,别让每个助手各存一份 | EasyNet Source: https://easynet.run/cases/problems/rotate-provider-credentials [easynet.run · 全部问题场景](https://easynet.run/cases#problem-scenarios) # 密钥轮换留在提供方,别让每个助手各存一份 数据服务要换密钥,工程师开始逐个找 Agent 配置。有人放在环境变量,有人复制进脚本,还有一份在旧笔记本里。轮换工作迟迟不能结束,因为没人知道遗漏的副本会在下一次什么任务中被用到。 有工作负载身份或集中密钥管理,就先用它们的轮换机制。EasyNet 不应该替代 secret store。更值得改变的是消费者关系:助手是否真的需要持有上游密钥,还是只需要调用一次获准的数据查询? 可以让查询函数运行在提供方环境,由那里读取上游凭据,接收明确的查询条件,返回必要业务字段。通过 EasyNet 接入后,各助手使用自己的获准调用身份,不再分别配置同一份服务秘密。 函数不能因此变成任意网址请求代理。提供方校验查询对象和范围,不把密钥放进参数、返回值或错误文本。调用身份的授权与上游密钥的权限分别管理,轮换其中一项不表示另一项也已经撤销。 实际轮换仍遵循上游流程:更新提供方配置,验证新凭据,再确认旧值被上游拒绝。是否允许短期双凭据、是否需要维护窗口,取决于该服务;这些逻辑和故障告警要由运行程序实现。 让两个调用者在测试环境完成同一查询,换钥后再次核对,同时检查旧凭据确实失效。以后上游再轮换,维护者改的是自己负责的一处接入,而不是要求每个助手重新领取一个秘密。 01 两个获准调用者 不接收同一份上游密钥 02 提供方查询函数 固定服务和必要查询范围 03 轮换后双向检查 新键能用,旧键被拒绝 助手持有自己的调用身份,提供方管理上游凭据。 测试的是旧值被拒绝,不是删了一行配置 使用无秘密的 mock token 演示验证条件,不连接 secret store,不输出或轮换真实密钥。 本地示例 · python ``` class MockUpstream: active_token = "mock-v1" def query(self, token): if token != self.active_token: raise PermissionError("credential rejected") return {"rows": 3} upstream = MockUpstream() provider_token = "mock-v2" upstream.active_token = provider_token assert upstream.query(provider_token) == {"rows": 3} try: upstream.query("mock-v1") except PermissionError: print("new credential works; old credential rejected") else: raise AssertionError("rotation incomplete") ``` 预期结果:输出新凭据可用且旧凭据被拒绝;真实轮换还需使用供应商流程验证。 接入时的检查项 调用者配置与返回结果中是否没有上游秘密。 轮换后两个调用者能否继续完成获准操作。 旧凭据是否确实被上游拒绝,而非仅从某份配置删除。 源码与接入资料 [函数接入指南](https://easynet.run/docs/connect/function) [设备接入指南](https://easynet.run/docs/connect/runtime)