So I've done some Googling and read some of the documentation on Spring Cloud, but in an effort to truly punish myself, I'm seeking to understand just exactly how encrypting sensitive application properties with a "{cipher}" really works.
For example in an application.yml...
Spring.datasource.password: '{cipher} abdjdbdjfb15168gddbdk3900289'
My understanding is that it is safe to commit this to a repo and that spring boot uses an encrypt.key in bootstrap.yml in order to decrypt it when needed.
What I don't understand is why is it safe to commit the encrypt.key to the repo? And if you don't, then how am I supposed to utilize this?
I also found a link on the heroku documentation that you maybe set this as a configuration variable in the server?
Bottom line, I have a lot of questions and, most importantly, I am not even sure what questions I need to be asking. So I'm hoping someone out there that knows what they're doing can point me in a few right directions of some links to read etc to get me going please?
Thanks in advance!
First of all, checkout the reference documentation about encryption in Spring Cloud Config which explains possibilities of configuration support.
You should never commit sensitive data such as keys to a source code repository if you can't control access to that repository. Not only regular access but also physical access, backups, ….
The preferred approach how to handle keys is storing the key in as few places as possible, ideally only on the server side where decryption happens. There you have the option to either use a bootstrap config, system properties or environment variables as a mechanism to pass the key to your runtime.
You might want to peek into HashiCorp Vault support as Vault solves the chicken-egg problem of key management. Instead, you can obtain a Vault token (from inside your client application, or configure a token on the server) and Vault will handle encryption/decryption for you.
Related
I'm developing an API which will connect with several endpoints. The uri for each endpoint is something like this:
rest/services/General/directory1/MapServer/export
rest/services/General/directory2/MapServer/export
rest/services/General/directory3/MapServer/export
rest/services/General/directory4/MapServer/export
and so on...
I don't know if it's possible, but would like to have something like this instead:
rest/services/General/${value}/MapServer/export
and then on my code just call the endpoint above injecting the specific directory that I want on ${value}
Is it possible? Don't know what I'm missing as I googled but couldn't find anything related.
Cheers
You can do so by means of Spring Cloud Config.
Spring Cloud Config provides server and client-side support for
externalized configuration in a distributed system. With the Config
Server you have a central place to manage external properties for
applications across all environments. The concepts on both client and
server map identically to the Spring Environment and PropertySource
abstractions, so they fit very well with Spring applications, but can
be used with any application running in any language. As an
application moves through the deployment pipeline from dev to test and
into production you can manage the configuration between those
environments and be certain that applications have everything they
need to run when they migrate. The default implementation of the
server storage backend uses git so it easily supports labelled
versions of configuration environments, as well as being accessible to
a wide range of tooling for managing the content. It is easy to add
alternative implementations and plug them in with Spring
configuration.
For more details, kindly go through spring documentation here.
I solve the problem using the simplest approach possible. In my code I used the string.replace() method. Was looking for something more robust, but as it was taking lots of time to sort it out how to do it, I decided to go with the string.replace method.
Currently, my spring-boot application connects to a local MongoDB without credentials. To be able to install it at a customer I need to provide the capability to use username and password for the DB connection. I am using the application.properties file, which currently contains only these 3 lines related to the database:
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=myApp
There would be these two additional ones:
spring.data.mongodb.username
spring.data.mongodb.password
But of course, I don't want to have the password in plain text within this file, or even worse in our git. One option would be to provide them as a parameter with a start script but then again it would be readable as plain text in the process details.
I've seen some encryption in the properties file using Jasypt, but I don't understand how this approach would work in my case. I never explicitly use these properties as they are automatically taken by spring to do the connection.
What would be the safest approach?
TL; DR
It depends on your security/risk profile, which method is acceptable.
The longer read
Your question is: What would be the safest approach?
A simple answer to this question is not storing the password anywhere but letting an operator type it in. Obviously, that's not the answer you're looking for as with servers in data centers or even VM's in the cloud this approach isn't feasible.
To understand what method is safe enough and which one is acceptable, it's important to understand your organizational context, its willingness to accept risk and the resulting consequence which is the requirement for handling secrets. This evaluation can result that for one organization it may be fine storing credentials in plain text (because the environment is secured or there's a low threat associated on exposed secrets), others require encryption with proper key management and auditing.
You're already describing that storing credentials in Git isn't a proper option. So I assume that you're looking towards a method that protects the actual secret in some way. Protection can happen on different levels:
Storing secrets in a protected place with access control applied
An environment variable on a host that is access protected
An access-controlled file with protected by permissions
Storing secrets in the encrypted form
Encrypting the value and storing it in a file. Here you need to consider who has access to this file and what about key management. Introduces sort of chicken and egg problem
Encrypting the value and storing it in memory. Still, you need to solve the key management issue.
Retrieving the secret from a trusted source
Credentials are typed in by an ops person (Not really feasible)
Asking a service to provide you with the credential. The remote service protects the secret and allows you/your application to ask for the secret.
There are potentially more possibilities but let's stick with these for now. One aspect that is associated with the above-mentioned possibilities is the transport of the credential from the source to the target destination. Transport typically spans over one to many parties and each of these parties need to be trusted in some way (i.e. you must make sure a certain party does not divulge your credentials). This pattern is also known as chain of trust. If every hop in the chain of trust is known, to not expose your credentials, then you can react with a particular protection pattern to this context. If you find a weak link that elevates the risk of exposure (e.g. a public folder, Lookup by an operator), then you again need to increase the level of protection according to your needs.
Having all that said, let's take a look which possibilities you have with Spring Boot to apply protection of secrets:
Environment variables
You can store configuration using environment variables or system properties. The aspect of volatility distinguishes from a persistent (e.g., file-based) storage. Variables can be set before/upon application startup.
Example for environment variables:
export SPRING_DATA_MONGODB_USERNAME=…
export SPRING_DATA_MONGODB_PASSWORD=…
java -jar my-app.jar
Examples for system properties:
java -jar my-app.jar -Dspring.data.mongodb.username=… -Dspring.data.mongodb.password=…
java -jar my-app.jar --spring.data.mongodb.username=… --spring.data.mongodb.password=…
Please note that environment variables/command lines can be introspected by the /proc file system and tools like ps
See the reference documentation on Externalized Configuration for further details.
Encrypted Configuration Properties
Spring Cloud comes with crypto support for individual properties. You can encrypt selected properties with different keys and key types (symmetric, asymmetric). This approach allows you to select properties that should be encrypted without the need to encrypt the whole file.
Example for environment variables:
application.properties
spring.data.mongodb.password={cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ
Please note this approach introduces the requirement of property key management.
See the reference documentation on Spring Cloud Config Encryption and Decryption for further details.
Application-controlled secrets
Configuration Properties in Spring Boot are obtained from the Environment and provided by PropertySources. You can contribute either properties or an entire PropertySource before spinning up Spring Boot.
Example of adding a PropertySource:
SpringApplication app = new SpringApplication(DemoApplication.class);
app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getEnvironment().getPropertySources().addFirst(…);
}
});
app.run(args);
Example of adding a property:
SpringApplication app = new SpringApplication(DemoApplication.class);
app.setDefaultProperties(Collections.singletonMap("spring.data.mongodb.password", "…"));
app.run(args);
Remote Configuration Properties
Spring Cloud Config allows you to centralize configuration that is served by Spring Cloud Config Server. Properties are no longer stored locally, but served from a config service that can be secured differently than your application protection level. To setup Spring Cloud Config Server, you need an additional service and integrate the client dependency in your application.
Please note that this approach does not solve the overall problem, but just moves it into someone else's responsibility.
See the reference documentation on Spring Cloud Config Server for further details.
Using Secrets Management
If you can afford a Secrets Management, such as HashiCorp Vault, CredHub, Azure KeyVault, Kubernetes Secrets, then you can leverage the features of your platform/Secrets Management system to apply protection to your credentials.
Secret Management systems typically handle encryption, auditing, and access control for you. These systems keep an encrypted copy of the credential. Once you request the credential (typically over TLS secured connections), the system checks whether you/your application is allowed to access that secret or not.
Some of these systems also provide dynamic secrets. Dynamic secrets are generated for a particular application instance upon demand. If your application wants to connect to MongoDB, the secrets management system is going to create a credentials pair and server these to your application. When your application stops, then the secrets management system is going to revoke the credentials.
See the reference documentation on Spring Cloud Vault for further details.
One addendum to the answer from #mp911de:
There is a second file option in Spring Boot: You are able to provide an additional file to overwrite the standard config, by providing either a ENV variable SPRING_CONFIG_ADDITIONAL_LOCATION to a file or adding it as a command property like spring.config.additional-location, see Application Property Files.
This could give you the opportunity to add the credentials via some file base secret deployment (eg. Kubernetes secrets used as a volumeMounts, Puppet/Chef/Ansible based secret deployment etc.).
I am currently developing a spring boot web application. It is a REST api proxy that connects to another api using some very sensitive credentials. The credentials are hard-coded at the moment, but obviously they should not be. What is the proper way of hiding them?
I have considered using some library, like jasypt to encode them and put the encoded values in a properties file, with the key hidden somewhere, perhaps in system variable, (but it is just another layer of obfuscation, isn't it?)
How can I properly hide these sensitive credentials?
You can use your server environment to hide your properties. Just store on your production server application.properties with real credentials and protect access, so only your application will have access to the property file.
The fundamental problem is that if you ever need to hold security credentials in the clear in the memory of a computer program, AND there are people who have the equivalent of "root" access to the machine, then it is possible for one of those people to gain access to the credentials.
So you need to design your security so that that the credentials never need to be held in the server's memory.
If you are really serious about solving this, you need to investigate Hardware Security Modules. However, the HSM approach is going to be complicated and expensive, and may require you to rework your authentication protocols.
I am working on a Java application that should be run in the background and was thinking of externalizing some sensitive info (DB credentials among others) in case it should change. These info is required in order for the application to start. However, I was wondering what is the proper way of doing this?
I was thinking of the following but needs advice from a security standpoint.
Encrypted passwords will be passed as Main arguments when starting the application. However, I noticed that any user can see the arguments when the list of processes in the OS will be viewed.
Generate an external file, i.e. java properties file (with encrypted credentials) with view restrictions, and pass the file path to the application
Put the encrypted credentials in the user's environment variables for the application to access it
Note: We already have an encryption tool that we use
Personally, I was leaning to the 2nd option but I would like to know suggestions, comments, or best practices for cases like this.
Thanks!
2 is the most sensible option. Problem with 1 and 3 is, once they have access to the "encrypted" string, all they have to figure out how are you decrypting it (You anyway have to do it, to make use of it).
Have you looked at Spring Cloud Config, I don't know whether this is an option for your or not.
Option 2 is most common.
Personally, I do not recommend Option 1 and 3.
There could be other options too.
As example you can look at PicketBox Vault.
It allows to make custom implementation more secured than default.
In fact it is extended option 2 - there is a Vault file protected by key stored in Keystore.
Still password to that Keystore(alias) must be secured, but only one(two). It is useful, when there are many properties need to be secured. It is also more manageable, since all properties secured same way and in one place.
I just started storing all of my DB credentials in my WAR's context.xml file, and loading them through JNDI. This way, my app can reuse the same credentials in multiple areas, and I can use JNDI to retrieve them (instead of sprinkling the credentials all over my codebase).
But now I'm thinking: what if an attacker gets onto the machine wehere my Tomcat server is installed? They could go straight to my webapps/MyApp exploded directory, find & open up the context.xml directory, and voila - they can now access my database!
So what is the next step for introducing security here? Is there a way to keep all of my credentials in some keystore, and reference their labels from inside context.xml? I still would like to use context.xml so that my JDBC code can access the credentials through JNDI. If so, how does context.xml access them in a secure way? What is the normal way of dealing with security here? Thanks in advance!
I would recommend building an encryption system that encrypts the data before it gets sent to the xml file then instead of searching for the username or whatever you encrypt the name before you search. This way even if a person managed to get into the file the wont be able to read it without having the algorithm used for encrytion and knowing exactly what they wanted to find. Well theoretically they could brute force it, but they still need to know the algorithm to do that. An easy way to handle encrytion would be to learn how to use the bouncy castle libs at http://www.bouncycastle.org/ . They have a very easy to use/learn system.