-
Notifications
You must be signed in to change notification settings - Fork 40.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a callback to decrypt DB passwords #1312
Comments
There might already be hooks that you can use to achieve this. If you have a bean that implements Another option might be to create a custom |
I foresee a couple of problems in the implementation of this feature. I like Phil's approach of postprocessing the I'll show you what we have already on Friday face to face if you can make it to the meetings. |
There were some requests for this via XD users, ATM the suggestion is using unix permissions on a yml profile variant file. There is also https://jira.spring.io/browse/SPR-10666 that has links to more possible approaches. |
Thanks for the link. UNIX permissions is the best (most secure) way to deal with local files. We are also working on a server-based solution (so the keys are never available to the client app). Jasypt seems like it doesn't provide much that you can't do with Spring Security Crypto (other than more flavours of encryption) - the principle is the same though: for client side local files you still need UNIX permissions to protect the key. |
In our situation we already have the keys secured via an external service and some ACLs. The problem I have is with injecting my decryption logic using this key into Boot's DataSourceProperties. I got what I wanted by extending and overriding DataSourceProperties to inject my decryption logic, but that felt pretty hacky. My thinking was that Boot could replicate that with a simple callback or configurer bean. Its single purpose, but handles the most common case of wanting to decrypt a DB password while leaving the implementation details of how to decrypt to the user. And because this is happening during refresh we'll have access to any beans in the context we need to assist with decryption. |
Hi, I would appreciate this enhancement. What I have done to use encrypted values in In that component, I initialize Jasypt with the key coming from It is working for me so far, but I sure would appreciate if this was included in Boot. |
That's great and thanks for the update. If anyone else is interested in the evolution of this story, then we have some features in Spring Cloud (with a release coming soon). The config client is definitely an awesome addition to any Spring Boot application and it's pretty lightweight hopefully. It will give you decryption of local property sources with all the features I think you should need. (By the way, I would use an environment key that is hidden by default in the Spring Boot Actuator /env endpoint - one ending in "password" or "secret".) I'm not opposed to using Jasypt, but Spring Cloud doesn't use it (there are Spring Security primitives that are close enough and simpler to operate hopefully). Spring Cloud also provides asymmetric key cryptography, which I think is a must have. |
Thanks Dave, I'll take a look at Spring Cloud. Spring Boot is really a great project! |
Just to answer some of the concerns why this could be helpful. In general this is some sort of security by obscurity if in the end the application can decrypt the passwords. However, the question is more how to do a safe packaging and distribution of an application. |
As I said above, I don't think Jasypt cuts it for me. Please take a look at the features in Spring Cloud Context (moved from Spring Cloud Config during the 1.0.x releases). All the encryption support is in a single, small jar with only Spring Boot dependencies. It would be dumb to duplicate that here. |
Fine. I will have a look. Thanks for the hint. Could you also have a look at this and consider some rethinking about springs inner design: I am pretty much aware that spring is a swiss army knife and people will use it in million different (and sometimes sick) ways. So regression is not an easy one, but I would be happy, if you could have a look and see if there is something wrong in spring that can be fixed. Thanks! |
@ulisesbocchio explains in that issue that it is his design decision not to cache decrypted values. I don't see what it has to do with Spring Boot yet. Please let us know separately if you find something that needs changing. |
I filed a separate issue for this so I am done here. |
So you are talking about things like this: Sorry to say so but this is rather disappointing. Actually it would be better to allow to configure a custom decrytpor bean that is used for property values in the ENC(...) form. Then your current hardwired implementation can be a fallback if nothing else is configured. |
For the record, there is a related Spring Core issue for similar functionality that's been around for a while: https://jira.spring.io/browse/SPR-10666 |
Hi, Can anyone please help me with following issue http://stackoverflow.com/questions/31824601/spring-boot-not-loading-propertysourceloader Thanks |
@arafique For what I can tell the |
@stephane-deraco: How did you get Spring to use your |
@DanieleTorino In fact, I have followed the advice given by @dsyer and took a look at Spring cloud client. However, I do not use Spring cloud. I came to this solution inspired by https://github.com/spring-cloud/spring-cloud-commons/blob/cde7c7f3118382490c28776f66e0a56f248141fd/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EnvironmentDecryptApplicationInitializer.java : Create a class implementing Initialize your encryptor with something like : // Try to initialize the encryptor with master password
encryptor = new StandardPBEStringEncryptor();
final char[] password = // Get your pass here
((StandardPBEStringEncryptor) encryptor).setPasswordCharArray(password);
Arrays.fill(password, '\0'); And then write: @Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String, Object> overrides = new LinkedHashMap<>();
for (PropertySource<?> source : environment.getPropertySources()) {
decrypt(source, overrides);
}
if (!overrides.isEmpty()) {
environment.getPropertySources().addFirst(
new MapPropertySource("decrypted", overrides));
}
}
private void decrypt(PropertySource<?> source, Map<String, Object> overrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
for (String key : enumerable.getPropertyNames()) {
String value = source.getProperty(key).toString();
if (value.startsWith("{cipher}")) {
value = value.substring("{cipher}".length());
try {
value = encryptor.decrypt(value);
LOG.debug("Decrypted: key={}", key);
} catch (Exception e) {
LOG.warn(String.format("Cannot decrypt: key=%s", key), e);
// Set value to empty to avoid making a password out of the
// cipher text
value = "";
}
overrides.put(key, value);
}
}
} else if (source instanceof CompositePropertySource) {
for (PropertySource<?> nested : ((CompositePropertySource) source)
.getPropertySources()) {
decrypt(nested, overrides);
}
}
} This is something that works for me, including on Yaml properties file. |
@stephane-deraco: Thanks a lot. I got it working with your help, my complete solution can be found on stackoverflow. |
@DanieleTorino You're welcome |
I'm going to close this because I think https://cloud.spring.io/spring-cloud-vault/ is the best way to solve this. |
...and if
|
Common requirement is to encrypt your db password and put it in your props file. It'd be nice for Boot to provide some kind of callback so that I can provide decryption logic. Perhaps consider making it flexible so we can use it for more than just the DB passwords. My initial thought was to register a custom spel function and create a property like
spring.datasource=#{decrypt('someCrazyEncryptedPassword')}
The text was updated successfully, but these errors were encountered: