1. 为什么大模型网关的配置必须加密
  2. Nacos 配置加密方案选型
  3. 接入 Nacos 加密插件实战
  4. 网关侧密钥管理与动态刷新
  5. 大模型供应商密钥的安全传递
  6. 最佳实践与踩坑点总结

1. 为什么大模型网关的配置必须加密

大模型接口对接的是按 token 计费的商业 API(OpenAI、通义、智谱、Claude 等),其 `API Key` 一旦泄露,攻击者可以冒用你的额度产生巨额费用,甚至用你的身份输出违规内容。此外,网关配置里还可能含数据库密码、内部服务 token、灰度白名单等敏感信息。

明文存放在 Nacos 有三大风险:运维同学截图泄露、Nacos 控制台未鉴权被拖库、配置导出文件散落。因此必须把敏感字段**加密存储、解密使用**,且密钥本身不能和密文放在同一处。

2. Nacos 配置加密方案选型

2.1 官方加密插件 nacos-aes-encrypt

Nacos 2.x 官方提供 `nacos-aes-encrypt-plugin`,基于 AES 对称加密。写入时加密、读取时自动解密,对应用透明。缺点是对称密钥若和 Nacos 同机部署仍有泄露面,生产建议密钥来自 KMS。

2.2 应用侧加解密(更可控)

另一种常见做法是:配置在 Nacos 中以密文(如 `cipher:AES:xxxx`)存储,网关启动时或监听时用本地/ KMS 的密钥解密。这种方式解密逻辑在网关侧,密钥可放 KMS,隔离更强。

下表对比:

方案

加密位置

密钥管理

应用改动

适用

---

---

---

---

---

Nacos 官方插件

Nacos 服务端

服务端配置

几乎无

快速接入

应用侧解密

应用侧

KMS/本地

需写解密器

强合规

全量 KMS

不落 Nacos

KMS

配置只存引用

金融级

3. 接入 Nacos 加密插件实战

3.1 服务端启用加密插件

Nacos 服务端 `application.properties` 开启插件并配置密钥(生产改为 KMS 注入):

nacos.core.auth.enabled=true
nacos.plugin.encrypt.version=highest
nacos.plugin.encrypt.aes.secretKey=${NACOS_ENCRYPT_KEY}

 

客户端在 dataId 内容中以 `cipher` 前缀标记密文,Nacos 控制台显示密文,应用拉取时是明文。

3.2 网关侧自定义解密过滤器(应用侧方案)

当采用应用侧解密,我们实现一个 `ConfigDecryptProcessor`,在配置监听回调里解密:

@Component
public class ConfigDecryptProcessor {
    private final KmsClient kmsClient;
    public ConfigDecryptProcessor(KmsClient kmsClient) {
        this.kmsClient = kmsClient;
    }
    public String decryptIfNeeded(String raw) {
        if (raw != null && raw.startsWith("cipher:AES:")) {
            String cipherText = raw.substring("cipher:AES:".length());
            String dataKey = kmsClient.getConfigDataKey(); // 从 KMS 取明文密钥
            return AesUtil.decrypt(cipherText, dataKey);
        }
        return raw;
    }
}

 

网关的 `@NacosConfigListener` 拿到原始内容先过一遍 `decryptIfNeeded`,再注入到路由配置,保证内存与运行态是明文、落库是密文。

4. 网关侧密钥管理与动态刷新

4.1 密钥集中管理为 Spring Bean

把解密后的大模型供应商密钥收敛到一个 `LlmCredentialHolder`,由 `@RefreshScope` 管理,配置变更时自动重建:

@RefreshScope
@Component
public class LlmCredentialHolder {
    @Value("${llm.qwen.api-key}")
    private String qwenApiKey;     // 解密后注入
    @Value("${llm.zhipu.api-key}")
    private String zhipuApiKey;
    public String getKey(String provider) {
        switch (provider) {
            case "qwen": return qwenApiKey;
            case "zhipu": return zhipuApiKey;
            default: throw new IllegalArgumentException("unknown provider");
        }
    }
}

 

4.2 路由转发时注入密钥(不回显)

网关在转发到大模型供应商前,用 `ModifyRequestBodyFilter` 或自定义 `GlobalFilter` 把密钥塞进下游 Header,且**绝不在日志/响应里打印**(用掩码):

@Component
public class LlmAuthInjectFilter implements GlobalFilter, Ordered {
    private final LlmCredentialHolder holder;
    public LlmAuthInjectFilter(LlmCredentialHolder holder) {
        this.holder = holder;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String provider = exchange.getRequest().getHeaders().getFirst("X-Provider");
        String apiKey = holder.getKey(provider);
        ServerHttpRequest mutated = exchange.getRequest().mutate()
                .header("Authorization", "Bearer " + apiKey)
                .build();
        // 日志仅打印掩码,禁止明文
        log.debug("注入 {} 密钥: {}", provider, mask(apiKey));
        return chain.filter(exchange.mutate().request(mutated).build());
    }
    private String mask(String key) {
        if (key == null || key.length() < 8) return "***";
        return key.substring(0, 4) + "****" + key.substring(key.length() - 4);
    }
    @Override
    public int getOrder() {
        return -50;
    }
}

 

5. 大模型供应商密钥的安全传递

5.1 密钥轮换(Rotation)

密钥泄露或定期合规要求轮换时,在 Nacos 把新密钥以密文更新,网关 `@RefreshScope` 自动重建 `LlmCredentialHolder`,无需重启。旧密钥短期内并行保留,确认无流量后再吊销。

5.2 密钥与密文分离存储

资产

存储位置

访问方式

---

---

---

密文配置

Nacos(namespace 隔离)

控制台/API,需鉴权

数据密钥

KMS

运行时动态获取

主密钥

KMS/HSM

不落应用

这样即便 Nacos 被拖库,攻击者拿到的也只是 AES 密文,没有 KMS 主密钥无法还原。

5.3 审计与最小权限

生产 namespace 开启配置鉴权,只有网关部署账号能读 `LLM_GATEWAY_GROUP`;所有密钥读取走 KMS 审计日志,可追溯谁在何时取了哪个密钥。

6. 最佳实践与踩坑点总结

  • **踩坑 1:加密密钥和密文同仓同机**。对称密钥绝不能写在 Nacos 同一份配置里,否则加密形同虚设,务必走 KMS/HSM。
  • **踩坑 2:日志打印明文密钥**。务必加掩码工具,且网关 `log` 级别在 prod 设为 INFO,避免 DEBUG 误打密钥。
  • **踩坑 3:解密失败无兜底**。KMS 不可用时若直接抛异常会让网关起不来,应加本地缓存密钥 + 降级策略。
  • **最佳实践**:敏感配置统一用 `cipher:` 前缀标记,未标记的不允许含密钥(用 CI 扫描拦截)。
  • **最佳实践**:密钥轮换常态化,配合第 12 篇的监听热更新做到零停机换密钥。
  • **最佳实践**:环境隔离(第 13 篇)+ 配置加密(本篇)组合,是满足等保/合规的最小闭环。

密钥安全是大模型网关的底线,而要让这么多配置与路由「看得见、管得住」,下一站是网关可观测性。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐