通过 VPN 使用 Cassandra:为客户端与节点划分独立访问
一个 Cassandra 集群掩藏着三类受众。请分别决定客户端、对等节点与运维人员如何访问它,并把身份保留在 VPN 通道之内。
一套 Cassandra 部署并不存在一个通用的数据库网络。应用与客户端服务通信,集群成员彼此通信,运维人员使用管理接口,而这三类受众不应彼此继承可达性。像 VPN 这样的私有通道是很好的起点,但它并不是数据库的用户身份,也不是它的加密策略。请把连通性决策和授权决策当作两次独立的评审。
三类受众各自得到答案,下面的小节按暴露程度依次讨论它们。
三类受众,三个决策
在动手改任何规则之前,先弄清楚每一组真正需要什么。客户端需要客户端监听器,以及足够的信息去访问可能被分配给它们的每一个节点;对等节点需要在内网端口上彼此可达;运维人员需要管理接口,以满足 runbook 实际要求的操作。三份清单,三类受众,三个信任级别。
常见的错误是搭建一个扁平的私有网段,并假定 VPN 边界会解决其余问题。在这个网段内部,能访问客户端端口的应用通常也能访问内网端口,而运维人员的管理工具往往与应用位于同一台跳板机上。把这些都压平在一起,意味着一个被攻破的应用身份已经比它自己的查询拥有更大的可达范围。在设计文档中把三类受众画成三行,每一行配上允许它的规则,缺口就会在任何人动手搭建之前显现出来。
客户端需要什么,以及仅此而已
按已部署版本允许预期的应用来源访问客户端端点,并把无关的集群与管理服务排除在该范围之外。然后检查驱动如何发现节点。一个可达的初始接触点并不能证明驱动随后选择的每个节点地址都能从该客户端环境访问,因为驱动会向集群询问对等节点,然后连接集群所公布的地址。
正因如此,一处私有地址不匹配就会产生那种熟悉的模式:第一次连接成功,随后超时。请有意地配置对外公布的地址和客户端路由;为了修复一处不匹配而把整个集群发布到互联网,是用一个路由缺陷换回一次无法撤回的暴露。
同时保留应用的数据库认证与角色权限。一个共享的、经过转换的 VPN 地址可能代表许多用户或服务,因此它永远不能替代彼此独立的数据库身份。
分别加密客户端到节点与内网通信
Apache 的 安全文档 把客户端到节点加密与内网加密视为彼此独立的配置,启用其中一个并不会启用另一个。这一区分在 VPN 内部依然成立,因为隧道保护的是它自己的网段,并不会自动从应用进程延伸到数据库进程,也不会覆盖集群成员的每一对组合。
一个显式开启两者的配置,而不是继承模板默认值,大致如下:
client_encryption_options:
enabled: true
optional: false
server_encryption_options:
internode_encryption: all在允许可选客户端加密的服务器配置上,接受 TLS 可以与接受未加密连接并存,所以要读实际生效的策略,而不是意图。为每个客户端真正访问的端点规划证书名称、信任分发与续期;把主机名换成 IP 地址会改变客户端的身份校验,而不只是路由。
把管理留在它自己的通道上
内网流量需要被允许的对等节点集合以及它自己的保护策略。管理访问,包括使用时的 JMX,需要独立的受众和独立的认证。一个被允许发出普通查询的应用并不因此需要全部管理能力,而反过来更糟:暴露给应用网段的管理通道,是从一个缺陷走到一次重建的最短路径。请分别写下这两类受众,并指明各自的负责人,因为它们通常是被意外合并了规则的不同团队。
让实际生效的云规则、主机规则与监听器配置保持一致。私有监听器仍可能通过非预期的转换或代理暴露出来,而一条宽泛的公网规则可以安静地躺在一条狭窄的 VPN 规则旁边,直到有人同时审计两者。
在运维人员确实需要管理通道的地方,给它指定负责人,并让凭据有效期比应用的更短。这样当下一个人接手集群时,这项委托依然可见。
设计所承诺的内容
用真实角色而不只是连通性测试来验证这三项承诺。被批准的应用应当完成被允许的工作,不多做任何事;被排除的来源应当在客户端入口处失败;应用身份应当在保留的管理通道上被拒绝。把客户端重连与节点选择加入同一次上线测试,因为发现类错误正是在那里浮现。
在设计文档中用三句话收尾:哪些客户端可以查询,哪些节点可以通信,哪些运维人员可以管理。身处 VPN 之后是有用的拓扑信息,但它并不是这三个问题中任何一个的答案。