说起来有点难为情我是在一次差点酿成事故的配置泄露之后才认真研究起“Nacos 服务端开启鉴权”这件事的。当时团队在维护某个跨平台系统的配置中心Nacos 服务端开在内网的一台虚拟机上图省事没有做任何访问控制。直到有一天一份本该严格保密的配置文件内容被改得面目全非操作日志查不到来源控制台也没有任何异常告警。排查到最后才发现是某个旧环境迁移过来的离线脚本因为配置不当直连了我们的 OpenAPI 并触发了清理逻辑整个过程只有几秒钟。那次事故之后我做了一系列整改其中最关键的一步就是给 Nacos 服务端完整开启鉴权并同步改造了所有客户端的接入方式。这篇博文就是基于那次实操整理的重点讲清楚为什么 Nacos 鉴权必须开、服务端怎么配、客户端怎么适配、以及开启之后会遇到哪些坑。适合两类人看一类是 Nacos 已经在测试或生产环境跑着但还没开鉴权的朋友另一类是刚接触 Nacos、希望从一开始就按安全方式搭建的初学者。我会从原理讲到可复制的配置和排错命令全程不绕弯子。1. 一次惊心的配置事故为什么服务端鉴权不能再拖了1.1 事故重现一条请求删光配置只用了三秒钟事情发生在一个普通得不能再普通的周四凌晨。监控系统突然发来一堆配置校验失败的告警紧接着核心业务配置从配置中心全部消失。起初我以为是存储盘坏了登录 Nacos 控制台一看配置列表空空如也注册中心的服务列表倒是都在。第一反应是查操作记录结果发现控制台根本没有审计日志——因为服务端压根就没开鉴权也就没有任何身份追踪。最后定位到的原因让人哭笑不得一个从旧环境迁移过来的离线同步脚本内容里硬编码了 Nacos 的 OpenAPI 地址而它所在的网络段恰好能直连我们的服务端。脚本本身不怀恶意但其中一条清理逻辑触发了配置批量删除接口。整个过程只有三秒钟却让整个团队第二天陪着我一起恢复配置。从那一刻起我就明白内网环境里“Nacos 服务端开启鉴权”不是安全建议而是必须做的生存配置。1.2 先分清两个概念服务端鉴权和客户端接入认证很多人把“鉴权”理解成一个开关翻一下配置就结束了。实际上 Nacos 的鉴权至少涉及两个层面。第一层是服务端身份认证控制台登录、OpenAPI 调用、服务注册与发现请求都要先证明“你是谁”。服务端通过校验用户名密码或 token 来决定是否放行。第二层是客户端接入认证当服务端开启鉴权后所有客户端无论是 Spring Cloud 服务、Go 服务还是纯脚本在发起请求时都必须携带身份凭证。如果客户端代码没有适配轻则读不到配置重则整个应用启动失败。这两个概念经常被混淆。网上很多教程只教你在服务端配置一个enabledtrue却完全不提客户端需要同步修改导致很多人开了鉴权之后生产环境一片报错。这篇博文会把两层都讲清楚并且给出可以直接抄的配置和验证方式。1.3 这篇博文覆盖的范围和前置知识如果你已经决定要开鉴权那么后面这些内容是你可以直接用的鉴权原理、服务端配置项逐项说明、重启后的验证命令、主流框架的客户端适配方式以及我踩过的坑和排错逻辑。前置要求很简单Nacos 服务端版本建议在 2.2.1 及以上后面会解释为什么你会基本的 Linux 命令和 properties 文件编辑。如果你还在用 1.x 版本建议先整体升级再开鉴权不要在一个老版本上做安全改造后面的坑会多到让你怀疑人生。2. Nacos 鉴权的底层机制JWT、插件化与版本分水岭2.1 一条访问请求的完整鉴权链路先把最核心的东西讲清楚Nacos 的鉴权基于 JWTJSON Web Token。为了让你不被术语吓到我用游乐园手环来类比。游客进游乐园时先在大门口用门票用户名密码换取一个当日手环token。手环上有一串防伪码是用园区管理员的秘密印章token.secret.key盖上去的游客自己改不了。每玩一个项目访问一个接口工作人员先看手环然后用手里的同一枚印章验证防伪码真伪有效就放行。对应到 Nacos客户端先调用登录接口/nacos/v1/auth/users/login提交账号密码服务端校验通过后用 token.secret.key 签发一个 accessToken 返回给客户端。客户端后续请求把 accessToken 放在 URL 参数、HTTP Header 或 Cookie 里服务端每次收到请求都会校验 token 的签名和有效期。这里有三个关键点值得注意token.secret.key 是签名的唯一秘密一旦泄露任何人都能伪造 token鉴权等于没开。accessToken 有有效期安全要求高的场景应该定期重新登录刷新。校验逻辑在服务端客户端无法绕过除非攻击者直接拿到服务端配置文件的修改权限。2.2 2.2.1 版的分水岭为什么必须自定义密钥为什么反复强调服务端版本要 2.2.1 及以上因为这里有一个真实的安全漏洞背景。在 2.2.1 之前如果你只把nacos.core.auth.enabled设成 true而没有显式配置 token.secret.key服务端会使用源码里内置的一个默认密钥。这个默认密钥是公开的等于手环防伪码全世界都知道。攻击者可以用默认密钥直接伪造一个管理员 token然后调用任何接口鉴权形同虚设。2.2.1 版本之后官方把默认密钥这个坑堵上了要求必须显式配置自定义密钥并且密钥要满足一定强度不配置的话服务启动会失败或打印严重错误。同时鉴权实现被插件化通过nacos.core.auth.system.type指定具体鉴权实现默认nacos内置实现大多数场景直接用默认即可。所以如果你在网上翻到老文章教你在配置里写nacos.core.auth.token.secret.key先确认一下文章对应的版本。2.2.1 之后推荐的配置项是nacos.core.auth.plugin.nacos.token.secret.key两者名字就差一段但写错地方会导致鉴权不生效或启动失败。2.3 server.identity集群节点之间怎么互相信任服务端鉴权解决了“客户端和服务端”之间的信任问题但 Nacos 集群里还有一类请求节点与节点之间的通信。比如配置变更后的数据同步、节点心跳、leader 选举这些请求是由服务端进程发出的前端控制台会拦截它们吗如果也要求带 token节点之间怎么交换 tokenNacos 的做法是配置一对自定义身份标识nacos.core.auth.server.identity.key和nacos.core.auth.server.identity.value。节点发起内部通信时会在请求头里带上这对 key/value接收方校验组合是否与自己配置文件里的一致一致就认为是可信节点。这相当于内部人员之间用一句暗号打招呼。实践证明这句暗号不能太简单也不建议所有节点用同一个值。我的做法是服务端每个节点生成独立的身份标识并通过内部专网传输如果完全是单机部署且没有集群同步需求可以省略但为了安全还是建议配上。3. 服务端开启鉴权配置、密钥、重启与验证全流程3.1 动手前的准备版本确认与配置备份改配置之前先做两件事。第一确认版本。Nacos 服务端不用登录控制台也能看到版本在安装目录的 lib 目录下找到以 nacos-server 开头的 jar 包版本号就在文件名里或者看 logs 目录下 start.out 的前几行。版本决定你该用哪个配置项这一步不能跳过。第二备份配置。把conf/application.properties复制一份命令如下cp conf/application.properties conf/application.properties.bak-$(date %Y%m%d)这个习惯是我踩过多次坑之后养成的。服务端配置多个节点时改错一个字符整个集群可能起不来备份至少能让你快速回滚。3.2 核心配置项逐行拆解与密钥生成接下来是正文。用编辑器打开conf/application.properties在文件末尾追加以下配置不要覆盖原有的 server 端口等基础配置### 开启鉴权开关 nacos.core.auth.enabledtrue ### 鉴权系统类型使用 Nacos 内置实现 nacos.core.auth.system.typenacos ### JWT 签名密钥必须显式自定义 nacos.core.auth.plugin.nacos.token.secret.key你的密钥 ### 集群节点间身份标识 nacos.core.auth.server.identity.keyserverIdentity nacos.core.auth.server.identity.value你的随机标识值逐行解释一下nacos.core.auth.enabled总开关设成 true 后所有需要鉴权的接口开始强制校验。nacos.core.auth.system.type2.2.1 版本开始引入指定鉴权插件类型。不写默认就是 nacos但显式写出来更清楚。nacos.core.auth.plugin.nacos.token.secret.keyJWT 签名密钥整份配置里最重要的一个值。nacos.core.auth.server.identity.key / value前文说的节点间暗号key 一般固定写 serverIdentityvalue 必须随机且不易猜测。密钥怎么生成推荐用系统自带的工具openssl rand -hex 32这条命令会输出 64 个十六进制字符对应 256 位随机密钥比手打一串字母要安全得多。为什么用 hex 而不是 base64 输出因为 hex 只包含 0-9a-f没有、/、这类容易在 properties 解析中出问题的字符实测最省心。复制的时候注意去掉可能产生的换行符。如果你更习惯 base64openssl rand -base64 32也可以但要确保粘贴到 properties 文件时不含换行、不含多余空格。3.3 重启服务端并用三条命令验证保存配置后重启 Nacos 服务端单机模式sh bin/shutdown.sh sh bin/startup.sh -m standalone启动过程留意控制台输出和logs/start.out。启动完成、看到 auth 相关日志没有报错之后用下面三条命令验证鉴权是否真正生效。第一条不带任何凭证直接读取配置预期返回 403curl -X GET http://127.0.0.1:8848/nacos/v1/cs/configs?dataIdtest.jsongrouppublic你会看到类似 access denied 的提示。如果这里返回 200 或者配置内容说明配置根本没生效回头检查 enabled 是否写对、文件是否保存、进程是否真的重启过。部分接口会返回 401本质是同一类认证失败。第二条调用登录接口获取 token假设账号名为 nacos密码为 nacoscurl -X POST http://127.0.0.1:8848/nacos/v1/auth/users/login -d usernamenacospasswordnacos返回的 JSON 里会有 accessToken 和 tokenTtl。第三条把 accessToken 带上再请求一次curl -X GET http://127.0.0.1:8848/nacos/v1/cs/configs?dataIdtest.jsongrouppublicaccessToken你的token这次要么返回配置内容要么返回 404表示 dataId 不存在但不会出现 403。403 变成 200/404说明鉴权链路通了。这套验证组合我每次改完配置都会完整跑一遍比只看控制台登录结果可靠得多。3.4 控制台首次登录与默认账号处理接口验证通过后打开浏览器访问http://ip:8848/nacos会看到登录页。这一步有一个新手容易疑惑的地方不同小版本的默认账号密码行为不完全一致。2.2.1 到 2.3.x 的常见情况是默认账号 nacos、密码 nacos部分版本首次登录后会强制跳转修改密码页也有个别版本要求先看服务端日志中的提示。如果你用 nacos/nacos 登不进去不要反复试直接去logs/start.out里搜 password 或 default account 相关日志以实际输出为准。登录进去之后第一时间做三件事修改默认账号的密码改成一个足够复杂的随机密码。在“权限控制”菜单里新建一个专门用于日常维护的管理员账号不要所有同事共用内置账号。检查“权限控制”下的用户、角色列表确认只有你预期中的账号。内置账号与角色管理只有在开启鉴权后才会出现所以如果你登录后找不到“权限控制”菜单多半是鉴权没完全生效回到上一节重新验证。4. 客户端适配清单主流框架、原生 SDK 与豁免场景4.1 Spring Cloud 生态下的用户名密码配置服务端开了鉴权客户端如果还按老样子只配 server-addr最典型的症状就是服务启动时读取配置失败、日志里出现 403或者注册到 Nacos 的实例列表为空。以 Spring Cloud 方式接入为例配置中心和数据发现分别在spring.cloud.nacos.config和spring.cloud.nacos.discovery两个模块下两个模块都要带上用户名密码spring: cloud: nacos: discovery: server-addr: 192.168.1.10:8848 username: nacos password: 修改后的密码 config: server-addr: 192.168.1.10:8848 username: nacos password: 修改后的密码这里很容易踩的一个点只配了 discovery 的 username/password忘了 config 模块。如果你的服务依赖配置中心启动印象就是“开了鉴权之后服务全挂了”其实只是配置漏了。我在团队里统一加了一个约定任何客户端接 Nacos都必须把 config 和 discovery 两个模块的用户名密码同时写上哪怕当前服务只用其中一个。4.2 原生 SDK 与其他语言客户端的接入方式如果你的项目直接用 Nacos 官方 SDK不经过 Spring Cloud配置逻辑同样简单。以 Java 原生 SDK 为例Properties properties new Properties(); properties.put(serverAddr, 192.168.1.10:8848); properties.put(username, nacos); properties.put(password, 修改后的密码); ConfigService configService NacosFactory.createConfigService(properties); NamingService namingService NacosFactory.createNamingService(properties);一个 Properties 实例传给两个 create 方法会各自建立连接这是正常现象。其他语言的客户端原理也类似先调用 login 接口拿到 token再把 token 放到后续请求的accessToken参数或Authorization: Bearer xxxHeader 里。如果某个 SDK 不原生支持账号密码配置通常也能手动处理思路都是“登录换取 token请求统一携带 token”不同语言只是语法差异我这里就不逐个贴完整代码了。4.3 那些不需要带 token 的请求健康检查与白名单有人问鉴权开启之后是不是所有接口都要 token并不是。Nacos 对健康检查、服务列表查询这类基础运营接口做了匿名放行比如/nacos/v1/ns/health这类用于负载均衡探测的接口不需要 token。这属于设计预期不属于鉴权漏洞。但要有边界感你自定义的监控脚本如果要去读配置内容或者要通过 OpenAPI 发布配置就必须带 token。我在团队里维护了一个独立的监控账号专门给脚本用不和业务服务共享账号这样即使脚本的 token 泄露也能快速在控制台吊销重发。另外如果你们在 Nacos 前置了一层 Nginx建议把/nacos/v1/auth/users/login之外的接口都限制在可控出口网段不要在公网随意暴露。鉴权解决的是“谁可以访问”网络层面还要解决“谁能到服务端”两者叠加才比较稳。5. 开启鉴权后我踩过的四个坑现象、原因与排查思路5.1 坑一服务端重启后客户端全部 403但控制台登录正常这是新手最容易遇到的。现象是服务端鉴权生效控制台也能正常登录但重启一个业务服务后日志疯狂报 HTTP 403配置中心连不上。原因几乎都在客户端要么没有配置 username/password要么只配置了其中一个模块。排查时我习惯先把客户端报错日志里的请求 URL 抓出来看它请求的是/nacos/v1/cs/configs还是/nacos/v1/ns/instance哪个 403 就补哪个模块的配置。如果在 Nacos 服务端所在主机上 curl 不带 token 也会 403说明服务端状态正常此时问题一定在客户端配置不要反复重启服务端。这个区分很重要能节省大量时间。5.2 坑二启动报错提示密钥缺失或长度不足2.2.1 之后的版本对密钥有强校验。如果只写了nacos.core.auth.enabledtrue忘记写 token.secret.key启动时日志会出现类似 The secret key is null or not configured 的报错服务可能一直起不来。还有一种情况密钥写了但内容太短。网上有些教程随便写了个 nacos 当密钥几秒钟就报错。Nacos 要求密钥经过 base64 编码后长度不能低于一定字节数我这里统一建议生成 64 个 hex 字符32 字节一次满足要求。如果你是从老版本升级上来的还要检查是否沿用了旧配置项nacos.core.auth.token.secret.key。升级后这个配置项不一定生效要改成nacos.core.auth.plugin.nacos.token.secret.key。这个只是配置项名字的差异但极难排查。5.3 坑三密钥复制时的换行与特殊字符配置密钥本身没有问题问题往往出现在复制粘贴环节。第一种情况是命令行生成密钥时输出带换行粘贴进 properties 后值被截断启动时长度校验失败或签名校验失败症状是登录一直 401。第二种情况是手动修改密钥时混入了反斜杠或空格。properties 文件对反斜杠有转义语义一个\n可能被解析成换行导致后续内容全部错乱。我的做法是生成密钥后用tr -d \n去掉换行再复制粘贴完成后再用sed -n 密钥行号p检查当前行的实际字符数和内容。如果发现长度不对宁可重新生成一次也不要手工删改。5.4 坑四鉴权开了但权限管理放任自流这个坑不是技术问题但比技术问题更常见。开了鉴权之后如果所有服务都用同一个 admin 账号或者控制台直接暴露在公网、密码还是 nacos那这个鉴权基本等于白开。攻击者拿到明文密码或抓到一次登录请求就能接管整个配置中心。我的建议是三步走控制台和 OpenAPI 不要直接暴露公网能走内网走内网需要外部访问就加一层 HTTPS 和来源 IP 白名单。服务账号和管理账号分离。业务服务用只读或命名空间受限账号管理员用独立账号脚本用自动续期的专用账号。定期轮换密钥。token.secret.key 轮换会让所有已签发的 token 失效所以操作前要预留客户端重新登录的窗口最好选在业务低峰期做。5.5 一套排错三步走日志、接口、配置最后把我常用的排错套路分享出来遇到鉴权问题按这个顺序走基本都能定位。步骤操作预期结果如果不对1查看服务端 logs/start.out 中 auth 相关日志无报错查配置项和密钥2不带 token 调 OpenAPI403鉴权可能未生效回查开关3带 token 调 OpenAPI200/404账号密码或 token 问题第 2 步特别关键。如果你不带 token 也拿到了配置内容那说明服务端鉴权压根没生效后面所有客户端配置都不用看了。很多朋友一遇到 403 就怀疑客户端其实根源在服务端配置和重启顺序用这套三步走能快速收敛。最后补一个我自己的小习惯每次改完 Nacos 服务端配置我不会只凭控制台能登录就判定成功而是会把第 3.3 节那三条 curl 命令完整跑一遍然后重启一个依赖配置中心的客户端服务确认整条链路真的走通。鉴权开启本身不难难的是让所有相关系统都跟着改对这也是我最想在文中强调的一件事。希望这份实录能帮你少走几个来回。