在本系列的第一篇文章中,我们介绍了几种提高 SSL 私钥安全性的方法。 该帖子最后演示了用于与 NGINX 实例安全地共享加密密码的远程密码分发点 (PDP)。
诸如HashiCorp Vault之类的机密管理系统的运行方式与该示例 PDP 类似:
在这篇文章中,我们展示了如何设置 HashiCorp Vault 来分发 SSL 密码。 为了提高安全性,您可以设置外部硬件安全模块(HSM)。
要完全消除 SSL 证书密钥对的磁盘存储,请参阅本系列的第三篇文章《使用 NGINX Plus 键值存储从 HashiCorp Vault 保护临时 SSL 密钥》 。 它解释了如何从 HashiCorp Vault 生成临时 SSL 密钥并将它们存储在 NGINX Plus 键值存储的内存中。
这篇文章适用于 NGINX Open Source 和 NGINX Plus。 为了方便阅读,我们将始终引用NGINX 。
本节中的说明使用 Vault 设置中央 PDP 服务器来分发 SSL 密码。 它们基于DigitalOcean 的指示;根据需要修改它们以符合您自己的 Vault 政策。
在我们的示例中,每个远程 Web 服务器都有一个唯一的身份验证令牌。 这些令牌可用于访问 Vault 的secret/webservers/路径中的秘密,我们将 SSL 密码存储在secret/webservers/ssl_passwords中。
我们将了解如何保护令牌,以及如何在必要时撤销单个身份验证令牌。
按照DigitalOcean 的说明在您的 PDP 服务器上下载并提取 Vault。 我们使用以下示例/etc/vault.hcl文件使 Vault 可远程访问,并禁用 TLS(以便在测试时轻松使用):
后端“文件”{路径 =“/var/lib/vault”
监听器“tcp”{
地址 =“0.0.0.0:8200”
tls_disable = 1
}
使用启动脚本(如果您创建了它们)或手动启动 Vault:
用户@pdp:~$ sudo /usr/local/bin/vault server -config=/etc/vault.hcl
初始化 Vault 并获取初始根令牌:
用户@pdp:~$ export VAULT_ADDR=http://localhost:8200用户@pdp:~$ vault init -key-shares=3 -key-threshold=2用户@pdp:~$ vault operator 解封初始根令牌: 86c5c2a4-8ab2-24dd-1816-48449c83114e
我们需要在以下许多命令中提供初始根令牌。 为了方便起见,我们将其分配给root_token
shell 变量:
用户@pdp:~$ root_token=86c5c2a4-8ab2-24dd-1816-48449c83114e
继续在 PDP 服务器上工作,创建一个名为/tmp/ssl_passwords.txt的临时文件,其中包含密码。
将此文件作为机密存储在 Vault 中,并验证您是否可以检索它:
用户@pdp:~$ VAULT_TOKEN=$root_token vault kv put secret/webservers/ssl_passwords value=@/tmp/ssl_passwords.txt用户@pdp:~$ VAULT_TOKEN=$root_token vault kv get -field=value secret/webservers/ssl_passwords password1 password2 ...
为了安全起见,请删除/tmp/ssl_passwords.txt 。
在名为web.hcl的文件中创建策略规范,其内容如下:
路径“secret/webservers/*”{
capabilities = ["read"]
}
将策略加载到 Vault,并将其命名为web
:
用户@pdp:~$ VAULT_TOKEN=$root_token 保险库策略写入 web web.hcl
创建一个新的身份验证令牌,将其与Web
策略关联,并可选择包含显示名称
参数以赋予其一个用户友好的名称。 记下token
和token_accessor
的值;您将在后续命令中使用它们:
用户@pdp:~$ VAULT_TOKEN=$root_token vault token create -policy=web -display-name=webserver1键值 --- ----- token dcf75ffd-a245-860f-6960-dc9e834d3385 token_accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
NGINX 网络服务器使用此令牌来检索 SSL 密码。 Web
策略阻止 Web 服务器检索secret/webservers/*路径之外的机密。
声明远程 Vault 服务器的位置(此处为http://pdp:8200 ),然后验证 Web 服务器计算机是否可以使用令牌检索 SSL 密码:
用户@web1:~$ export VAULT_ADDR=http://pdp:8200用户@web1:~$ VAULT_TOKEN=dcf75ffd-a245-860f-6960-dc9e834d3385 vault kv get -field=value secret/webservers/ssl_passwords password1 password2 ...
作为第一篇文章中设置示例 PDP 的一部分,我们在 NGINX 主机(Web 服务器机器)上创建了一个名为Connector.sh的 shell 脚本。 这里我们对其进行修改以使用 Vault:
#!/bin/sh
# 用法: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 # 竞争条件,确保 EOF
done
将脚本作为后台进程运行,调用方式如下:
root@web1:~# ./connector_v.sh /var/run/nginx/ssl_passwords \dcf75ffd-a245-860f-6960-dc9e834d3385 &
通过读取连接器路径来测试连接器:
root@web1:~$ cat /var/run/nginx/ssl_passwords密码1 密码2...
配置 NGINX 在启动时读取ssl_passwords文件,并使用其中的内容作为密码来解密加密的私钥。 您可以在服务器
块(例如,在第一篇文章中为标准配置创建的服务器块)或http
上下文中包含ssl_password_file
指令,以将其应用于多个虚拟服务器:
ssl_password_文件/var/run/nginx/ssl_passwords;
验证 NGINX 是否可以读取密码并解密 SSL 密钥:
root@web1:~# nginx -t nginx: 配置文件 /etc/nginx/nginx.conf 语法正确 nginx: 配置文件 /etc/nginx/nginx.conf 测试成功
如果 Web 服务器受到威胁或者已退役,您可以轻松撤销访问权限。 为此,您可以直接撤销 Web 服务器使用的身份验证令牌:
用户@pdp:~$ VAULT_TOKEN=$root_token 保险库令牌撤销 dcf75ffd-a245-860f-6960-dc9e834d3385
Vault 令牌是敏感数据项,许多 Vault 工作流程不会存储颁发给经过身份验证的客户端的令牌的副本。 如果令牌的副本被泄露,攻击者可以冒充客户端。
相反,通常使用其访问者来管理活动令牌,这为令牌赋予了有限的权限,并且不能用于检索令牌值。 不要在发出令牌时存储它们,而是存储其相应的访问者。
如果需要确定 Web 服务器身份验证令牌的访问者,请运行vault
list
命令来检索访问者列表,并在每个访问者上运行vault
token
lookup
命令来查找具有相关显示名称和策略的访问者:
user@pdp:~$ VAULT_TOKEN=$root_token 保管库列表 /auth/token/accessors密钥 ---- 83be5a73-9025-1221-cb70-4b0e8a3ba8df 0c1d6181-7adf-7b42-27be-b70cfa264048 f043b145-7a63-01db-ea85-9f22f413c55e user@pdp:~$ VAULT_TOKEN=$root_token 保管库令牌查找 -accessor 0c1d6181-7adf-7b42-27be-b70cfa264048密钥值 --- ----- ... display-name webserver1 ... policy web ...
然后您可以使用其访问器撤销该令牌:
用户@pdp:~$ VAULT_TOKEN=$root_token 保险库令牌撤销-accessor 0c1d6181-7adf-7b42-27be-b70cfa264048
使用 Vault 具有与第一篇文章中描述的示例 PDP 类似的安全配置文件。 只有获得相应的密码才能获得 SSL 私钥,为此,攻击者需要知道当前身份验证令牌的值。
使用 Vault 的主要好处是可以自动化和扩展秘密存储。
当攻击者获得 NGINX 服务器的root
访问权限时,我们在本系列中迄今为止介绍的解决方案都无法保护私钥。 如果攻击者可以访问 NGINX 的运行时内存或生成核心转储,则可以使用众所周知的技术来扫描进程的内存并定位私钥数据。
外部硬件安全模块 (HSM) 通过将 SSL 私钥存储在外部防篡改硬件中来解决此问题。 他们提供解密服务,并且每当 NGINX 需要执行需要密钥的 SSL 操作时,它就会访问该服务。
NGINX 服务器永远看不到 SSL 私钥数据。 获得服务器root
访问权限的攻击者无法获取 SSL 私钥,但可以使用 NGINX 凭证访问 HSM 解密服务来按需解密数据。
NGINX 将所有 SSL 私钥操作委托给名为 OpenSSL 的加密库。 通过使用 HSM 供应商的 OpenSSL 引擎,第三方 HSM 设备可提供给 NGINX。
NGINX 配置特定于每个供应商 HSM,但通常遵循一条简单的路径:
配置 NGINX 以使用供应商的 OpenSSL 引擎而不是默认软件引擎:
ssl_certificate_key引擎:供应商-hsm 引擎:...;
不要使用真正的私钥,而是配置 NGINX 以使用供应商提供的“假”密钥。 此密钥包含一个句柄,用于标识 HSM 设备上的真实密钥:
ssl_certificate_key ssl/供应商.private.key;
密钥可能还包含访问 HSM 设备的凭证,或者可以使用额外的特定于供应商的配置来提供凭证。
(可选)应用任何所需的调整,例如增加 NGINX 工作进程的数量,以最大限度地提高 NGINX 和 HSM 的性能。
有关 HSM 设置的示例,请参阅Amazon 的 CloudHSM 文档。
外部 HSM 是一种存储 SSL 私钥的高度安全的方法。 具有 NGINX 服务器root
访问权限的攻击者能够利用 NGINX 凭据使用 HSM 解密任意数据,但无法获取未加密的私钥。 HSM 使攻击者冒充网站或离线解密任意数据变得更加困难。
确保 SSL 私钥等秘密数据得到充分保护至关重要,因为泄露的后果非常严重。
对于许多具有适当安全流程的组织来说,将私钥存储在前端负载均衡器上,然后限制和审核对这些服务器的所有访问就足够了(第一篇文章中描述的标准配置)。
对于需要频繁部署NGINX配置的组织,可以使用这篇文章和第一篇文章中的措施来限制可以看到私钥数据的用户或实体。
在本系列的第三篇文章中,使用 NGINX Plus 键值存储从 HashiCorp Vault 获取临时 SSL 密钥,我们解释了如何使用NGINX Plus API自动将密钥和证书从 Vault 配置到 NGINX Plus 的键值存储。
请再次注意,这些方法都不能降低对正在运行的 NGINX 实例进行全面保护以防止远程访问或配置操纵的需要。
亲自尝试 NGINX Plus – 立即开始30 天免费试用或联系我们讨论您的用例。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”