在本系列的第一篇文章中,我们介绍了几种提高SSL私钥安全性的方法。文章最后演示了如何使用远程密码分发点(PDP),与NGINX实例安全共享加密密码。
密钥管理系统(例如HashiCorp Vault)的运行方式与该示例PDP类似:
- 它们使用集中式(或高可用的分布式)密钥服务,并通过HTTPS或其他API进行访问
- 客户端通过身份验证令牌或其他方式进行身份验证
- 可根据需要撤销令牌,以控制对密钥的访问
本文将介绍如何设置HashiCorp Vault来分发SSL密码。为进一步增强安全性,可以设置外部硬件安全模块(HSM)。
要彻底避免将SSL证书和密钥对存储在磁盘上,请参阅本系列的第3篇文章《使用NGINX Plus键值存储保护来自HashiCorp Vault的临时SSL密钥》。该文章介绍了如何从HashiCorp Vault生成临时SSL密钥,并将其存储在NGINX Plus键值存储的内存中。
本文同时适用于NGINX Open Source和NGINX Plus。为便于阅读,下文将统一简称为“NGINX”。
使用HashiCorp Vault保护SSL私钥
本节说明如何使用Vault设置中央PDP服务器,以分发SSL密码。这些说明基于DigitalOcean的说明;请根据需要进行修改,以符合您自己的Vault策略。
在本示例中,每台远程Web服务器都有唯一的身份验证令牌。这些令牌可用于访问Vault的secret/webservers/路径中的机密信息,SSL密码则存储在secret/webservers/ssl_passwords中。
我们将了解如何保护令牌,以及如何在必要时撤销单个身份验证令牌。
在PDP服务器上下载、安装并初始化HashiCorp Vault
- 按照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
}- 使用启动脚本(如果已创建)启动Vault,或手动启动:
user@pdp:~$ sudo /usr/local/bin/vault server -config=/etc/vault.hcl- 初始化Vault并获取初始根令牌:
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- 在以下许多命令中,都需要提供初始根令牌。为方便起见,我们将其赋值给
root_tokenshell变量:
user@pdp:~$ root_token=86c5c2a4-8ab2-24dd-1816-48449c83114e存储密钥
- 继续在PDP服务器上操作,创建一个名为“/tmp/ssl_passwords.txt”的临时文件,并将密码存入其中。
- 将此文件作为密钥存储在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
...- 为确保安全,请删除/tmp/ssl_passwords.txt。
- 在名为“web.hcl”的文件中创建策略规范,内容如下:
path "secret/webservers/*" {
capabilities = ["read"]
}- 将策略加载到Vault,并将其命名为“
web”:
user@pdp:~$ VAULT_TOKEN=$root_token vault policy write web web.hcl- 创建新的身份验证令牌,将其与
web策略关联,并可选择添加display-name参数,为其指定一个易于识别的名称。请记下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服务器检索secret/webservers/*路径之外的密钥。
验证Web服务器能否检索令牌
- 在NGINX Web服务器上安装Vault二进制文件。
- 声明远程Vault服务器的位置(此处为http://pdp:8200),然后验证Web服务器计算机能否使用令牌检索SSL密码:
user@web1:~$ export VAULT_ADDR=http://pdp:8200user@web1:~$ VAULT_TOKEN=dcf75ffd-a245-860f-6960-dc9e834d3385 vault kv get -field=value secret/webservers/ssl_passwords
password1
password2
...在Web服务器上配置NGINX Vault Connector
- 在第一篇文章中设置示例PDP时,我们在NGINX主机(Web服务器)上创建了一个名为connector.sh的Shell脚本。现在修改该脚本以使用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- 按如下方式调用脚本,使其作为后台进程运行:
root@web1:~# ./connector_v.sh /var/run/nginx/ssl_passwords \dcf75ffd-a245-860f-6960-dc9e834d3385 &- 通过从连接器路径读取数据来测试连接器:
root@web1:~$ cat /var/run/nginx/ssl_passwordspassword1
password2
...- 配置NGINX,使其在启动时读取ssl_passwords文件,并将文件内容用作密码来解密已加密的私钥。可以将
ssl_password_file指令添加到server块中(例如第一篇文章中为标准配置创建的块),也可以添加到http上下文中,以将其应用于多个虚拟服务器:
ssl_password_file /var/run/nginx/ssl_passwords;- 验证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-dc9e834d3385Vault令牌属于敏感数据,许多Vault工作流不会存储向已通过身份验证的客户端颁发的令牌副本。如果令牌副本泄露,攻击者便可冒充该客户端。
通常的做法是改用活动令牌的访问器来管理该令牌。访问器仅提供对令牌的有限权限,无法用于检索令牌值。因此,令牌签发后无需存储令牌本身,而应存储其对应的访问器。
如果需要确定Web服务器身份验证令牌的访问器,请运行vault list命令以获取访问器列表,然后对每个访问器运行vault token lookup命令,找出具有相关显示名称和策略的访问器:
user@pdp:~$ VAULT_TOKEN=$root_token vault list /auth/token/accessors
Keys
----
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-b70cfa264048
Key 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配置为使用供应商提供的“伪”密钥。此密钥包含一个句柄,用于标识HSM设备上的真实密钥:
ssl_certificate_key ssl/vendor.private.key;- 密钥还可能包含用于访问HSM设备的凭据,也可以通过其他供应商特定配置提供这些凭据。
- (可选)根据需要进行调优,例如增加NGINX工作进程的数量,以充分发挥NGINX和HSM的性能。
有关HSM设置示例,请参阅Amazon CloudHSM文档。
安全影响
外部HSM是一种安全性很高的SSL私钥存储方式。拥有NGINX服务器root访问权限的攻击者可以利用NGINX凭据,通过HSM解密任意数据,但无法获取未加密的私钥。HSM会显著增加攻击者冒充网站或离线解密任意数据的难度。
结论
必须确保SSL私钥等机密数据得到充分保护,因为一旦泄露,后果将非常严重。
对于许多已实施适当安全流程的组织,将私钥存储在前端负载均衡器上,并限制和审计对这些服务器的所有访问,就足以满足安全要求(即第一篇文章中所述的“标准配置”)。
对于需要频繁部署NGINX配置的组织,可以采用本文和第一篇文章中介绍的措施,限制可查看私钥数据的用户或实体。
在本系列的第3篇文章使用NGINX Plus键值存储保护HashiCorp Vault中的临时SSL密钥中,我们将介绍如何使用NGINX Plus API,自动将Vault中的密钥和证书配置到NGINX Plus的键值存储中。
再次提醒,这些方法都不能降低全面保护正在运行的NGINX实例的必要性,仍需防止远程访问或配置篡改。
亲自体验NGINX Plus,立即开始30天免费试用,或联系我们,探讨您的使用场景。
关于作者

相关博客文章
NGINX Plus R26 正式发布
NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。
使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。
Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。
NGINX Plus R19 正式发布
NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。
NGINX现已正式加入F5
NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。
