java - 在 Spring Boot 中存储证书的最佳实践是什么?
问题描述
我在网上看到的每一个教程都向我展示了如何在 spring boot 中设置 HTTPS,只需在 application.conf 文件中指定密钥库路径和密码,例如此链接中的 1.4 。我可以做到这一点并很好地设置 HTTPS。
但是,这对我来说似乎很脏。这意味着密钥库和密码都存储在源代码中,我不想这样做。到目前为止,我所做的是我创建了自己的自定义 tomcat 配置,就像这样,并从环境变量中提供了密码。这是一个很好的第一步,但我仍然需要将密钥库保存在源代码中。这足够了吗?还是我还能做些什么?
解决方案
像所有其他指南一样,他们说诸如“不要在源代码中保留密钥库”之类的话,而没有提供有关如何这样做的任何建议。我知道我不应该将密钥库保存在 git、docker、jars 中……但是我如何将它们分开?我应该使用什么工具?
无论如何,这是重要的东西(如果有人可以扩展简短建议的解决方案,那就太好了):
保护您的密钥库和密钥密码(我已经这样做了)
通常,密钥库密码以开放文本形式存储在各种配置文件中。
例如,这是一个典型的 Tomcat 连接器配置:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
keystoreFile="${catalina.home}/conf/keystore.p12"
keystorePass="mypass" keyPass="mypass"
keyAlias="main-key"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
/>
从安全的角度来看,这显然是完全不能接受的。
将敏感的秘密保存在其他地方,最好使用秘密管理器,如 Hashicorp 保险库。至少,主密码可以存储在适当保护帐户的环境变量中。保持私钥分开
将私钥保存在单独的密钥库文件中,不要将相同的密钥库用于信任证书和密钥。必须使用文件系统权限保护带有密钥的密钥库。它还必须使用复杂的密码进行保护。带有密钥的密钥库必须只包含密钥/证书对和 CA(如果需要),仅此而已。
为密钥库设置限制性文件权限(我已经这样做了)
将密钥库文件的权限设置为只读。用于运行应用程序的帐户应该是文件的所有者。
chown account_id keystore_file_name
chmod 400 keystore_file_name
只保留活动密钥/证书(我已经这样做了)
确保密钥库仅包含活动密钥、证书和 CA 链。过期的证书,未使用的 CAS 必须删除。
这需要实施一个定期清理密钥库的过程,或者作为每个应用程序发布的一部分。
不要在 Jar 文件/应用程序存档文件中打包密钥库
开发人员经常将密钥库文件与所有其他应用程序资源捆绑在一起,因此它们最终位于应用程序类路径中,然后自动拾取我的 Maven/Gradle 构建工具并添加到 Jar 文件中。
这使得在需要时难以更新密钥/证书。密钥/证书可以(并且应该)在不同于应用程序生命周期的生命周期中更新。因此,将它们保存在应用程序存档之外是一个好主意——这允许完全独立于应用程序本身更新密钥库。
即使有一个真正的持续交付流程并且应用程序代码更新非常频繁,从打包的角度来看,将密钥库与应用程序分离仍然是值得的,这样密钥库可以在发生违规时快速更新。
这也意味着密钥库的部署工具链应该与常规应用程序部署工具链分开。换句话说,密钥库应该被视为一个完全独立的部署工件,独立于应用程序。
不要在 Docker 容器中打包密钥库
密钥库和 PEM 文件应放置在外部 docker 卷上,以便在不修改 docker 映像的情况下更新它们。这允许在安全漏洞或常规密钥/证书轮换/刷新的情况下独立于 docker 映像更新密钥库。
可以简单地在主机上替换外部卷上的文件,然后可以重新启动 docker 容器(或多个容器)。
如果在同一主机上运行多个 docker 容器,它们都可以与密钥库共享同一个卷。
不要在应用程序 Git 存储库中存储密钥库
所有密钥和秘密都必须与源代码分离并单独存储。不同环境的单独密钥库
生产环境必须始终拥有自己的专用密钥库文件。对密钥库使用 PKCS12 格式
PKCS12 与其他工具兼容,例如 openSSL。它是 Java 9 及更高版本的默认值,但必须为以前的 Java 版本显式设置。
推荐阅读
- html - 带有下拉菜单的 2 部分响应式 HTML 和 CSS 导航
- azure-devops - 用于 Web 应用程序的 VSTS 堆栈
- swift - 选择播放设备后如何隐藏播放弹出窗口?
- ios - 串行队列 API 多个服务调用
- c++ - LoadLibrary 失败 - 找不到指定的模块
- c# - 将 IWeb 元素从一个列表移动到另一个列表并使用 Selenium 比较它们的计数?
- visual-studio - 统一的意外符号无效
- javascript - 使用 Javascript dom 代替 jQuery 元素选择器(没有 jQuery)
- ios - 如何从 Swift 类中检索 ObjectiveC 类中的 Userdefault?
- android - 带有 Android Switch 的 RxView