Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should I store development credentials on a Spring Boot project?

Where should I store development credentials on a Spring Boot project so that they are not committed to the repository? What's the most standard way?

In other frameworks (Rails, Clojure) I'm used to have a file that I do not commit to the repo where that information goes. Something like a secondary application.properties that gets merged and it's never committed. Does such a thing exist?

I'm deploying to Heroku, which provides credentials in environment variables that Spring can pick up, so, that part is solved. If I deploy somewhere else, it'll be a similar config.

In the Spring Boot Docs, chapter 24, Externalized Configuration, there's a list of all the places where properties are defined. I went through that list trying to find the appropriate place for credentials and I couldn't find it:

Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).

It's not a devtools thing, as you could want to develop locally disabling devloots.

@TestPropertySource annotations on your tests.

It's not about testing

@SpringBootTest#properties annotation attribute on your tests.

Again, not testing.

Command line arguments.

I'd rather not have credentials in command lines as those tend to be public in the computer, so, another program could pick them up. But besides that, I'm not running a command when development; I'm triggering the app from IntelliJ.

Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)

Same as environment variable/system properties bellow.

ServletConfig init parameters. ServletContext init parameters. JNDI attributes from java:comp/env.

Those seem not to apply at all when developing local generating a jar,

Java System properties (System.getProperties()).

I'm not sure what would be the appropriate way of setting them up, but it feels laborious.

OS environment variables.

I either set them on my OS, which is opaque to new developers, or I set them inside the IntelliJ run profile, which makes them part of the repository, which is what I'm trying to avoid.

A RandomValuePropertySource that only has properties in random.*.

They are not random.

Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)

This could be, but I'm not sure where that file should reside.

Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)

I want to be able to commit profile specific application properties to the repo, so, I cannot store credentials in these files.

Application properties outside of your packaged jar (application.properties and YAML variants).

This could be, but I'm not sure where that file should reside.

Application properties packaged inside your jar (application.properties and YAML variants).

I want to commit that file, so, I cannot store credentials there.

@PropertySource annotations on your @Configuration classes. Default properties (specified using SpringApplication.setDefaultProperties).

Using something like this, I could make my own thing, picking properties from a file that's not committed, but I'm interested in following Spring Boot's best and common practices, not making my own; specially as I'm just getting started.

like image 448
pupeno Avatar asked Aug 26 '17 21:08

pupeno


2 Answers

Spring-boot allows you to externalize your configuration in different places. For the scenario in question, one could place an application.properties file under ${PROJECT_ROOT}/config/. Those properties will override any other defined properties. In this case, it is not packaged within a deployable artifact.
Take a look at Application property files for further details.

Provide a sample configuration file under config/application.properties.example as a good starting point. That file could be version controlled. To avoid unintentional commits ignore everything else.

Using git, an ignore file could contain the following snippet (ignores everything but files ending with .example and a README.md):

.gitignore:

/config/*
!/config/README.md
!/config/*.example
like image 180
fateddy Avatar answered Jan 17 '23 23:01

fateddy


It depends on your configuration. Thanks to Spring's Environment abstraction, you can override properties at runtime from the environment, so depending on your deployment, there are many ways of doing that. However, be warned that, a false sense of security can be a real pain in the neck. You'd want to maintain configuration as code - that can be versioned, reviewed and audited, not as a text file on someone's PC that they use to inject random runtime variables. It is the classic "works on my machine" problem.

You didn't say anything about your deployment so it's almost impossible to say; if you're using Tomcat, you can use the setenv.sh. Your question, as it stands, is pretty vague; I'll update my answer when you update your post.

Edit, based on what OP said in the comments:

You could just provide key-value pairs as JVM variables. For example, if using Gradle to build, you could do gradle clean bootRun -Dmy.secret.key=whatever, and in the build.gradle:

bootRun {
  systemProperties = System.properties
}

You could also keep a application-local.properties that's not committed to Git, and start the application with a -Dspring.profiles.active=default,local profile, in which case Spring would merge application.properties and application-local.properties, with higher preference given to the later. Like I said before, this is a very bad idea, but you're a free man, so...

Spring Boot in itself doesn't have first-class support for encrypting properties, but if you're willing to do that yourself, you could commit everything, and either start the app passing in the key, or somehow manage it in your build environment (like a property in Maven settings.xml).

Edit 2, how to override properties in application.properties using env variables at runtime:

my.secret.key=${MY_SECRET_KEY:default}

If env variable MY_SECRET_KEY is present, my.secret.key will be equal to it's value; else it will be equal to default.

like image 39
Abhijit Sarkar Avatar answered Jan 18 '23 01:01

Abhijit Sarkar