作者:柳遵飞
Nacos 作为配置中心经常存储一些敏感信息,但是由于误用导致安全风险,最常见的主要是以下两个问题:
1)Nacos 暴露公网可以吗?不可以,因为 Nacos 定位是注册配置中心,是内部系统,不应该暴露到公网使用。
2)不得已要开公网不开鉴权可以吗?不可以,开公网不开鉴权等同于裸奔,为黑客攻击创造充分条件。
看到赶紧自查一下是否有这两类问题,如果有立即解决一下!!! 解决完这些基础问题,可以看一下下面安全的进阶玩法。
安全问题的现实背景
Nacos 作为国内被广泛使用的注册配置中心,是云原生时代不可或缺的基础中间件组件,在开源社区拥有庞大的开发者群体,Nacos 也被广泛运行在生产环境之中。随着当前云计算,物联网,大数据 AI 等技术的兴起,相比于传统的基于“安全内网”的网络架构,现代的系统网络部署架构复杂性上升,传统的网络边界逐渐模糊化,对传统的网络安全架构产生了极大的冲击,业内数据泄露,网络攻击等事件频发,安全问题给企业的发展带来的影响越来越大。在此背景下,安全零信任的理念逐渐兴起,成为了现代化网络安全架构的指导思想,本文将介绍如何基于安全零信任的理念来保证 Nacos 的数据安全。
今天分享的内容分为三个部分展开,第一个部分会简单介绍下 Nacos 这款产品以及其常见的一些使用场景,第二个部分会根据 Nacos 运行时的原理来分析其可能面临的安全风险,没有对 Nacos 做必要安全保护也是当前造成 Nacos 数据泄露的真实现状,最后一个部分会分享 Nacos 在安全零信任理念下的最佳实践,如何让 Nacos 更加安全的运行在生产环境。
Nacos 发展及使用场景
Nacos 是什么?它的名字是由服务和配置管理的英文首字母,它的核心功能包括动态服务发现管理,动态配置管理,动态 DNS 服务。动态服务管理可以和上层的微服务 RPC 调用框架结合,比如 Spring Cloud, Dubbo 等实现节点上下线自动流量拆除或者上线,动态配置管理提供了在运行期不重启业务节点的情况下改变业务应用的运行时行为,也可以结合 CoreDNS 将 Nacos 上注册的服务导出为 DNS 域名来实现动态 DNS 服务。
Nacos 将阿里巴巴集团内部 Diamond,ConfigServer,VipServer 三款中间件融合进一款产品,承袭了阿里内部十几年双十一大促的性能,稳定性,高可用方面的技术经验,2018 年从阿里内部开源以来,无论从 github 上的 star 数,fork 数,社区活跃度还是知名技术网站论坛评选的奖项可以看出它的受欢迎程度。从注册配置中心单一领域产品角度看,Nacos 现在是国内首选,被非常多的头部企业使用,占据国内 60%+ 的市场份额。
Nacos 能收到这么多开源社区的关注度和参与度,和它的使用场景是息息相关的。
上图列举了 Nacos 的一些非常常见的使用场景,覆盖了微服务领域,高可用领域,前端生态,数据库领域等等,产品功能角度看,服务发现和注册涉及的场景会相对聚焦一些,它所承载的数据是服务名或者域名到 ip 地址的映射关系,而配置管理涉及的场景就会丰富很多,可以说是涉及到任何的领域。从上面图中可以看出,其中有一些非常关键的场景都是靠配置中心来完成的,比如流量调度,路由规则,应急预案,一些业务的关键开关,数据库的一些数据源配置。
这些数据是非常敏感的,如果数据被误写,密码数据被泄露,可能会产生非常大的数据安全问题。
在业界内也发生过不少的敏感数据泄漏事件,用户把开源的 Nacos 部署到了生产环境,但没有对 Nacos 做一些必要的安全防护的措施,当前行业对安全方面的意识也在逐渐提高,国家颁布的网络安全三级等保也对非银行业的平台做了若干个角度的安全要求。
Nacos 面临的安全问题
上面是 Nacos 运行时的简要示意图,左侧是业务应用和 nacos-client,通常是部署在一个进程中,右侧是 Nacos 的服务端,包括 Nacos-Server 和中心化的持久化存储。从数据流转方向上看,数据由业务应用侧产生调用 nacos-client 的配置发布接口,通过网络传输至 Nacos-Server 端,Nacos-Server 端将配置内容持久化存储,并且从持久化存储加载到 Server 本地的磁盘缓存和内存缓存中,客户端查询配置时将配置内容从服务端拉取到本地,出于高可用容灾的考虑,客户端会将配置内容缓存在客户端本地磁盘中。从数据的角度看,配置内容会存在于业务应用本地的磁盘缓存,服务端本地的磁盘缓存,持久化的数据库中,并且数据会在传输过程中经过每一个中间网络设备。
现在我们做个假设,让我们先忽略安全内网,假设这些组件都是暴露在公网之中。基于这个假设,可能会存在以下几个方面的问题。
-
业务应用机器被入侵
因为 Nacos 的配置数据会在客户端进行缓存,所以如果业务应用的机器被入侵,本地缓存中的配置内容也会泄漏
-
数据传输过程中被中间网络设备获取
数据经过中间网络设备,可能被流量抓包,如果数据是明文传输,数据就会泄漏
-
Nacos 服务端被入侵
如果 Nacos 服务端所部署的机器被外部攻破,那么存在于本地磁盘缓存内的也会被明文获取
-
持久化层数据库被拖库
配置存储的中心化数据库被拖库也会导致配置泄露
-
Nacos 服务端可公开访问
Nacos 服务端没有开启权限访问,任何知道 server 节点 IP 地址的人都可以通过 Nacos 接口 API 拉取到配置内容,或者对 Nacos 服务端的节点设置了比较宽泛的 ACL 规则,这两种情况在用户使用 Nacos 的场景中都比较常见,比如在商业化 MSE Nacos 的真实案例中,有很多用户给实例开了公网访问并且设置了比较宽泛的 ACL 规则的情况下没有开启鉴权,这些都是风险比较高的场景。
我们对以上的几个问题进行一些简单的归纳,可以分为三个方面,存储安全,传输安全,访问控制。
上面我们做了几个假设,比如忽略安全内网隔离的问题,假设每一个环境都可能会被攻破的。其实这也就是安全零信任理念中一个非常重要的原则,“永不信任,永远验证”,下一节我们将介绍下 Nacos 的安全零信任实践,如何通过安全零信任理念来保障 Nacos 数据安全。
Nacos 安全零信任实践
我们先简单了解下安全零信任的相关内容。
零信任的定义
顾名思义,即对任何未经验证的访问实体默认不信任。零信任是一种现代化的网络安全访问理念,核心思想是“永不信任,持续验证”。
零信任解决的问题
它诞生的背景是基于当前 IT 网络架构下的一系列现实因素。
- 网络边界模糊化,现代系统网络架构更加负责,云计算,物联网等兴起打破了传统的”安全内网“边界
- 安全漏洞无法避免:网络攻击和数据泄露事件增加,传统安全模型无法应对
- 数据泄露风险:数据泄露对企业造成的直接经济损失以及舆情影响
- 合规性要求:整体大环境下,行业和法规要求企业对网络安全实时更加严格的验证
零信任基本功能
零信任的几个基本功能包括:
- 身份管理:提供对身份全生命周期管理
- 身份认证:对所以访问的来源进行身份认证
- 访问控制:确保对网络实体发起访问的资源进行授权
- 传输安全:确保所有在网络中传输的数据不被窃取和篡改
- 行为监控:对行为进行持续监测,实时响应异常
零信任基本原则
- 永不信任,永远验证
- 访问控制,最小权限访问
- 微分段,防止横移,减少攻击面
Nacos 传输安全
接下来我会按照 Nacos 传输安全,存储安全,访问控制三个方面来介绍 Nacos 的安全零信任实践。
第一个方面是 Nacos 传输安全 TLS,我们知道 TLS 解决的是数据传输过程中的三个问题,一个是数据保密性,基于 TLS 传输的数据都会被加密,无法被第三方获取明文,第二个是完整性,它保证的是数据不被第三方篡改,第三个是身份认证,它解决的是通信双方的身份认证问题,防止中间人攻击。
TLS 的握手过程分为几个主要阶段,这里做了部分简化,第一个阶段是客户端和服务端之间进行 TLS 协议版本,加密算法,压缩方法等基本信息的确认,第二阶段是双方的证书交换及验证,这里保证的是身份认证的问题,第三个阶段是双方通过非对称加密来协商后续实际传输报文过程中所使用对称秘钥,第四个阶段,双方发送加密切换消息,双方开始基于对称加密秘钥进行通信,第五个阶段是进行实际的应用报文传输,这里会使用对称加密进行数据传输,同时对报文进行 MAC 校验保证完整性。
Nacos 在 2.x 的版本中使用 grpc 来作为底层通信协议,grpc 内部使用 netty 作为网络通信框架,Nacos 的 TLS 能力也是基于 grpc/netty 来实现的,该图中描述了客户端服务端的基本组件,其中淡蓝色部分是用户通过参数来控制是否开启 TLS 的方式,包括属性文件,jvm 参数,环境变量。深蓝色部分是 Nacos 层提供的组件来接受参数,并将参数转换为底层 grpc、netty 的组件来实现 TLS 功能。 另外在 server 端我们支持了服务端证书的动态轮转功能,可以自定义 SPI 扩展来实现当服务端证书文件变更时的处理逻辑。
这里我们介绍 Nacos 如何开启 TLS 传输加密功能,整个过程分为三步:
-
证书准备
可以通过购买商业证书来获得相关的文件信息,如果是开发测试,可以通过 keytool openssl 自签的方式来生成 SSL 证书,该步骤可以参考网上的自签 SSL 证书流程,此处不在赘述。这一步中需要得到如下几个信息:
- CA 证书文件:用于对端的证书合法性,对端使用的证书必须是通过是由该 CA 签发,防止身份冒充中间人攻击
- 证书文件&证书私钥文件:用于服务端开启 TLS 功能
- 私钥文件密码:处于安全性考虑,通常需要为私钥文件设置密码。
-
Nacos 服务端启动
- nacos.remote.server.rpc.tls.enable=true开启 TLS 开关,设置为 true 表示服务端开启 TLS 功能
- nacos.remote.server.rpc.tls.certChainFile={certFilePath}指定证书文件路径
- nacos.remote.server.rpc.tls.certPrivateKey={keyPath}指定证书私钥文件
- *nacos.remote.server.rpc.tls.mutualAuth=true/false是否开启双向认证,默认为 false,设置为 true 表示需要验证客户端的身份,客户端也需要同步设置证书和私钥文件
- *nacos.remote.server.rpc.tls.trustCollectionChainPath={trustFilePath}受信任客户端 CA 证书,当开启双向认证时,用于校验客户端的证书合法性
- *nacos.remote.server.rpc.tls.compatibility=true/false是否支持非加密客户端,默认是 true
- *nacos.remote.server.rpc.tls.sslContextRefresher={spiName}指定证书轮转感应器 SPI 名称
-
Nacos 客户端启动
- nacos.remote.client.rpc.tls.enable=true客户端开启 TLS 开关,如果设置为 true 的情况下,服务端不支持 TLS 或者没有开启 TLS,则会连接失败
- nacos.remote.client.rpc.tls.trustAll=true/false是否信任所有支持 TLS 的服务端,设置为 true 表示不对服务端证书进行 CA 校验
- *nacos.remote.client.rpc.tls.trustCollectionChainPath={trustFilePath}trustAll 为 true 时,需要设置受信任服务端 CA 证书文件
- *nacos.remote.client.rpc.tls.mutualAuth=true/false是否开启双向认证,设置为 true 时,则需要同步设置客户端的证书文件和私钥
- *nacos.remote.client.rpc.tls.certChainFile={certFilePath}指定客户端的证书文件路径
- *nacos.remote.client.rpc.tls.certPrivateKey={keyPath}指定客户端的证书私钥文件
Nacos 存储安全
配置存储安全解决的问题是当各个可能存在配置内容的介质被攻破,配置被明文访问的问题。在这种情况下,我们需要对配置内的内容进行加密存储,加密存储需要第三方加密系统来辅助完成,复杂性会上升,通常我们建议对部分敏感配置进行加密存储。下面我们将介绍如何通过配置的加解密插件来实现敏感配置存储。
上图介绍了加密配置的发布过程,明文内容在业务应用中产生,经由 nacos-client 发往服务端,在客户端内部,加密配置经过 IConfigFilter 过滤器,会经过加解密插件的加密 encrypt 步骤,将明文转化为密文和 dataKey,通常的做法是本地先生成一个随机 key,通过这个随机 key 对明文内容进行本地加密为密文,将 key 经由加解密插件加密的 dataKey,然后把将密文配置内容和加密后的 dataKey 发向服务端,服务端将密文 +dataKey 进行持久化存储,并且通知集群所有节点将密文 +dataKey 从数据库加载到服务端本地的磁盘缓存和内存缓存中。这种情况下,即使服务端被攻破,持久化数据库被拖库,无法通过密文 +dataKey 解密对应的明文,降低数据泄露带来的安全风险。
接下来是加密后的配置的查询过程,客户端从服务端查询配置,服务端将密文 +dataKey 返回给客户端,客户端经由 IConfigFilter 过滤器,会经过加解密插件的解密 decrypt,将密文 +dataKey 解密为明文,然后在内存中将明文回调给业务的监听器,其中客户端本地缓存中存储的是密文和 dataKey,并不是明文,以此来保证整个链路中的配置存储安全。
在整个链路中引入了第三方加解密插件,增加数据安全的同时,也会带来额外的链路复杂度,我们建议是对一些敏感信息进行加解密,比如用户名密码,数据库配置,AK/SK, Token 等。同时因为加解密插件实现了密文->明文的加密过程,在与其的交互过程中也要保证数据传输安全,并且如果它是有状态的,也要保证它的存储安全。在商业化 MSE Nacos 中,我们使用 KMS 作为第三方加解密插件的实现方,来保证整体的数据安全。
Nacos 访问控制
第三个部分,我们将介绍如何通过 Nacos 鉴权插件实现对 Nacos 的访问控制。
鉴权插件对 Nacos 访问控制进行了基础的模型抽象,分为客户端和服务端,两者通过约定的规则实现整体的访问控制功能。
-
客户端
- 提取识别客户端身份信息 IdentityContext
- 使用身份信息对访问资源进行签名
- 在报文中上传身份信息+签名
-
服务端
- 提取客户端上传的身份信息 identityNames
- 验证身份合法性及验证签名 validateIdentity
- 验证身份与访问资源的权限 validateAuthority
身份信息 IdentityContext 可以是用户名密码,AK/SK,或者 STS/RAM ROLE 自动轮转的 AK/TOKEN,如果想自定义实现自己的身份信息,只需要按需实现 SPI 即可,也可在自定义实现中实现动态身份轮转的逻辑。无论使用哪种身份识别信息,客户端和服务端要保持一致的规则,包括身份信息的提取以及签名验证的逻辑。
服务端处理身份验证和签名验证之外,还需要对身份和访问资源进行权限的校验,用户权限管理比较通用的是 RBAC 模型,RBAC 全称是基于角色的访问控制,当前 Nacos 默认的鉴权插件也就是使用这个模型。
RBAC 模型由权限-角色-用户三个部分组成。
- 权限:权限定义了对指定资源的访问规则,包括资源定义+ 操作(读/写)+许可(允许/拒绝),比如允许对命名空间 A 下的配置进行读操作。
- 角色:拥有一系列权限集合的虚拟身份,它包含了多个权限的集合,比如定义命名空间 A 管理员角色,给其赋于对命名空间 A 下的配置进行读写操作。
- 用户:可实际访问系统的实体用户,用于一个代表自身身份的标识,可以将多个角色赋于实体的用户,间接拥有多种权限。分为管理员和普通用户,管理员拥有最高权限,一般对其会进行 MFA 多因素认证。普通用户由管理员创建,可以给用户赋于多种角色。
上面提到,Nacos 默认的鉴权插件也是基于 RBAC 模型构建,可以完成基本的权限控制,开启默认的鉴权功能需要创建 users,roles, permissions 三张表用于存储对应的数据。
开启 Nacos 访问控制需要三步:
1)服务端开启鉴权
- 打开鉴权开关:nacos.core.auth.enabled=true
- 设置鉴权插件:nacos.core.auth.system.type=nacos,指定为 Nacos 模型内置鉴权插件名
2)创建用户/角色/权限
- 修改 admin 角色默认密码:开启服务端鉴权开关后,登录 Nacos 控制台需要设置用户名密码,首次登录后务必替换默认密码。开启鉴权后,登录控制台,左侧会出现权限控制的菜单
- 创建普通用户,设置用户名密码
- 创建角色,绑定用户-角色
- 创建权限,绑定资源访问规则和角色的关系
3)创建用户/角色/权限
服务端打开鉴权之后,控制台登录需要验证用户名密码,通过 nacos-client 进行接口调用时也需要传入用户名,密码,在构建 ConfigService 和 NamingService 时需要在 properties 属性中传入用户名密码,否则接口访问会返回 403 无权限错误码。
标签:TLS,Nacos,实践,安全,nacos,信任,服务端,客户端 From: https://www.cnblogs.com/alisystemsoftware/p/18160622