Vault从入门到精通系列之五:Transit Secrets Engine
- 一、Transit Secrets Engine
- 二、工作集管理
- 三、NIST 轮换指南
- 四、Key类型
- 五、融合加密
- 六、部署
- 七、使用
- 八、自带钥匙 (BYOK)
一、Transit Secrets Engine
- 传输机密引擎处理传输中数据的加密功能。 Vault 不存储发送到机密引擎的数据。也可以将其视为“密码学即服务”或“加密即服务”。 transit secrets 引擎还可以对数据进行签名和验证;生成数据的散列和 HMAC;并充当随机字节的来源。
- 传输的主要用例是加密来自应用程序的数据,同时仍将加密数据存储在一些主要数据存储中。这减轻了应用程序开发人员进行适当加密/解密的负担,并将负担推给了 Vault 的操作员。
- 支持密钥派生,通过基于用户提供的上下文值派生新密钥,允许将同一密钥用于多种用途。在这种模式下,可以选择支持收敛加密,允许相同的输入值产生相同的密文。
- 数据密钥生成允许进程请求返回给定位长度的高熵密钥,并使用命名密钥加密。通常这也会以明文形式返回密钥以允许立即使用,但可以禁用它以满足审计要求。
二、工作集管理
- Transit 引擎支持密钥的版本控制。早于密钥指定的 min_decryption_version 的密钥版本被存档,其余密钥版本属于工作集。这是保持密钥快速加载的性能考虑,也是安全考虑:通过不允许解密旧版本密钥,发现大多数用户无法解密与过时(但敏感)数据对应的密文,但在紧急情况下min_decryption_version 可以移回以允许合法解密。
- 当前,此存档存储在单个存储条目中。对于某些存储后端,特别是那些使用 Raft 或 Paxos 实现 HA 功能的后端,频繁轮换可能会导致存档的存储条目大小大于存储后端可以处理的大小。对于频繁的轮换需求,使用与时间范围相对应的命名键(例如,五分钟的时间段为最接近的五的倍数)可能是一个很好的选择,允许多个键同时生效,并以一种确定性的方式来决定哪个键在任何给定时间使用。
三、NIST 轮换指南
- 建议定期轮换加密密钥,即使在没有妥协的情况下也是如此。对于 AES-GCM 密钥,按照 NIST 出版物 800-38D 的指导方针,旋转应该在密钥版本执行大约 232 次加密之前发生。建议操作员估计密钥的加密率,并使用它来确定防止达到指导限制的轮换频率。例如,如果确定估计速率为每天 4000 万次操作,则每三个月轮换一次密钥就足够了。
四、Key类型
截至目前,transit secrets 引擎支持以下密钥类型(所有密钥类型也会生成单独的 HMAC 密钥):
- aes128-gcm96:具有 128 位 AES 密钥和 96 位随机数的 AES-GCM;支持加密、解密、密钥派生、收敛加密
- aes256-gcm96:具有 256 位 AES 密钥和 96 位随机数的 AES-GCM;支持加密、解密、密钥派生、收敛加密(默认)
- chacha20-poly1305:带有 256 位密钥的 ChaCha20-Poly1305;支持加密、解密、密钥派生、收敛加密
- ed25519:Ed25519;支持签名、签名验证和密钥派生
- ecdsa-p256:使用曲线 P-256 的 ECDSA;支持签名和签名验证
- ecdsa-p384:使用曲线 P-384 的 ECDSA;支持签名和签名验证
- ecdsa-p521:使用曲线 P-521 的 ECDSA;支持签名和签名验证
- rsa-2048:2048 位 RSA 密钥;支持加密、解密、签名、验签
- rsa-3072:3072 位 RSA 密钥;支持加密、解密、签名、验签
- rsa-4096:4096 位 RSA 密钥;支持加密、解密、签名、验签
- hmac: HMAC;支持 HMAC 生成和验证。
- managed_key:托管密钥;支持多种操作,具体取决于后备密钥管理解决方案。有关详细信息,请参阅托管密钥。
注意:在 FIPS 140-2 模式下,以下算法未经认证,因此不应使用:chacha20-poly1305 和 ed25519。
注意:所有密钥类型都通过使用第二个随机生成的密钥创建密钥创建时间或轮换来支持 HMAC 操作。 HMAC 密钥类型仅支持 HMAC,并且在 HMAC 操作方面与其他算法的行为相同,但支持密钥导入。默认情况下,HMAC 密钥类型使用 256 位密钥。
RSA 操作使用以下方法之一:
- OAEP(加密、解密),具有 SHA-256 哈希函数和 MGF,
- PSS(签名、验证),具有也用于 MGF 的可配置哈希函数,以及
- PKCS#1v1.5:(签名、验证),具有可配置的散列函数。
五、融合加密
- 收敛加密是一种相同的明文+上下文集合总是产生相同密文的模式。它通过使用密钥派生函数派生密钥以及确定性地派生随机数来实现这一点。由于这些属性对于大小为 2^256 的密钥空间上的明文和密文的任意组合都不同,因此随机数重用的风险接近于零。
- 这有很多实际用途。一种常见的使用模式是允许将值加密存储在数据库中,但具有有限的查找/查询支持,以便可以从查询返回特定字段具有相同值的行。
为了适应任何需要的算法升级,历史上支持不同版本的融合加密:
- 版本 1 要求客户端提供他们自己的随机数,这种方式非常灵活,但如果操作不当可能会很危险。这仅在 Vault 0.6.1 中,使用此版本的密钥无法升级。
- 版本 2 使用算法方法来导出参数。但是,所使用的算法容易受到离线明文确认攻击,如果明文较小,攻击者可能会暴力破解。使用版本 2 的密钥可以通过简单地执行到新密钥版本的旋转操作来升级;然后可以根据新密钥版本重新包装现有值,并将使用版本 3 算法。
- 版本 3 使用不同的算法来抵抗离线明文确认攻击。它类似于 AES-SIV,因为它使用 PRF 从明文生成随机数。
六、部署
大多数秘密引擎必须提前配置才能执行其功能。这些步骤通常由操作员或配置管理工具完成。
启用 Transit 秘密引擎:
vault secrets enable transit
Success! Enabled the transit secrets engine at: transit/
默认情况下,秘密引擎将安装在引擎的名称上。要在不同的路径启用秘密引擎,请使用 -path 参数。
创建一个命名的加密密钥:
vault write -f transit/keys/my-key
Success! Data written to: transit/keys/my-key
通常每个应用程序都有自己的加密密钥。
七、使用
在配置了秘密引擎并且用户/机器拥有具有适当权限的 Vault 令牌后,它可以使用这个秘密引擎。
1.使用带有命名密钥的 /encrypt 端点加密一些明文数据:
注意:**所有明文数据都必须采用 base64 编码。之所以有这个要求,是因为 Vault 不要求明文是“文本”。它可以是二进制文件,例如 PDF 或图像。**作为 JSON 有效负载的一部分,此数据最简单的安全传输机制是对其进行 base64 编码。
vault write transit/encrypt/my-key plaintext=$(echo "my secret data" | base64)
Key Value
--- -----
ciphertext vault:v1:54d6PQ5i6jOWL/61cpEB4AKsJlZoJXHAhzhoHGRwLv+GOuweyKzfZQRuLw==
key_version 1
返回的密文以 vault:v1: 开头。第一个前缀 (vault) 标识它已被 Vault 包装。 v1 表示密钥版本 1 用于加密明文;因此,当您轮换密钥时,Vault 知道使用哪个版本进行解密。其余部分是初始化向量 (IV) 和密文的 base64 串联。
请注意,Vault 不存储任何此类数据。调用者负责存储加密后的密文。当调用者想要明文时,它必须将密文提供回 Vault 以解密该值。
Vault HTTP API 规定最大请求大小为 32MB 以防止拒绝服务攻击。这可以在 Vault 服务器配置中针对每个侦听器块进行调整。
2.使用带有命名密钥的 /decrypt 端点解密一段数据:
vault write transit/decrypt/my-key ciphertext=vault:v1:54d6PQ5i6jOWL/61cpEB4AKsJlZoJXHAhzhoHGRwLv+GOuweyKzfZQRuLw==
Key Value
--- -----
plaintext bXkgc2VjcmV0IGRhdGEK
生成的数据是 base64 编码的(有关原因的详细信息,请参阅上面的注释)。对其进行解码以获得原始明文:
base64 --decode <<< "bXkgc2VjcmV0IGRhdGEK"
my secret data
也可以在一个命令中使用一些巧妙的 shell 脚本编写此解密脚本:
vault write -field=plaintext transit/decrypt/my-key ciphertext=vault:v1:54d6PQ5i6jOWL/61cpEB4AKsJlZoJXHAhzhoHGRwLv+GOuweyKzfZQRuLw== | base64 --decode
my secret data
使用 ACL,可以限制传输秘密引擎的使用,以便受信任的操作员可以管理命名密钥,并且应用程序只能使用他们需要访问的命名密钥进行加密或解密。
3.轮换底层加密密钥。这将生成一个新的加密密钥并将其添加到指定密钥的密钥环中:
vault write -f transit/keys/my-key/rotate
Success! Data written to: transit/keys/my-key/rotate
未来的加密将使用这个新密钥。由于使用了密钥环,旧数据仍然可以被解密。
4.将已加密的数据升级为新密钥。 Vault 将使用密钥环中的适当密钥解密该值,然后使用密钥环中的最新密钥加密生成的明文。
vault write transit/rewrap/my-key ciphertext=vault:v1:54d6PQ5i6jOWL/61cpEB4AKsJlZoJXHAhzhoHGRwLv+GOuweyKzfZQRuLw==
Key Value
--- -----
ciphertext vault:v2:fhsQPtZtEns2j7ZXLn28EYWh5NF0tFk9i5fa0jq7qkNsft/ZEFlVook1pg==
key_version 2
此过程不会泄露明文数据。因此,Vault 策略可以授予几乎不受信任的进程“重新包装”加密数据的能力,因为该进程将无法访问明文数据。
八、自带钥匙 (BYOK)
注意:密钥导入功能支持需要从 HSM 或其他外部系统导入现有密钥的情况。让 Transit 在 Vault 中生成和管理密钥更加安全。
首先,需要从传输中读取包装密钥:
vault read transit/wrapping_key
包装密钥将是一个 4096 位 RSA 公钥。
然后包装密钥用于为导入端点创建密文输入,如下所述。在下面,目标密钥是指正在导入的密钥。
HSM
如果密钥是从支持 PKCS#11 的 HSM 导入的,则有两种可能的情况:
- 如果 HSM 支持 CKM_RSA_AES_KEY_WRAP 机制,则可以使用包装密钥来包装目标密钥。
- 否则,可以结合两种机制来包装目标密钥。首先,应生成一个 256 位 AES 密钥,然后使用 CKM_AES_KEY_WRAP_KWP 机制将其用于包装目标密钥。然后,应使用 MGF1 和 SHA-1、SHA-224、SHA-256、SHA-384 或 SHA-512 使用 CKM_RSA_PKCS_OAEP 机制将 AES 密钥包装在包装密钥下。
密文是通过将包装的目标密钥附加到包装的 AES 密钥来构造的。
密文字节应该是 base64 编码的。
手动流程
如果目标密钥未存储在 HSM 或 KMS 中,则可以使用以下步骤为导入端点的输入构造密文:
- 生成一个临时的 256 位 AES 密钥。
- 使用带有 AES-KWP 的临时 AES 密钥包装目标密钥。
注意:包装对称密钥(例如 AES 或 ChaCha20 密钥)时,包装密钥的原始字节。例如,对于 AES 128 位密钥,这将是一个长度为 16 个字符的字节数组,将直接包装而不使用 base64 或其他编码。
包装非对称密钥(例如 RSA 或 ECDSA 密钥)时,以原始 DER/二进制格式包装此密钥的 PKCS8 编码格式。在加密之前不要将 PEM 编码应用于此 blob,也不要对其进行 base64 编码。
- 使用带有 MGF1 和 SHA-1、SHA-224、SHA-256、SHA-384 或 SHA-512 的 RSAES-OAEP 将 AES 密钥包装在 Vault 包装密钥下。
- 删除临时 AES 密钥。
- 将包装的目标密钥附加到包装的 AES 密钥。
- Base64 编码结果。