-
Notifications
You must be signed in to change notification settings - Fork 715
Description
Version Information
spring-cloud-context
: 3.0.1
Details
Pre-Ilford, it was possible to inject a custom TextEncryptor
into the framework to override the default implementation of decrypting a secret. (In my case, I am using GCP KMS to decrypt the secrets.)
The TextEncryptorBindHandler
introduced in #872 allows for a custom TextEncryptor
implementations by resolving from the bootstrap context: TextEncryptorConfigBootstrapper:L70
registry.registerIfAbsent(BindHandler.class, context -> {
TextEncryptor textEncryptor = context.get(TextEncryptor.class);
if (textEncryptor != null) {
KeyProperties keyProperties = context.get(KeyProperties.class);
return new TextEncryptorBindHandler(textEncryptor, keyProperties);
}
return null;
});
However, DecryptEnvironmentPostProcessor
prefers to create it's own TextEncryptor
: DecryptEnvironmentPostProcessor:L78
protected TextEncryptor getTextEncryptor(ConfigurableEnvironment environment) {
Binder binder = Binder.get(environment);
KeyProperties keyProperties = binder.bind(KeyProperties.PREFIX, KeyProperties.class)
.orElseGet(KeyProperties::new);
if (keysConfigured(keyProperties)) {
setFailOnError(keyProperties.isFailOnError());
if (ClassUtils.isPresent("org.springframework.security.rsa.crypto.RsaSecretEncryptor", null)) {
RsaProperties rsaProperties = binder.bind(RsaProperties.PREFIX, RsaProperties.class)
.orElseGet(RsaProperties::new);
return EncryptionBootstrapConfiguration.createTextEncryptor(keyProperties, rsaProperties);
}
return new EncryptorFactory(keyProperties.getSalt()).create(keyProperties.getKey());
}
// no keys configured
return new FailsafeTextEncryptor();
}
Workaround
To enable custom decryption of properties in the spring environment:
- Subclass
DecryptEnvironmentPostProcessor
(with higher priority) to:- decrypt properties using custom
TextEncryptor
by overridinggetTextEncryptor
to create a new instance of the customTextEncryptor
. - inject a custom
PropertySource
to enable (for example)spring.config.use-legacy-processing
to preventDecryptEnvironmentPostProcessor
from processing encrypted properties (*).
- decrypt properties using custom
- Because the standard
DecryptEnvironmentPostProcessor
executes at lowest priority, use a high-priorityApplicationContextInitializer
to remove the customPropertySource
before any otherApplicationContextInitializer
implementations might execute and use the temporary value.
In addition to the above, to support decrypting properties with TextEncryptorBindHandler
:
- Add a custom
EnvironmentPostProcessor
to register aTextEncryptor
supplier that creates a new instance of the customTextEncryptor
.
(*) If DecryptEnvironmentPostProcessor
executes (because neither spring cloud bootstrap nor legacy processing is enabled), this results in a FailsafeTextEncryptor
being created (**). An exception gets thrown when DecryptEnvironmentPostProcessor
also tries to decrypt any values that have been encrypted.
(**) Because the properties to configure a normal TextEncryptor
are not defined, as we are intending to use a custom implementation instead.
Questions
- Should people be allowed to customise
TextEncryptor
during bootstrap to decrypt ConfigData values? - If not, should people simply use a different prefix for encrypted values and clone the code for
DecryptEnvironmentPostProcessor
andAbstractEnvironmentDecrypt
? - Or alternatively, people could implement a ConfigData version of what is described in Spring Boot Configuration with Jasypt. However, this means moving away from using the
{cipher}
prefix and so away from howspring-cloud
denotes encrypted values.