Maven: Keeping secrets out of Source Control

Written by: Stephen Connolly

OK, let’s get things clear up front… there is a “right way™” to to things… this post is not about the “right way™”… this post is about a pragmatic way to do things...

There now… that feels better!

So you have this project you are working on… and the project needs to have some secrets at runtime… there are three schools of thought on this one:

  • The right way™: you will put those secrets into the production environment by a different path and your application will be injected with their details

  • The wrong way: you check the secrets into source control.

  • The pragmatic way: I will keep the secrets on my and Joe’s machines and only I or Joe will do the builds that go into production (or even better is to keep the secrets only on Jenkins and only Jenkins will do the builds that go into production)

Now there have been times where everyone has just said ‘screw it’ and checked the password into source control… I am big enough to stand up and say ‘I have been that person’ but when you are doing it, you know in your heart that it is the wrong thing to do… but it is damn fast… and hey the integration tests can all use that secret too, so you know the code works

If you have ever done this the “right way™” and got it all working… well let me tell you that it is a nirvana… you can just deploy into production and the production secrets are picked up by magic… sadly getting the test cases working just right is a bit more complex and it can be hard to fire up a local copy of the application as you have to set up all that secret injecting wizardry… the view from the top is well worth the climb

Here is how to do things if you just don’t have the time to do it the “right way™”

Put your secrets in src/secrets/resources and make sure that directory is ignored by source control

Add the following to your pom.xml

<plugin>
  <groupid>io.github.stephenc.maven</groupid> 
  <artifactid>rfmm-maven-plugin</artifactid> 
  <version>1.0</version> 
  <executions>
    <execution>
      <goals>
        <goal>resources</goal> 
      </goals> 
    </execution> 
  </executions> 
</plugin> 

Done… problem solved!

The release-from-my-machine-maven-plugin will copy the files just like ordinary resources are copied from src/main/resources

At this point you are saying… yeah I could do that already...

But now look what happens when you run a release build...

mvn release:prepare release:perform

When Maven hits the release:perform step what it will do is checkout the tag from source control into the target/checkout directory (oh look… no secrets)

The rfmm plugin is smarter though… it will take a look and see that the secrets are in the original checkout and copy them from there… and it works even from child projects in a multi-module release… and if you are creating source bundles using the assembly plugin (much like all ASF projects need to) because there is no target/checkout/src/secrets/resources directory those files will not end up in the source bundle either (they will end up in the release binary artifact though… but that’s what you wanted)

Hope you enjoy...

P.S. you really should climb the “right way™” mountain at least once, it is a far nicer way… if you are using the CloudBees RUN@cloud for hosting your application, the mountain is not even that hard… bees config:set being your friend.

Stephen Connolly
Elite Developer and Architect
CloudBees

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.