SpringBoot 配置文件敏感信息加密:从 Jasypt 到生产级 Secret 管理
欢迎你来读这篇博客,这篇博客主要是关于 SpringBoot 配置文件敏感信息加密。
其中包括了关于我的见解和收集的知识分享:为什么配置文件里不能直接放数据库密码、API Key、Redis 密码;Jasypt 如何解决“密文存储、启动解密”的问题;以及在微服务、配置中心、Kubernetes、Vault 等生产环境里,应该如何更稳妥地管理敏感配置。
序言
在 Spring Boot 项目里,application.yml 或 application.properties 通常会保存很多运行配置,例如数据库连接、Redis 地址、MQ 账号、第三方 API Key、短信平台密钥、对象存储密钥等。
开发阶段图方便,很多人会这么写:
1 | |
这当然能跑,但问题也很明显:一旦代码提交到 Git、被打包进镜像、发到测试环境、上传到制品库,密码就会跟着到处裸奔。配置文件不是保险柜,把密码写进去,最多只能算“给小偷整理好了目录”。
所以,配置敏感信息的安全处理,至少要回答三个问题:
- 敏感信息是否应该出现在代码仓库里?
- 如果必须放在配置文件里,能否以密文形式保存?
- 解密密钥、访问凭证、轮换机制应该由谁来管理?
这篇文章从 Spring Boot 常见场景出发,重点讲 Jasypt 的配置加密方案,同时也会补充配置中心、Kubernetes Secret、Vault、云厂商 Secret Manager 等更适合生产环境的方案。
正文
chapter 1:Spring Boot 配置为什么容易泄露敏感信息?
Spring Boot 的配置系统非常灵活。它可以从很多地方读取配置,例如:
application.ymlapplication.propertiesapplication-dev.yml- 环境变量
- JVM 系统属性
- 命令行参数
- 外部配置目录
- 配置中心
- Kubernetes Secret / ConfigMap
- Vault / Secret Manager
灵活是好事,但灵活也意味着风险更分散。
常见泄露场景包括:
配置文件提交到 Git
开发人员把数据库密码、Redis 密码、第三方平台密钥直接写在
application.yml,然后提交到仓库。即便后面删掉,Git 历史里也可能还在。打包进 Jar 或镜像
如果生产密码写在项目资源目录里,它会被一起打进 Jar 包或 Docker 镜像。只要有人拿到制品,就有机会解压看到配置。
日志误打印
有些项目启动时会打印配置对象,或者异常堆栈里带出连接串,敏感信息可能直接进入日志系统。
配置中心权限过大
微服务项目常用 Nacos、Apollo、Spring Cloud Config 等配置中心。如果所有开发、测试、运维人员都能看到生产配置,那配置中心就变成了“密码公告栏”。
密钥和密文放在一起
有人把配置值加密了,但又把解密密钥也写在同一个
application.yml。这就像门上挂了把锁,然后把钥匙贴在门框上。形式上安全,实际上很尴尬。
所以,配置安全的第一原则是:
明文敏感信息不要进入代码仓库,解密密钥不要和密文放在同一个地方。
chapter 2:Jasypt 是什么?
Jasypt,全称 Java Simplified Encryption,是 Java 生态里常用的加解密工具。结合 jasypt-spring-boot-starter 后,它可以让 Spring Boot 在读取配置属性时自动识别密文,并在注入到 Spring Environment 前完成解密。
典型效果是这样:
1 | |
应用启动时,Jasypt 会识别 ENC(...),用指定的解密密钥把里面的密文解开,最终业务代码拿到的仍然是正常的明文值。
也就是说,代码里依旧可以这样使用:
1 | |
或者:
1 | |
业务代码无需关心加解密过程。
这就是 Jasypt 的核心价值:
配置文件里存密文,应用启动时自动解密,业务代码无感知。
chapter 3:Spring Boot 集成 Jasypt
以 Maven 项目为例,先引入依赖。
1 | |
然后在配置文件里设置加密算法和密文识别规则:
1 | |
注意,这里故意没有写:
1 | |
因为 jasypt.encryptor.password 是解密密钥,不能和密文一起放在配置文件中。
更推荐通过环境变量、JVM 参数或启动参数传入:
1 | |
或者:
1 | |
在 Docker 或 Kubernetes 环境里,也可以通过 Secret 注入环境变量。
chapter 4:如何生成密文?
Jasypt 常见有两种方式生成密文。
方式一:写测试类生成密文
可以注入 StringEncryptor:
1 | |
然后将输出结果放进配置文件:
1 | |
这种方式简单,但容易把明文、密文、测试代码混在项目里。临时验证可以,长期使用不优雅。
方式二:使用 jasypt-maven-plugin
可以在 pom.xml 中加入插件:
1 | |
先在配置文件中用 DEC(...) 包住待加密值:
1 | |
执行:
1 | |
插件会把 DEC(...) 转换成 ENC(...):
1 | |
如果只想加密单个值,可以执行:
1 | |
这个方式更适合工程化使用。
chapter 5:Jasypt 的关键安全点
Jasypt 很好用,但别把它当成“万能保险箱”。它解决的是“配置文件密文存储”的问题,不解决所有 Secret 管理问题。
1. 密文可以提交,密钥不能提交
这是底线。
可以提交:
1 | |
不要提交:
1 | |
密文和密钥一旦放在一起,加密就失去了意义。
2. 不同环境使用不同密钥
开发、测试、预发、生产环境应该使用不同的加密密钥。
不要所有环境共用一个 jasypt.encryptor.password。否则测试环境泄露,生产环境也跟着裸奔。
建议:
1 | |
3. 不要在日志中打印敏感配置
尤其是:
- 数据库密码
- Redis 密码
- MQ 密码
- Token
- SecretKey
- AccessKey
- RefreshToken
- 私钥内容
建议对配置对象的 toString() 做脱敏,或者禁止敏感字段打印。
示例:
1 | |
日志里宁可少一点,也别把公司数据库密码“直播”出去。
4. 注意 Actuator 暴露风险
Spring Boot Actuator 的 /env、/configprops 等端点可能暴露配置信息。生产环境要谨慎开放。
建议:
1 | |
不要随手暴露所有端点:
1 | |
这属于“门开着,狗还帮你摇尾巴迎客”。
5. 定期轮换密钥
加密密钥不是祖传玉玺,不能一用十年。
一旦人员离职、仓库泄露、CI/CD 变量泄露、配置中心权限异常,都应该考虑轮换密钥。
Jasypt 轮换密钥的一般思路是:
- 用旧密钥解密旧配置。
- 用新密钥重新加密配置。
- 更新部署环境中的解密密钥。
- 重启或滚动发布服务。
- 删除旧密钥。
chapter 6:Jasypt 适合什么场景?
Jasypt 适合以下场景:
单体 Spring Boot 应用
项目不复杂,配置主要在
application.yml中,使用 Jasypt 可以快速避免明文密码入库。中小型后台系统
没有复杂的 Secret 管理平台,但又不希望配置中心或 Git 仓库里直接出现明文密码。
遗留系统改造
老项目里已经有大量配置文件,短期内无法接入 Vault 或云厂商 Secret Manager,可以先用 Jasypt 做一层改造。
本地开发和测试环境
对安全有要求,但暂时不想引入完整的密钥管理基础设施。
但如果是更复杂的生产系统,尤其是微服务、多环境、多租户、多团队协作,就不能只依赖 Jasypt。
chapter 7:配置中心场景应该怎么做?
在微服务体系里,配置常常放在 Nacos、Apollo、Spring Cloud Config 等配置中心。
这时要区分两个问题:
- 配置中心里是否允许存明文?
- 应用启动后如何拿到明文?
如果使用 Spring Cloud Config,它本身支持 {cipher} 形式的加密配置。配置仓库中可以保存:
1 | |
Config Server 读取后会先解密,再把明文配置发给客户端。
它的好处是:
- Git 仓库里不是明文。
- 加解密集中在 Config Server。
- 客户端不需要每个服务都维护解密逻辑。
但是也要注意:
- Config Server 的加密密钥必须保护好。
/encrypt、/decrypt端点必须加认证和访问控制。- 不要让所有人都能调用解密接口。
- 配置中心和配置仓库权限要分级。
如果使用 Nacos 或 Apollo,常见做法有两种:
第一种是配置中心保存 Jasypt 密文,应用侧用 Jasypt 解密。
1 | |
第二种是配置中心或平台侧提供加密插件、密文管理、权限控制。
实际落地时,我更推荐按照团队成熟度选择:
- 小团队:Jasypt + 环境变量密钥。
- 中型团队:配置中心 + Jasypt + 权限隔离。
- 大型团队:配置中心只放非敏感配置,敏感信息交给 Vault、KMS、Secret Manager。
chapter 8:Kubernetes 场景:Secret 不是终点
在 Kubernetes 中,可以使用 Secret 保存密码、Token、证书等敏感数据。
例如:
1 | |
然后在 Deployment 中注入环境变量:
1 | |
Spring Boot 可以自动把环境变量绑定到配置项:
1 | |
也可以把 Secret 挂载为文件,然后通过 Spring Boot 的 configtree: 读取。
例如:
1 | |
这种方式适合 Docker Secret、Kubernetes Secret Volume 等场景。
不过要注意,Kubernetes Secret 默认并不等于绝对安全。它更像是 Kubernetes 原生的敏感信息承载对象,而不是完整的密钥管理系统。生产环境至少要考虑:
- etcd 加密存储。
- RBAC 最小权限。
- 禁止无关 Pod 读取 Secret。
- 限制 namespace 权限。
- 尽量通过 Volume 挂载而不是 API 读取。
- 高安全场景接入外部 Secret Store。
chapter 9:Vault / Secret Manager:更生产级的方案
当系统规模变大后,Jasypt 的短板会越来越明显:
- 密钥轮换麻烦。
- 谁能解密不容易审计。
- 密钥生命周期不够清晰。
- 多服务、多环境、多团队管理复杂。
- 无法很好支持动态凭证。
这时可以考虑使用:
- HashiCorp Vault
- AWS Secrets Manager
- Azure Key Vault
- Google Secret Manager
- 阿里云 KMS / 凭据管家
- 腾讯云 KMS / 凭据管理
以 Vault 为例,Spring Cloud Vault 可以通过 spring.config.import 引入 Vault 中的配置:
1 | |
这样应用启动时会从 Vault 拉取配置,敏感信息不需要写进 application.yml。
Vault 这类工具的核心价值不是“把字符串加密一下”,而是完整的 Secret 生命周期管理:
- 集中存储。
- 权限控制。
- 审计日志。
- 动态凭证。
- 自动续租。
- 密钥轮换。
- 凭证吊销。
如果项目已经上云,云厂商 Secret Manager 也很适合。比如 AWS Secrets Manager 可以保存数据库账号、API Key 等,并支持自动轮换和按需读取。
chapter 10:不同方案怎么选?
可以按复杂度分层选择。
1. 个人项目 / 小型后台
推荐:
1 | |
示例:
1 | |
优点是简单、直接、不引入额外依赖。
2. 已经有明文配置的老项目
推荐:
1 | |
改造成本低,业务代码基本无感知。
3. 使用配置中心的微服务
推荐:
1 | |
重点是做好配置中心权限隔离,不要让所有人都能看生产配置。
4. Kubernetes 部署
推荐:
1 | |
如果安全要求更高,可以接入 External Secrets Operator 或 Secret Store CSI Driver。
5. 金融、支付、SaaS 多租户、强合规系统
推荐:
1 | |
这种场景不要只靠 Jasypt。Jasypt 是工具,不是治理体系。
chapter 11:一个推荐落地方案
如果现在有一个普通 Spring Boot / Spring Cloud 项目,我会这样落地:
本地开发环境
.env 或本机环境变量保存敏感信息,不提交 Git。
1 | |
配置文件:
1 | |
测试环境
配置中心保存 Jasypt 密文:
1 | |
解密密钥通过启动参数或环境变量注入:
1 | |
生产环境
优先使用 Secret Manager / Vault / Kubernetes Secret。
如果短期只能用 Jasypt,则至少做到:
- 生产密钥只在部署平台配置。
- 生产密钥不进入 Git。
- 生产密钥不出现在日志。
- 生产配置中心权限严格隔离。
- 定期轮换数据库密码和加密密钥。
- CI/CD 平台的变量权限单独控制。
- Actuator 端点只暴露必要能力。
chapter 12:常见误区
误区一:配置加密后就绝对安全
不是。
配置加密只解决“静态配置文件不存明文”的问题。应用运行时最终还是要拿到明文,否则它无法连接数据库、Redis、MQ。
所以真正的重点是:
- 谁能拿到密文?
- 谁能拿到密钥?
- 谁能触发解密?
- 解密过程有没有审计?
- 密钥能不能轮换?
误区二:把 Jasypt 密钥写在 application.yml
这等于没加密。
错误示例:
1 | |
正确方向:
1 | |
或者使用部署平台注入环境变量。
误区三:所有敏感信息都用同一个密钥
不建议。
至少应该区分环境。更进一步,可以按业务域、系统等级、租户隔离策略拆分密钥。
误区四:配置中心权限随便给
配置中心是微服务时代的“中枢神经”。如果生产配置人人可见,那加密、认证、网关、审计都可能被绕开。
配置中心权限建议分层:
- 开发人员:可看开发环境。
- 测试人员:可看测试环境。
- 运维人员:可管理部署变量。
- 生产敏感配置:最小化授权。
- 解密密钥:只给部署平台或密钥管理系统。
误区五:忽略历史提交
如果明文密码曾经提交过 Git,只删除当前文件是不够的。
要做的是:
- 立即更换已泄露密码。
- 清理 Git 历史或更换仓库访问权限。
- 检查 CI/CD、制品库、镜像仓库。
- 检查日志系统是否记录过明文。
- 增加 Git secret 扫描。
chapter 13:实践清单
最后给一份检查清单。
代码仓库
- 不提交明文密码。
- 不提交
.env。 - 不提交私钥文件。
- 不提交生产配置。
- 添加
.gitignore。 - 接入 secret scanning。
配置文件
- 敏感字段使用占位符或密文。
- 不在配置文件里写解密密钥。
- 不在默认 profile 里放生产配置。
- 不同环境配置隔离。
启动部署
- 密钥通过环境变量、启动参数、Secret Volume 或密钥管理平台注入。
- CI/CD 变量做权限控制。
- 生产环境禁止打印完整启动参数。
- 容器镜像不内置生产密钥。
应用运行
- 日志脱敏。
- Actuator 最小暴露。
- 配置中心访问控制。
- 数据库账号最小权限。
- 定期轮换密码和密钥。
应急处理
- 发现泄露后第一时间换密钥。
- 不要只删配置文件。
- 检查 Git 历史、日志、镜像、制品、配置中心。
- 复盘权限链路。
参考资料
- SpringBoot3:轻松使用 Jasypt 实现配置文件信息加密
- Spring Boot Reference Documentation:Externalized Configuration
- ulisesbocchio / jasypt-spring-boot 官方 README
- Spring Cloud Config:Encryption and Decryption
- Spring Cloud Config:Key Management
- Spring Cloud Kubernetes:Secrets PropertySource
- Kubernetes Documentation:Secrets
- Spring Cloud Vault Reference Documentation
- AWS Secrets Manager Documentation
启示录
配置加密这件事,表面看是“把密码加密一下”,本质上是“谁在什么时候,以什么权限,拿到什么秘密”。
Jasypt 是一个很好用的工具,尤其适合 Spring Boot 项目快速改造。但到了生产环境,真正可靠的方案一定不只是加密字符串,而是权限、审计、轮换、隔离、应急响应一起做。
安全不是把门锁上这么简单,还要知道钥匙在谁手里、谁配过钥匙、钥匙丢了怎么办。
富贵岂由人,时会高志须酬。
能成功于千载者,必以近察远。