项目中敏感配置信息一般需要进行加密处理,比如数据库密码,Spring Boot内置不提供加密支持,不能加密配置文件信息,在官方文档中提供了自定义Environment和Spring Cloud Vault两种解决方案。使用jasypt-spring-boot是另一种方案。
Spring Cloud Vault为HashiCorp Vault的客户端,支持访问HashiCorp Vault内存储的数据,避免了在Spring Boot程序中存储敏感数据。
本文详细介绍了如何使用jasypt-spring-boot、Spring Cloud Vault和HashiCorp Vault,如何使用Vault的AWS Secret、Database Secret、AWS EC2认证和AWS IAM认证。
自定义Environment
- 自己实现加解密的方法,在配置文件中使用密文,比如:
spring:
datasource:
password: a3Ehaf0f/S1Rt6JfOGfQ+w==
jwt:
secret: a3Ehaf0f/S1Rt6JfOGfQ+w==
- 实现EnvironmentPostProcessor,在其中执行解密操作,简单示例如下:
package org.itrunner.heroes.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Map;
public class DecryptedEnvironmentPostProcessor implements EnvironmentPostProcessor {
private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Resource path = new ClassPathResource("config.yml");
PropertySource<Map<String, Object>> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
}
private PropertySource<Map<String, Object>> loadYaml(Resource path) {
if (!path.exists()) {
throw new IllegalArgumentException("Resource " + path + " does not exist");
}
try {
OriginTrackedMapPropertySource propertySource = (OriginTrackedMapPropertySource) loader.load("custom-resource", path).get(0);
return new DecryptedMapPropertySource(propertySource);
} catch (IOException ex) {
throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
}
}
private static class DecryptedMapPropertySource extends MapPropertySource {
public DecryptedMapPropertySource(OriginTrackedMapPropertySource propertySource) {
super(propertySource.getName(), propertySource.getSource());
}
@Override
public Object getProperty(String name) {
Object value = super.getProperty(name);
if (value instanceof CharSequence) {
// 执行解密,返回明文
return "DecryptedValue";
}
return value;
}
}
}
自定义的EnvironmentPostProcessor需在META-INF/spring.factories内注册:
org.springframework.boot.env.EnvironmentPostProcessor=org.itrunner.heroes.config.DecryptedEnvironmentPostProcessor
Jasypt Spring Boot
集成jasypt-spring-boot
有三种方式集成jasypt-spring-boot:
- 项目中如使用了@SpringBootApplication或@EnableAutoConfiguration,简单地添加jasypt-spring-boot-starter到classpath将在整个Spring环境中启用加密属性
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
- 添加jasypt-spring-boot到classpath,添加@EnableEncryptableProperties到main Configuration class将在整个Spring环境中启用加密属性
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot</artifactId>
<version>2.1.0</version>
</dependency>
@Configuration
@EnableEncryptableProperties
public class MyApplication {
...
}
- 添加jasypt-spring-boot到classpath,使用@EncrytablePropertySource声明加密的属性或YAML文件
@Configuration
@EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
public class MyApplication {
...
}
或者使用@EncryptablePropertySources:
@Configuration
@EncryptablePropertySources({@EncryptablePropertySource("classpath:encrypted.properties"),
@EncryptablePropertySource("file:/path/to/encrypted2.properties")})
public class MyApplication {
....
}
加密配置
Key | Required | Default Value |
---|---|---|
jasypt.encryptor.password | True | - |
jasypt.encryptor.algorithm | False | PBEWithMD5AndDES |
jasypt.encryptor.bean | False | jasyptStringEncryptor |
jasypt.encryptor.keyObtentionIterations | False | 1000 |
jasypt.encryptor.poolSize | False | 1 |
jasypt.encryptor.providerName | False | null |
jasypt.encryptor.saltGeneratorClassname | False | org.jasypt.salt.RandomSaltGenerator |
jasypt.encryptor.stringOutputType | False | base64 |
jasypt.encryptor.proxyPropertySources | False | false |
jasypt.encryptor.property.prefix | False | ENC( |
jasypt.encryptor.property.suffix | False | ) |
默认,加密算法为PBEWithMD5AndDES,加解密bean name为jasyptStringEncryptor,加密的数据需使用ENC()包裹。
所有这些属性都可在配置文件中声明,但加密密码不应存储在配置文件中,而应使用系统属性、命令行参数传入,只要名称为jasypt.encryptor.password即可:
java -jar jasypt-spring-boot-demo.jar --jasypt.encryptor.password=password
或
java -Djasypt.encryptor.password=password -jar jasypt-spring-boot-demo.jar
也可在application.properties 或 application.yml中使用环境变量:
jasypt.encryptor.password=${JASYPT_ENCRYPTOR_PASSWORD:}
配置文件示例:
spring:
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
properties:
hibernate:
default_schema: heroes
format_sql: true
jdbc:
lob:
non_contextual_creation: true
show-sql: true
datasource:
platform: postgresql
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/postgres
username: hero
password: ENC(a3Ehaf0f/S1Rt6JfOGfQ+w==)
initialization-mode: never
jasypt:
encryptor:
algorithm: PBEWithMD5AndDES
password: 1qefhQH7mRR4LADVettR
stringOutputType: base64
property:
prefix: ENC(
suffix: )
生成加密数据
使用CLI工具JasyptPBEStringEncryptionCLI生成加密数据,如下:
java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="inputdata" password=secretkey algorithm=PBEWithMD5AndDES
执行后,输出如下:
----ENVIRONMENT-----------------
Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.191-b12
----ARGUMENTS-------------------
algorithm: PBEWithMD5AndDES
input: hero
password: 1qefhQH7mRR4LADVettR
----OUTPUT----------------------
a3Ehaf0f/S1Rt6JfOGfQ+w==
生成后,使用ENC(密文)替换明文数据即可。
HashiCorp Vault
HashiCorp Vault提供集中管理机密(Secret)和保护敏感数据的服务,可通过UI、CLI或HTTP API访问。HashiCorp Vault使用GO语言编写。
初识HashiCorp Vault
- 安装HashiCorp Vault
根据您的系统下载HashiCorp Vault,然后解压zip包,其中为一可执行文件。
以linux系统为例:
$ unzip vault_1.0.2_linux_amd64.zip
$ sudo chown root:root vault
$ sudo chmod 755 vault
$ sudo mv vault /usr/local/bin/
$ vault --version
帮助
直接运行vault可查看支持的命令:
$ vault
Usage: vault <command> [args]
Common commands:
read Read data and retrieves secrets
write Write data, configuration, and secrets
delete Delete secrets and configuration
list List data or secrets
login Authenticate locally
agent Start a Vault agent
server Start a Vault server
status Print seal and HA status
unwrap Unwrap a wrapped secret
Other commands:
audit Interact with audit devices
auth Interact with auth methods
kv Interact with Vault's Key-Value storage
lease Interact with leases
namespace Interact with namespaces
operator Perform operator-specific tasks
path-help Retrieve API help for paths
plugin Interact with Vault plugins and catalog
policy Interact with policies
secrets Interact with secrets engines
ssh Initiate an SSH session
token Interact with tokens
运行 vault [command] [subcommand] -h可查看命令支持的参数。
path-help 查看系统、Secret引擎、认证方法等路径支持的配置,在实际应用中经常用到。比如:
$ vault path-help sys/
$ vault path-help database/
$ vault path-help database/roles
$ vault path-help aws