最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

民生银行 OpenStack 安全加固探索与实践

  • 2019-04-30
  • 本文字数:6105 字

    阅读完需:约 20 分钟

民生银行OpenStack安全加固探索与实践

1 前言

在构建企业私有云时,除了平台的功能性和稳定性,安全性也是非常重要的因素,尤其对于银行业,数据中心以及监管部门对平台的安全性要求更高。


OpenStack 是 IaaS 的开源实现,经过几年的发展,OpenStack 的功能越来越完善,运行也越来越稳定,目前已经成为企业构建私有 IaaS 云的主流选择之一。


民生银行从 2016 年就开始研究和使用 OpenStack 了,不仅积累了大量的 OpenStack 云平台开发和运维经验,还针对 OpenStack 平台的安全性进行了探索与研究,对社区 OpenStack 进行了大量的安全加固优化,本文接下来将详细分享我们针对开源 OpenStack 的安全加固优化方案。

2 配置文件明文密码加密

2.1 为什么明文密码需要加密

密码是非常重要的敏感数据,一旦密码被泄露,系统就有可能被非授权人员利用导致信息泄露、篡改,因此密码的安全性保障是企业的重中之重工作。避免在服务器上保存文本明文密码是防止密码泄露的有效手段之一,对于银行业来说,也是监管部门的硬性要求之一。


目前我们已基于开源 OpenStack 构建了多套 IaaS 云平台,社区 OpenStack 配置文件使用的都是明文密码存储,存在巨大的安全隐患,社区针对这个问题也有讨论,参考社区邮件列表[1]。不过至今社区还没有现成的配置文件密码加密方案,但已经在尝试使用 Secrets Management 管理密码,如 Castellan,详细文档可参考社区关于 secrets-management 的讨论[2],不过该方案离完全实现可能还需要一段时间。


然而由于我们线上系统的安全要求,我们对配置文件密码加密具有更迫切的需求,不得不在社区方案实现前完成 OpenStack 密码安全加固,对明文密码进行整改,对配置文件包含的所有敏感数据进行加密处理。

2.2 OpenStack 明文加密思路

对 OpenStack 配置文件进行加密的工具很多,但要 OpenStack 支持密文,修改源码不可避免。为了降低代码变更造成的风险,我们确立的三大原则是:


  • 尽量少的修改原有代码;

  • 对原有系统尽量少的侵入;

  • 避免交叉模块代码修改。


好在 OpenStack 具有良好的松耦合设计理念,虽然线上 OpenStack 环境涉及 Keystone、Glance、Nova、Cinder、Neutron、Heat 等多个项目,不同的项目关联不同的配置文件以及不同的配置项,但所有的配置文件读取都是通过 Oslo.config 库读取的。


关于 Oslo 库,OpenStack 不同项目中存在很多相同的功能,比如连接数据库、连接消息队列、线程池管理、配置读取等,因此早期 OpenStack 开发者经常从一个项目的代码拷贝到另一个项目去,导致 OpenStack 项目存在大量的重复代码。为了解决这个问题,OpenStack 社区从 Bexar 版本开始决定剥离这些公共功能组件形成共享公共库,不过进展一直很缓慢,直到 Grizzly 版本指派 PTL 专门负责公共库项目,并正式采用 Oslo 这个项目名称,从此吸引大量的开发者加入 Oslo 项目的开发以及 OpenStack 项目代码 Oslo 化改造,Oslo 成为了承载 OpenStack 核心组件的基石,更多关于 OpenStack Oslo 可参考官方文档[3]。


而 Oslo.config 就是 Oslo 中负责 OpenStack 配置管理的子模块,包括配置项的声明、校验、解析等,因此只要我们解决了 Oslo.config 读取密文问题,也就解决了 OpenStack 所有项目的配置加密问题,完全不需要涉及 OpenStack 其他项目的代码修改,从而大大减少了代码的侵入面。

2.3 哪些配置项需要加密

接下来我们需要解决的问题是要区分哪些配置项是敏感数据。我们分析了 OpenStack 的配置文件,发现虽然 OpenStack 的项目众多,配置文件分散,但涉及的敏感数据基本可以分为如下三类:


  • Keystone 认证密码。主要用于 OpenStack 各个组件内部认证使用的账号密码,如 keystone_authtoken 配置组的 admin_password 配置项。

  • 数据库密码。OpenStack 组件连接数据的密码,如 database 配置组的 connection 配置项。

  • 消息队列连接密码。OpenStack 组件连接消息队列 RabbitMQ 的密码,如 rabbit_password 或者 transport_url 配置项。


这些配置项虽然分散在各个项目的不同配置文件,但所有敏感配置项都是相同并且所有敏感配置项可枚举,因此我们可以建立一个敏感配置项字典集,把所有敏感的配置项放在这个字典集中。读取配置时,如果配置项在这个字典中,则先解密再返回,否则无需解密直接返回。未来如果有新的敏感配置项引入,只需要修改字典文件即可,无需再修改代码,符合软件工程中的开放封闭设计原则。


Oslo.config 读取配置项的模块为 oslo_config.cfg.ConfigOpts 的_get()方法,因此我们只需要修改该方法,嵌入加密配置项解密代码即可:


def _get(self, name, group=None, namespace=None):    # ...省略其它代码    try:        if namespace is not None:            raise KeyError
return self.__cache[key] # 配置项没有缓存 except KeyError: value = self._do_get(name, group, namespace) if key in self._encrypted_opts: value = self.decrypt_value(value) # 解密 self.__cache[key] = value # 加入缓存 return value
复制代码

2.4 如何加密

解决了在哪里加密以及哪些配置项需要加密的问题,最后需要解决的问题就是如何加密,即加密算法的选择。我们选择了 AES 加密算法,该算法是对称密钥加密中最流行的算法之一,AES 加密在当前计算机计算能力下暴力破解的可能几乎为 0,符合加密强度要求。


由于 AES 加密后是一串二进制,为了能够以文本字符的形式保存到配置文件,我们把密文编码为 base64。


OpenStack 在解密时需要读取加密时的密钥,密钥如何安全保存又是一个问题,一旦密钥泄露,密码还是可能被攻破。解决这个问题的最根本的办法是压根不保存密钥。我们在加密和 OpenStack 解密过程中只需要使用一套相同的自定义规则生成密钥,密钥不需要保存在本地,OpenStack 组件启动时动态自动生成即可。


综上,我们实现的加密过程如下:


  1. 基于自定义规则生成密钥 K;

  2. 输入明文 T;

  3. 对输入的 T 以及生成的 K 进行 AES 加密,生成密文 D;

  4. 对密文 D 转化为 base64 编码 B;

  5. 输出 B。


如上过程通过外部脚本执行。


OpenStack 组件启动时读取配置解密过程如下:


  1. 基于自定义规则生成密钥 K;

  2. 读取配置项 C;如果配置项 C 的 key 是敏感配置项,执行 3,否则跳到 5;

  3. 对配置项的 value 进行 base64 解码,转化为密文 D;

  4. 使用生成的 K,对密文 D 进行解密,生成明文 T,value = T;

  5. 输出明文 value。


我们使用了 Python 的 PyCrypto 库实现 AES 加解密,其中解密的部分代码实现如下:


def decrypt_value(self, enc):    enc = base64.b64decode(enc) # 解码base64    iv = enc[:AES.block_size] # 使用密文前缀作为随机初始化向量    cipher = AES.new(self.key, AES.MODE_CBC, iv)    dec = cipher.decrypt(enc[AES.block_size:])    return self._unpad(dec).decode('utf-8')
@staticmethoddef _unpad(s): return s[:-ord(s[len(s)-1:])]
复制代码


代码补丁开发完毕后,我们在测试环境下对补丁进行了充分验证后完成上线,目前平台已经顺利完成明文密码整改并稳定运行。

3 计算节点 VNC 加密

3.1 OpenStack 虚拟机 VNC 简介

虚拟机的 VNC 是非常重要的功能,类似于物理服务器的带外 console,能够不依赖于虚拟机操作系统的网络进行远程访问与控制。当虚拟机操作系统出现故障或者网络不通时,往往需要通过 VNC 进行远程连接修复。


OpenStack 原生支持 Web VNC 功能,用户可通过 Nova API 获取虚拟机的 VNC 链接,VNC 链接会带上一个授权的临时 Token。用户访问 Web VNC 时其实访问的是 Nova 的 nova-novncproxy 服务,nova-novncproxy 会首先检查 Token 是否有效,如果有效则会转发到对应虚拟机所在计算节点监听的 VNC 地址,否则连接将会被强制阻断。


因此,用户通过 OpenStack 平台访问虚拟机 VNC 是安全的,能够有效阻止非授权人员通过端口扫描非法访问 VNC。


然而,原生 OpenStack 的 Libvirt Driver 目前还没有实现 VNC 连接密码认证功能,意味着非法人员可以不需要任何认证直接连接计算节点绕过 OpenStack 访问虚拟机 VNC,利用 VNC 可发送电源指令或者 Ctrl+Alt+Delete 指令重启虚拟机并进入单用户模式,绕过操作系统 root 认证直接登录虚拟机,这显然存在巨大的安全隐患。


社区针对这个问题也有讨论,但一直没有实现,参考社区 bug #1450294[4]。

3.2 VNC 加密优化

针对如上 OpenStack 虚拟机没有配置 VNC 密码问题,我们对 OpenStack 进行了二次开发,增加了 password 参数配置 VNC 密码,核心代码如下:


@staticmethoddef _guest_add_video_device(guest):    # ...    if CONF.vnc.enabled and guest.virt_type not in ('lxc', 'uml'):        graphics = vconfig.LibvirtConfigGuestGraphics()        graphics.type = "vnc"        if CONF.vnc.keymap:            graphics.keymap = CONF.vnc.keymap        if CONF.vnc.vnc_password:            graphics.password = CONF.vnc.vnc_password        graphics.listen = CONF.vnc.server_listen        guest.add_device(graphics)        add_video_driver = True   # ...    return add_video_driver
复制代码


如上实现了新创建虚拟机添加 VNC 密码功能,但是对正在运行的虚拟机并无影响,如果要使 VNC 密码生效必须重启虚拟机。但由于我们线上环境已经有业务在运行,重启虚拟机意味着必须中断业务,这显然不能接受。虚拟机不重启如何让其重刷配置呢?我们自然想到了虚拟机热迁移办法,虚拟机从一个宿主机热迁移到另一个宿主机,理论上会重新生成虚拟机配置,而又几乎对业务无影响。


然而当我们在测试环境上验证时发现虚拟机在线迁移并不会更新配置,于是我们又分析了虚拟机在线迁移的流程,发现在源端更新 xml 配置文件时没有添加 VNC 密码,该功能代码位于 nova/virt/libvirt/migration.py 的_update_graphics_xml( )方法:


def _update_graphics_xml(xml_doc, migrate_data):    listen_addrs = graphics_listen_addrs(migrate_data)
# change over listen addresses for dev in xml_doc.findall('./devices/graphics'): gr_type = dev.get('type') listen_tag = dev.find('listen') if gr_type in ('vnc', 'spice'): if listen_tag is not None: listen_tag.set('address', listen_addrs[gr_type]) if dev.get('listen') is not None: dev.set('listen', listen_addrs[gr_type]) return xml_doc
复制代码


我们修改了该方法实现,增加了 VNC 密码的更新,经过验证,所有虚拟机通过在线迁移方法增加了 VNC 密码认证功能。

3.3 用户 VNC 连接

前面提到用户是通过 Nova 的 novncproxy 代理访问虚拟机 VNC 的,novncproxy 北向接收用户请求,南向连接计算节点的 VNC server,由于我们的 VNC server 增加了密码认证功能,因此 novncproxy 就无法直接连接 VNC server 了。


由于 VNC 使用了 RFB(Remote Frame Buffer)协议进行数据传输,我们对 RFB 协议进行了研究,通过重写(overwrite)(nova/console/websocketproxy.py 的 do_proxy 方法,实现 VNC 密码的代填功能,从而实现用户能够沿用原有的方式通过 OpenStack 标准 API 访问虚拟机 VNC,该部分实现准备在下一篇文章中进行详细介绍。

4 OpenStack 平台加固措施

4.1 服务访问策略控制

OpenStack 依赖很多公共组件服务,如数据库、消息队列、缓存服务等,这些服务是 OpenStack 的内部服务,通常不允许外部直接访问,安全访问控制非常重要,否则可能被非法访问导致信息泄露,甚至通过 webshell 进行主机攻击。


以 Memcached 服务为例,OpenStack 利用 Memcached 存储了 Keystone 认证 Token、VNC 链接等缓存的敏感数据。


由于 Memcached 未对安全做更多设计,导致客户端连接 Memcached 服务后无需任何认证即可读取、修改服务器缓存内容。


# 导出Memcached数据,192.168.0.0/24为OpenStack管理网平面memcached-tool 192.168.0.4:11211 dump 
复制代码


同时,由于 Memcached 中数据和正常用户访问变量一样会被后端代码处理,当处理代码存在缺陷时,将可能导致不同类型的安全问题,比如 SQL 注入。


为了规避如上安全风险,我们通过 iptables 对访问来源进行严格限制,只允许 OpenStack 控制节点访问,其他源一律阻断访问。


iptables -A INPUT -s 192.168.0.1 -p tcp --dport 11211 -j ACCEPTiptables -A INPUT -s 192.168.0.2 -p tcp --dport 11211 -j ACCEPTiptables -A INPUT -s 192.168.0.3 -p tcp --dport 11211 -j ACCEPT# ... 其他控制节点iptables -A INPUT -p tcp --dport 11211 -j DROP
复制代码


其他服务如 mysql、rabbitmq 等,也做了类似的操作,尽可能缩小服务开放范围,最小权限控制。

4.2 源码和配置文件安全

为了确保密码的安全性,除了对配置文件的密码加密,还需要对配置文件的权限进行严格控制,禁止非授权用户读取,我们线上的所有配置文件均设置了仅 root 用户可读权限。


另外由于 OpenStack 是基于 Python 解释性语言编写的,源码的安全性也非常重要,需要对代码的读写权限进行严格地安全管控,避免非法人员通过断点注入方式截取密码等数据,因此我们线上的源码也同样设置了仅 root 可读写权限。

4.3 API SSL 加密

OpenStack 提供了 internal、admin、public 三种类型的 endpoint,通常 OpenStack 内部组件间通信会使用 internal endpoint,比如 Nova 向 Glance 获取镜像信息,向 Neutron 获取网络信息等,内部 endpoint 通常不对外开放。用户访问 OpenStack API 时通常使用 public endpoint,因此 public endpoint 通常是对外开放的,必须对其进行严格安全防控。


我们对 public endpoint 进行了 SSL 加密,只允许通过 https 协议访问 OpenStack API,保证数据传输的安全性。

5 总结

本文首先介绍了我们私有云的构建情况,引入私有云安全的重要性,然后详细介绍了我们针对开源 OpenStack 的安全加固优化措施,包括配置文件信息加密、VNC 密码认证等,最后介绍了我们针对 OpenStack 平台的安全加固方案,如对 OpenStack 内部服务访问进行严格控制以及配置文件和源码的读写权限设置等。


参考资料


  1. OpenStack 社区讨论明文密码加密的邮件列表:http://lists.openstack.org/pipermail/openstack-dev/2016-April/093358.html

  2. “secrets-management: passwords-in-config-files”: https://docs.openstack.org/security-guide/secrets-management/secrets-management-use-cases.html

  3. Oslo 官方文档: https://docs.openstack.org/project-team-guide/oslo.html

  4. OpenStack 社区 vnc 无密码认证问题讨论:https://bugs.launchpad.net/nova/+bug/1450294

作者介绍

  • 付广平:任职民生银行云技术管理中心,负责云计算相关技术研究。毕业于北京邮电大学,从 2013 开始从事 OpenStack 相关工作,参与了 OpenStack Nova、Cinder、Oslo 等项目社区开发,知乎专栏《OpenStack》作者。对 Ceph、Docker 等技术也有一定的了解。

  • 崔增顺:任职民生银行云技术管理中心,目前致力于 IaaS 云平台工作,熟悉服务器/操作系统/存储等。

  • 蔡泽宇:任职民生银行云技术管理中心,毕业于北京邮电大学,目前致力于民生银行 IaaS 运维相关工作,熟悉 Python、Shell 等编程语言。

  • 刘文静:任职民生银行云技术管理中心,目前主要致力于民生银行云管平台建设和运维工作。


2019-04-30 08:0012927

评论 1 条评论

发布
用户头像
通过vnc访问客户机时填写的客户机用户名密码是通过websocket协议传输,是否有被抓包截取的风险?
2019-06-03 17:11
回复
没有更多了
发现更多内容

GOPS现场 | 对话龙智技术顾问,分享DevOps观察与心得

龙智—DevSecOps解决方案

运维 DevOps工具链

区块链NFT网站开发:NFT数字藏品网站开发

开源直播系统源码

NFT 数字藏品 数字藏品系统

我们总结了弹性伸缩的五个条件与六个教训

阿里巴巴云原生

阿里云 分布式 云原生 弹性伸缩

基于GitLab CI的kubectl镜像配置

白粥

gitlab k8s gitlab ci kubectl

【荣耀开发者服务平台—百亿曝光扶持等你来】智慧服务内容接口卡片接入指南

荣耀开发者服务平台

手机 激励 卡片服务 厂商 honor

深圳web前端技术培训学习费用

小谷哥

惠州等保测评机构有几家?电话多少?

行云管家

等保 等级保护 等级测评 惠州

个推TechDay直播回顾 | 分享基于Flink的实时数仓搭建秘诀 附课件下载

个推

数据湖 实时数仓 flink window 数仓建设 大数据仓库

设计模式的艺术 第二十二章观察者设计模式练习(开发一款实时在线股票软件。该软件需要提供如下功能:当股票购买者所购买的某只股票价格变化幅度达到5%时,系统将自动发送通知(包括新价格)给购买该股票的所有股民。试使用观察者模式设计并实现该系统)

代廉洁

新零售标杆 SKG 全面拥抱 Serverless,实现敏捷交付

阿里巴巴中间件

阿里云 Serverless 云原生

Docker 向全面集成 containerd 又迈进一步

张晓辉

Docker 容器 Containerd

版本管理 | 如何解决SVN的合并冲突与分支问题?

龙智—DevSecOps解决方案

svn 版本管理

测试管理 | 龙智获得Xray专家认证

龙智—DevSecOps解决方案

Jira插件

LED屏幕有色差要怎么办?

Dylan

LED显示屏 户外LED显示屏 led显示屏厂家

最后 3 天|报名参加 OpenYurt+EdgeX 挑战赛 ,冲击最高 5 万元奖励!

阿里巴巴云原生

阿里云 云原生 openyurt EdgeX

我用 极狐 Gitlab issue 来点菜 #JIHULAB 101

朱亚光

JIHULAB 101

亚信科技、清华AIR、英特尔成功举办WAIC智能算网与绿色计算论坛

亚信AntDB数据库

数据库 AntDB 国产数据库 AntDB数据库

在Java培训机构中怎么学习?

小谷哥

设计模式的艺术 第九章适配器设计模式练习(OA系统需要提供一个加密模块,将用户机密信息(例如口令、邮箱)加密再存储在数据库,系统已经定义好数据库操作类。为了提高开发效率,现需要重用已有的加密算法,这些算法封装在一些由第三方提供的类中,有些甚至没有源代码)

代廉洁

设计模式的艺术

深度操作系统20.7正式发布!

深度操作系统

国产操作系统 deepin 深度操作系统 深度 deepin20.7

硅谷名企、国内大厂是如何度量研发效能的?|ONES 研发管理大师课

万事ONES

北京哪家WEB前端培训机构比较不错

小谷哥

零基础如何参加大数据培训机构?

小谷哥

Alibaba最新发布!耗时182天肝出来1028页分布式全栈手册太香了

了不起的程序猿

Java 阿里巴巴 分布式 java程序员

CI/CD | 大型企业与开发团队如何进行持续集成与持续发布

龙智—DevSecOps解决方案

持续集成 CI/CD 持续发布

国产操作系统应用小程序化:夯实技术底座,促进生态发展

Speedoooo

小程序 国产操作系统 小程序容器

设备健康管理在石化行业的探索与实践

PreMaint

预测性维护 设备健康管理

个推TechDay直播回顾 | 分享基于Flink的实时数仓搭建秘诀

个推

数据变更白屏化利器-推送轨迹上线

阿里巴巴云原生

zookeeper 阿里云 开源 微服务 云原生

2022最新BATJ等一线互联网大厂秋招面试题汇总,速刷

程序知音

Java 程序员面试 后端技术 Java面试题 Java面试八股文

上海WEB前端培训机构有什么推荐的

小谷哥

民生银行OpenStack安全加固探索与实践_行业深度_民生运维_InfoQ精选文章