【问题标题】:Securely storing secrets of a Spring Boot application in HashiCorp Vault?在 HashiCorp Vault 中安全地存储 Spring Boot 应用程序的秘密?
【发布时间】:2020-06-28 15:03:03
【问题描述】:

我已阅读以下教程:Vault Configuration

好的,我们安装了 Vault 服务器并放置了 2 对秘密属性:

$ vault kv put secret/gs-vault-config example.username=demouser example.password=demopassword
$ vault kv put secret/gs-vault-config/cloud example.username=clouduser example.password=cloudpassword

Spring boot 应用具有以下属性(bootstrap.properties):

spring.application.name=gs-vault-config
spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true

所以基于spring.cloud.vault.token 应用程序能够读取安全属性(名称和密码),但spring.cloud.vault.token 存储在不安全的地方 - bootstrap.properties 存储在代码存储库中。你能解释一下为什么它是安全的吗?

附言

我们发现它不安全。如何使其安全?我知道可能有多种解决方案可以确保其安全,但一个简化的示例对我来说就足够了。

【问题讨论】:

  • 为什么你的令牌存储在不安全的地方?
  • @f1sh 据我所知,Vault 是一个安全的地方,但 github 存储库不是一个安全的地方。要使用(从应用程序连接)安全 Vault,我需要知道令牌,并且此令牌存储在 github

标签: java spring spring-boot hashicorp-vault spring-cloud-vault-config


【解决方案1】:

您能解释一下为什么它是安全的吗?

答案是不安全......如果你这样做。例如,Spring Vault reference manual 表示:

“请仔细考虑您的安全要求。如果您想快速开始使用 Vault,则可以使用静态令牌身份验证,但不会进一步保护静态令牌。任何向非预期方的披露都允许 Vault 与关联的令牌角色一起使用。”

您应该保护您的静态令牌,或者只授予他们访问保险库中您很高兴广为人知的“秘密”的权限。

或者,让您的应用程序使用authenticated method 来生成短期动态令牌。


据我了解,最初的问题是将密码存储在 Github 上的 application.properties 文件中是不好的。

在 Github 上的 application.properties 文件中存储静态 Vault 令牌同样糟糕。

有什么区别?

几乎没有区别1。这简直是​​使用 Vault 的错误方式。


1 - 有一个小优势,如果您发现令牌意外泄漏,您可以使令牌无效。但这并不意味着故意发布它是明智的。


那么你如何安全地做事呢?

首先,您必须保护将要使用机密的机器。即使您不打算将实际机密存储在磁盘上,您也需要在每台机器上(安全地)存储不同的机密,以便它们可以在保存真实机密的地方验证自己的身份。

这是一个使用 Chef 的示例。

  1. 设置一个安全的 Chef 服务器来保存您机器的配置;即所有需要安装的东西的配方,节点描述说明要应用哪些配方等。

  2. 当您将机器作为节点引导时,会为机器生成一个密钥对并注册到 Chef 服务器。密钥对也保存在机器上,并且必须安全保存。

  3. 然后您使用 Chef 客户端运行用于安装和配置您的服务器的配方。

请注意,这依赖于具有适当保护的系统来运行 Chef 服务器。它还依赖于每个节点都足够安全来保护自己的密钥。

还有其他方法可以做到这一点,但如果您不能充分保护您的主机,则任何事情都不会奏效。

【讨论】:

  • 那么 Vault + static token 与 spring cloud confing + spring cloud bus 相比没有额外的意义?因此,它只是作为分布式集中财产来源。正确吗?如何安全存储秘密?
  • 无法避免必须保持安全的某些秘密(私钥、密码、静态令牌、物理设备、指纹或视网膜扫描等)。 Vault(和类似的)的优点是您可以更好/更安全地存储秘密,并且您可以更好地控制谁/什么可以访问它们。
  • 您能解释一下为什么使用 Vault 可以更安全地存储秘密吗?据我了解最初的问题,将密码存储在guthub的application.properties中是不好的。好的 - 我们将 Vault 令牌存储在 Guthub 中并将属性移动到 Vault 中,而不是在 Guthub 中拥有属性。如果黑客知道令牌,他可以轻松地从 Vault 中读取所有属性。有什么区别?
  • 您能否澄清一下您的说法您应该保护您的静态令牌,或者只授予他们访问您很高兴广为人知的保险库中“秘密”的权限。
  • 无论如何我不明白我必须在哪里存储 Vault 令牌?是否有任何最佳实践来实现它?我必须手动为每个环境设置秘密吗?
【解决方案2】:

spring.cloud.vault.token 存储在已签入 VCS(例如 Git)的 application.properties 中可能会危及存储在 Vault 中的所有机密。

解决方案是不要将 Vault 令牌作为纯文本存储在 application.properties 中。有几种选择。

application.properties 中删除 Vault 令牌

只需从application.properties 中删除spring.cloud.vault.token,而是通过系统属性-Dspring.cloud.vault.token=00000000-0000-0000-0000-000000000000(启动应用程序时)或环境变量SPRING_CLOUD_VAULT_TOKEN 提供它。如果您使用容器(Docker 或 Kubernetes),环境变量特别方便。

将加密的 Vault 令牌存储在 application.properties

您可以将spring.cloud.vault.token 属性保留在application.properties 中,如果它是加密的。

Spring Cloud Config支持解密以{cipher}开头的属性:

spring.cloud.vault.token={cipher}encrypted_vault_token

要使用属性加密和解密,您需要以下依赖项(Gradle 示例):

implementation 'org.springframework.cloud:spring-cloud-context:2.2.2.RELEASE'
implementation 'org.bouncycastle:bcprov-jdk15on:1.64'

对称加密

加密属性的最简单方法是使用对称加密。

想出一个对称密钥(例如s3cr3t)。

要加密 Vault 令牌,您可以使用 Spring Boot CLISpring Boot Cloud CLI

curl "https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.2.2.RELEASE/spring-boot-cli-2.2.2.RELEASE-bin.tar.gz" -o spring-boot-cli-bin.tar.gz
tar -xf spring-boot-cli-bin.tar.gz
cd spring-2.2.2.RELEASE
bin/spring install org.springframework.cloud:spring-cloud-cli:2.2.1.RELEASE

bin/spring encrypt 00000000-0000-0000-0000-000000000000 --key s3cr3t
# 507cd1614682535ab8237b448ca73dc74058d3ae9145d63a7381ee67f3046eb1598da6960abdbf2dbf22c47206db5222e45fc74fd6122bc707b61c62f5051e0f

bin/spring decrypt 507cd1614682535ab8237b448ca73dc74058d3ae9145d63a7381ee67f3046eb1598da6960abdbf2dbf22c47206db5222e45fc74fd6122bc707b61c62f5051e0f --key s3cr3t
# 00000000-0000-0000-0000-000000000000

将对称密钥传递给ENCRYPT_KEY 环境变量中的应用程序。

绝对不能将对称加密密钥签入 VCS。

非对称加密

考虑使用公钥和私钥对的非对称加密作为对称加密的更安全替代方案。

您需要生成一个密钥库,而不是对称加密密钥(使用 JDK 附带的 keytool 实用程序或 openssl)。

bootstrap.properties 中指定以下属性:

  • encrypt.keyStore.location
  • encrypt.keyStore.password
  • encrypt.keyStore.alias
  • encrypt.keyStore.type

密钥库必须安装在encrypt.keyStore.location 中指定的位置,并且从不签入 VCS。

另外,解锁密钥库的密码最好传入ENCRYPT_KEYSTORE_PASSWORD 环境变量。

在 Spring Cloud Config 中了解 key management

【讨论】:

  • 但在所有方法中,都有密码或密钥或必须安全存储的东西。你无法解决这个问题。
  • 最简单的解决方案是不要存储主密码并仅将其保留在您的脑海中。或者将其存储在 AWS Secrets Manager 等安全地方,但手动提供。
  • 该解决方案不适合生产。如果您在系统重新启动时无法输入密码,则不起作用。如果你被绿色公共汽车撞到,那就不行了。
  • 一切都取决于部署的完成方式。任务是将主密码作为环境变量传递。在 Kubernetes 上,您可以使用主密码手动创建 Secret 并将其绑定到环境变量。此解决方案适用于重新启动。如果您被公共汽车撞到,将主密码存储在 AWS Secrets Manager 中可以解决问题。
【解决方案3】:

回答您的问题

您能解释一下为什么它是安全的吗?

这不安全!永远不要在源代码管理中公开秘密。

我们发现它不安全。如何保证安全?

提高安全性的一些方法:

  • 使用环境变量而不是属性文件;
  • 将网络级别对 Vault 服务器的访问仅限于工作负载服务器。这保证了该网络之外的任何人都不能交换令牌;
  • 每次使用令牌时,保险柜都会生成真实但临时的凭据。尽可能将真实凭据的范围缩小为只读;
  • 定期轮换令牌。

关于 Spring 的细节

引导属性应仅包含非关键属性。对于关键属性,您可以使用环境变量将它们传递给应用程序。

spring.cloud.vault.token = ${SPRING_CLOUD_VAULT_TOKEN}

总结

问题仍然是“谁看守钥匙?”。但 Vault 令牌实际上用于保护真正的敏感数据。如果保管库令牌泄露,您可以只使令牌无效。

改进应用程序可以访问保险库服务器的限制并减少真实凭据的范围是确保只有运行应用程序的服务器才能通过真实凭据交换令牌并且真实凭据具有最低限度的额外方法尽可能的特权。

【讨论】:

    猜你喜欢
    • 2017-12-18
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2019-04-01
    • 1970-01-01
    • 2021-11-17
    • 2020-04-28
    相关资源
    最近更新 更多