使用 HashiCorp Vault 保护 NGINX 中的 SSL 私钥
原文作者:Owen Garrett of F5
原文链接:使用 HashiCorp Vault 保护 NGINX 中的 SSL 私钥
转载来源:NGINX 中文官网
NGINX 唯一中文官方社区 ,尽在nginx.org.cn
在本系列博文的第一篇中,我们介绍了几种提高 SSL 私钥安全性的方法,并在结尾处演示了如何使用远程密码分发点 (PDP) 与 NGINX 实例安全地共享加密密码。
HashiCorp Vault 等密钥管理系统的工作方式与 PDP 示例相似:
-
使用通过 HTTPS 或 API 进行访问的集中式(或高可用、分布式)密钥服务
-
通过身份验证令牌或其他方式对客户进行身份验证
-
可按需撤销令牌,以控制对密钥的访问
在本文中,我们将展示如何设置 HashiCorp Vault 以分发 SSL 密钥。要想进一步加强安全性,您可以设置外部硬件安全模块 (HSM)。
如要彻底清除存储在磁盘上的 SSL 证书密钥对,请参阅本系列博文的第三篇——使用 NGINX Plus 键值存储保护来自 HashiCorp Vault 的临时 SSL 密钥。该文介绍了如何从 Hashicorp Vault 生成临时 SSL 密钥,并将其存储在 NGINX Plus 内存键值存储中。
本文适用于 NGINX 开源版和 NGINX Plus。为了便于阅读,我们把两者统称为 NGINX。
使用 HashiCorp Vault 保护 SSL 私钥
本节说明部分介绍了如何使用 Vault 设置集中式 PDP 服务器,以分发 SSL 密码。这些设置基于 DigitalOcean 说明;可按需进行修改以符合自己的 Vault 策略。
在我们的示例中,每台远程 Web 服务器都拥有一个唯一身份验证令牌。这些令牌可用于访问 Vault secret/webservers/ 路径中的密钥,我们将 SSL 密码存储在 secret/webservers/ssl_passwords 中。
本文将介绍如何保护令牌,以及在必要时如何撤销个人身份验证令牌。
在 PDP 服务器上下载、安装和初始化 HashiCorp Vault
1. 按照 Digitalocean 说明在 PDP 服务器上下载并提取 Vault。使用下列 /etc/vault.hcl 样本文件使 Vault 远程可访问,并禁用 TLS(为方便测试时使用):
backend "file" { path = "/var/lib/vault" } listener "tcp" { address = "0.0.0.0:8200" tls_disable = 1 }
2. 使用启动脚本(如已创建)或手动启动 Vault:
ser@pdp:~$ sudo /usr/local/bin/vault server -config=/etc/vault.hcl
3. 初始化 Vault,并获取初始 root 令牌:
user@pdp:~$ export VAULT_ADDR=http://localhost:8200 user@pdp:~$ vault init -key-shares=3 -key-threshold=2 user@pdp:~$ vault operator unseal Initial Root Token: 86c5c2a4-8ab2-24dd-1816-48449c83114e
4. 我们需要在下列许多命令中都提供初始 root 令牌。为了方便起见,我们将它分配给 root_token shell 变量:
user@pdp:~$ root_token=86c5c2a4-8ab2-24dd-1816-48449c83114e
存储密钥
5. 这个过程仍在 PDP 服务器上运行,创建一个名 /tmp/ssl_passwords.txt 的临时文件,并将密码存储其中;
6. 将此文件作为密钥存储在 Vault 中,并验证能否检索该文件:
user@pdp:~$ VAULT_TOKEN=$root_token vault kv put secret/webservers/ssl_passwords value=@/tmp/ssl_passwords.txt user@pdp:~$ VAULT_TOKEN=$root_token vault kv get -field=value secret/webservers/ssl_passwords password1 password2 ...
7. 为了安全起见,删除 /tmp/ssl_passwords.txt。
8. 在名为 web.hcl 的文件中创建策略规范,并在该文件中包含以下内容:
path "secret/webservers/*" { capabilities = ["read"] }
9. 将策略加载到 Vault 中,并将其命名为 web
:
user@pdp:~$ VAULT_TOKEN=$root_token vault policy write web web.hcl
10. 新建身份验证令牌,将其与 web
策略相关联,可以选择设置 display-name
参数以指定一个方便用户记住的名称如 webserver1。将 token
和 token_accessor
值记录下来,以供在后续命令中使用:
user@pdp:~$ VAULT_TOKEN=$root_token vault token create -policy=web -display-name=webserver1 Key Value --- ----- token dcf75ffd-a245-860f-6960-dc9e834d3385 token_accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
NGINX Web 服务器使用此令牌来检索 SSL 密码。该 web
策略阻止 Web 服务
验证 Web 服务器能否检索令牌
1. 仍在 NGINX Web 服务器上运行,安装 Vault 二进制文件。
2. 声明远程 Vault 服务器的位置(在这里是 http://pdp:8200),然后验证 Web 服务器能否使用下列令牌检索 SSL 密码:
user@web1:~$ export VAULT_ADDR=http://pdp:8200 user@web1:~$ VAULT_TOKEN=dcf75ffd-a245-860f-6960-dc9e834d3385 vault kv get -field=value secret/webservers/ssl_passwords password1 password2 ...
在 Web 服务器上配置 NGINX Vault Connector
3. 在第一篇博文中的 PDP 示例设置部分,我们在 NGINX 主机(Web 服务器)上创建了一个名为 connector.sh 的脚本。在这里,我们将其修改以使用 Vault:
#!/bin/sh # Usage: connector_v.sh CONNECTOR=$1 CREDS=$2 [ -e $CONNECTOR ] && /bin/rm -f $CONNECTOR mkfifo $CONNECTOR; chmod 600 $CONNECTOR export VAULT_ADDR=http://pdp:8200 export VAULT_TOKEN=$CREDS while true; do vault kv get -field=value secret/webservers/ssl_passwords > $CONNECTOR sleep 0.1 # race condition, ensures EOF done
4. 将脚本作为后台进程运行,调用代码如下所示:
root@web1:~# ./connector_v.sh /var/run/nginx/ssl_passwords \ dcf75ffd-a245-860f-6960-dc9e834d3385 &
5. 通过读取连接器路径,测试连接器:
root@web1:~$ cat /var/run/nginx/ssl_passwords password1 password2 ...
6. 将 NGINX 配置为启动时读取 ssl_passwords 文件,并将文件内容用作解密加密私钥的密码。可通过在 server
代码块(就像在第一篇博文中为 标准配置所创建的)或者 http
上下文中引用 ssl_password_file 指令,将其应用于多台虚拟服务器:
ssl_password_file /var/run/nginx/ssl_passwords;
7. 验证 NGINX 能否读取密码并解密 SSL 密钥:
root@web1:~# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
撤销 Web 服务器的身份验证令牌
当 Web 服务器遭到攻击或被淘汰时,可轻松撤销访问权限。可直接撤销 Web 服务器所使用的身份验证令牌:
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke dcf75ffd-a245-860f-6960-dc9e834d3385
Vault 令牌是敏感的数据项,对于发放给经过身份验证的客户端的令牌,许多 Vault 工作流都不存储其副本。如能窃取这些令牌的副本,攻击者就可以冒充客户端。
相反,通常使用令牌访问器来管理活跃令牌,令牌访问器可限制令牌权限,但无法检索令牌值。令牌发放之后,不存储令牌,而是存储其相应的访问器。Token Accessors:创建令牌时,会同时创建并返回令牌访问器。此访问器是一个值,用作对令牌的引用,并且只能用于执行有限的操作。
如需确定 Web 服务器身份验证令牌的访问器,则运行 vault
list
命令以检索访问器列表,并在每个访问器上运行 vault
token
lookup
命令以查找具有相关显示名称和策略的访问器:
user@pdp:~$ VAULT_TOKEN=$root_token vault list /auth/token/accessorsKeys ---- 83be5a73-9025-1221-cb70-4b0e8a3ba8df 0c1d6181-7adf-7b42-27be-b70cfa264048 f043b145-7a63-01db-ea85-9f22f413c55e user@pdp:~$ VAULT_TOKEN=$root_token vault token lookup -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048Key Value --- ----- ... display-name webserver1 ... policy web ...
然后,可使用相应访问器撤销令牌:
user@pdp:~$ VAULT_TOKEN=$root_token vault token revoke -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
安全隐患
Vault 与第一篇博文中所述的 PDP 示例具有类似的安全隐患。只能在获得相应的密码后才能获得 SSL 私钥,因此攻击者需要知道当前身份验证令牌的值。
使用 Vault 的最大优势在于能够自动配置和扩展密钥存储。
使用外部 HSM 管理私钥
一旦攻击者获得对 NGINX 服务器的 root
权限,迄今为止,我们在本系列里所介绍的解决方案都无法为私钥提供有效的保护。如果攻击者可以访问 NGINX 的运行时内存或生成核心转储,则可通过已知技术扫描该进程的内存并定位私钥数据。
外部硬件安全模块 (HSM) 通过将 SSL 私钥存储在外部防篡改硬件中来解决此问题。它们提供解密即服务,当 NGINX 需要执行要求提供密钥的 SSL 操作时就会访问该服务。
NGINX 服务器从不查看 SSL 私钥数据。获取服务器 root
权限的攻击者无法获得 SSL 私钥,但可通过使用 NGINX 凭证访问 HSM 解密服务,根据需要解密数据。
将 NGINX 配置为访问 HSM
NGINX 将全部 SSL 私钥操作都委派给一个名为 OpenSSL 的加密库。可使用 HSM 厂商的 OpenSSL 引擎为 NGINX 提供第三方 HSM 设备。
NGINX 配置对于每个厂商 HSM 会有一些差别,但通常遵循一条简单的路径:
-
将 NGINX 配置为使用厂商的 OpenSSL 引擎,而不是默认软件引擎:
ssl_certificate_key engine:vendor-hsm-engine:...;
-
与其使用真实私钥,不如将 NGINX 配置为使用厂商提供的“虚假”密钥。该密钥包含一个 handle,可在 HSM 设备上识别真实密钥:
ssl_certificate_key ssl/vendor.private.key;
该密钥还可以包含用于访问 HSM 设备的凭证,也可以使用其他厂商特定配置提供凭证。
-
(可选)按需执行任何调整,例如增加 NGINX 工作进程的数量,以最大程度地提高 NGINX 和 HSM 的性能。
如欲查看 HSM 设置示例,请参阅 Amazon CloudHSM 文档。
安全隐患
外部 HSM 是一种高度安全的 SSL 私钥存储方法。在使用 HSM 的情况下,拥有 NGINX 服务器 root
权限的攻击者可利用 NGINX 凭证解密任意数据,但无法获取未加密的私钥。HSM 可显著增加攻击者冒充网站或离线解密任意数据的难度。
结语
必须确保 SSL 私钥等密钥数据得到充分保护,因为如果这些数据遭到泄露,会造成非常严重的后果。
对于许多拥有适当安全流程的组织来说,只需将私钥存储在前端负载均衡器,然后限制并审计对这些服务器的访问即可(第一篇博文中描述的标准配置)。
对于需要频繁部署 NGINX 配置的组织来说,则可以结合使用本文中所介绍的措施以及上述第一种方法来限制可查看私钥数据的用户或实体。
在本系列博文的第三篇使用 Nginx Plus 键值存储保护来自 Hashicorp Vault 的临时 SSL 密钥中,我们介绍了如何使用 NGINX Plus API 自动将密钥和证书从 Vault 配置到 NGINX Plus 键值存储。
再次提醒,即便采用这些方法,也需要全面保护 NGINX 运行实例免遭远程访问或配置操纵。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
GaussDB数据库使用COPY命令导数
目录 一、前言 二、GaussDB数据库使用COPY命令导数语法 1、语法COPY FROM 2、语法COPY TO 3、特别说明及参数示意 三、GaussDB数据库使用COPY命令导数示例 1、操作步骤 2、准备工作(示例) 3、把一个表的数据拷贝到一个文件(示例) 4、从一个数据文件拷贝数据到一个表(示例) 四、常见数据导入导出的场景 五、小结 一、前言 在数字化时代,数据是驱动业务决策和创新的关键要素。数据库作为数据存储、管理和分析的核心工具,其高效、准确的数据导入功能至关重要。 GaussDB作为华为推出的高性能数据库,提供了丰富的数据导入选项,其中之一便是COPY命令。COPY命令为数据迁移、备份恢复、大数据加载等场景提供了一个高效且灵活的手段。通过COPY命令,用户可以将外部文件、数据流或其他数据源的数据快速导入到GaussDB中,从而支持业务分析、报表生成、数据挖掘等多样化需求。 二、GaussDB数据库使用COPY命令导数语法 通过COPY命令实现在表和文件之间拷贝。在GaussDB中,COPY FROM从一个文件拷贝数据到一个表,COPY TO把一个表的数据拷贝到一个...
- 下一篇
基于Netty开发轻量级RPC框架
笔者在开发基于客户端/服务端模式通信的插件的时候,需要用到轻量级最小包依赖的RPC框架,而市面上的RPC框架份量过于庞大,最终打包下来都是几十兆甚至上百兆,而这里面大多数功能我都用不上,于是思来想去我决定写一款属于自己的轻量级RPC框架,简单易用快速接入。 关于技术选型 协议序列化/反序列化 网络通信基于TCP/IP为基础自定义应用层协议,常见的序列化/反序列化工具有java原生序列化,json,kryo,protobuf,fst,hessian等。 在不考虑跨语言的情况下,从序列化时长/序列化大小/易用性/扩展性这几方面考虑,综合性比较强的是kryo,但是kryo只支持java版本不能跨语言(据说能跨语言但是非常复杂,相当于不能跨语言了),protobuf是性能最强的且支持跨语言,但是需要事先基于proto生成一个类,这会导致所有序列化和反序列化的时候只能用proto定义的类型。 最终选择kryo和protobuf两种序列化工具,使用的时候可选序列化类型,前者序列化几乎不受限制,后者支持跨语言,但是必须事先生成proto类型的类并使用其作为序列化工具。 通信框架使用 高性能异步非阻塞...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS6,CentOS7官方镜像安装Oracle11G
- Mario游戏-低调大师作品
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS关闭SELinux安全模块
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果