项目中敏感的配置信息一般需要加密保存,比如数据库用户名/密码。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 Secrets、Database Secrets、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> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
}
private PropertySource> 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环境中启用加密属性
com.github.ulisesbocchio
jasypt-spring-boot-starter
3.0.2
添加jasypt-spring-boot到classpath,添加@EnableEncryptableProperties到Configuration class将在整个Spring环境中启用加密属性
com.github.ulisesbocchio
jasypt-spring-boot
3.0.2
@Configuration
@EnableEncryptableProperties
public class MyApplication {
...
}
添加jasypt-spring-boot到classpath,使用@EncrytablePropertySource或@EncryptablePropertySources声明加密的属性文件
@Configuration
@EncryptablePropertySource(name = "EncryptedProperties", value = "classpath:encrypted.properties")
public class MyApplication {
...
}
或
@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
PBEWITHHMACSHA512ANDAES_256
jasypt.encryptor.bean
False
jasyptStringEncryptor
jasypt.encryptor.key-obtention-iterations
False
1000
jasypt.encryptor.pool-size
False
1
jasypt.encryptor.provider-name
False
SunJCE
jasypt.encryptor.provider-class-name
False
null
jasypt.encryptor.salt-generator-classname
False
org.jasypt.salt.RandomSaltGenerator
jasypt.encryptor.iv-generator-classname
False
org.jasypt.iv.RandomIvGenerator
jasypt.encryptor.string-output-type
False
base64
jasypt.encryptor.proxy-property-sources
False
false
jasypt.encryptor.skip-property-sources
False
empty list
jasypt.encryptor.property.prefix
False
ENC(
jasypt.encryptor.property.suffix
False
)
默认,Jasypt使用StringEncryptor加/解密属性值,默认bean name为jasyptStringEncryptor,加密算法为PBEWITHHMACSHA512ANDAES_256;加密的数据使用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(LL8xHWiEdH52yho0ADQ9/h5RsOa3txOFs+GcLtcdrLa2ke4JJ9UpZbKF/r13BIz3)
initialization-mode: never
jasypt:
encryptor:
algorithm: PBEWITHHMACSHA512ANDAES_256
password: 1qefhQH7mRR4LADVettR
stringOutputType: base64
property:
prefix: ENC(
suffix: )
加/解密数据
Jasypt提供了加/解密插件:
com.github.ulisesbocchio
jasypt-maven-plugin
3.0.2
加密
加密单一值:
mvn jasypt:encrypt-value -Djasypt.encryptor.password="the password" -Djasypt.plugin.value="theValueYouWantToEncrypt"
加密属性文件
先将属性文件中要加密的值使用DEC()包裹起来:
sensitive:
password=DEC(secret value)
然后运行如下命令:
mvn jasypt:encrypt -Djasypt.encryptor.password="the password" -Djasypt.plugin.path="file:src/main/resources/application-prod.yml"
运行后会自动替换文件内容:
sensitive:
password: ENC(encrypted)
解密
解密单一值:
mvn jasypt:decrypt-value -Djasypt.encryptor.password="the password" -Djasypt.plugin.value="DbG1GppXOsFa2G69PnmADvQFI3esceEhJYbaEIKCcEO5C85JEqGAhfcjFMGnoRFf"
解密文件:
mvn jasypt:decrypt -Djasypt.encryptor.password="the password" -Djasypt.plugin.path="file:src/main/resources/application-prod.yml"
运行后会输出解密后的内容,不会替换文件。
说明:运行jasypt:decrypt前删除下面内容,否则会出错。
property:
prefix: ENC(
suffix: )
您也可以调用CLI工具类JasyptPBEStringEncryptionCLI、JasyptPBEStringEncryptionCLI加/解密数据,比如:
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="theValueYouWantToEncrypt" password="the password" algorithm=PBEWITHHMACSHA512ANDAES_256
非对称加密
自jasypt-spring-boot:2.1.1支持非对称加密。
Key
Default Value
Description
jasypt.encryptor.privateKeyString
null
private key for decryption in String format
jasypt.encryptor.privateKeyLocation
null
location of the private key for decryption in spring resource format
jasypt.encryptor.privateKeyFormat
DER
Key format. DER or PEM
例如,DER key as string:
jasypt:
encryptor:
privateKeyString: MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCtB/IYK8E52CYMZTpyIY9U0HqMewyKnRvSo6s+9VNIn/HSh9+MoBGiADa2MaPKvetS3CD3CgwGq/+LIQ1HQYGchRrSORizOcIp7KBx+Wc1riatV/tcpcuFLC1j6QJ7d2I+T7RA98Sx8X39orqlYFQVysTw/aTawX/yajx0UlTW3rNAY+ykeQ0CBHowtTxKM9nGcxLoQbvbYx1iG9JgAqye7TYejOpviOH+BpD8To2S8zcOSojIhixEfayay0gUR