Generate keystores for TLS with minimal effort

written by Sönke Liebau on 2018-08-24

TL/DR

If you need a few keystores to enable SSL on Kafka, Elasticsearch or what-have-you, run the following:

$ git clone git@github.com:opencore/keystore_generator.git

$ cd keystore_generator

$ ./generate.sh inventory.template

And you will find a set of three server and two client keystores generated in the inventory.template.keystores directory.

The longer version

I'll tell you a quick story in the next few lines, and if at any time while reading those lines you find yourself thinking "exactly!" - then this post may be for you!

You are setting up a small test system to look into some bug or functionality, let's say ACLs for now. So naturally you need to set up some form of authentication.

Kerberos? Let's not! TLS it is..

Since this is only a test system that will be torn down in a few hours it is totally acceptable to use self-signed certificates. Of course you know what you need to do, set up a CA, generate keys, CSRs, sign the CSRs and import the entire shebang into keystores - you've done it a hundred times already.

So, you are able to freely type out the commands from memory, right? If you are like me the answer to that is a resounding NO!

Instead, what happens is that I do one or more of the following in a more or less random order:

  • google for certificates ca generate tutorial or something similar
  • check Evernote and find I didn't take notes the last time
  • run history | grep openssl
  • curse
  • hunt through my Skype history for when Oliver sent me those commands a year and a half ago
  • start manually generating multiple server keystores
  • google how I can specify the certificate properties on the command line instead of interactively
  • promise myself that this time I'll be sure to write everything I did down
  • get distracted by whatever I needed the keystores for in the first place and forget to take notes

If any of that rang a bell: welcome to the club!

So yesterday I actually took some time to automate the process and created a small ansible playbook that performs all of these steps.

Usage

You can find the playbook itself on Ansible Galaxy or Github. Since not everybody is necessarily familiar with Ansible I also created a wrapper script that takes care of checking out the role, setting inventory and variables as needed and running everything for you. The repository for this is also on Github .

What this does is create a connection to localhost and then it checks the server group for hosts that need certificates. Since these hosts are not being provisioned by the playbook there is no need for these to be accessible or alive. All values given in the inventory are taken at face value. I plan to extend this a little bit so that ansible discovered facts can be used instead, but that is still in the future.

After running this command a subdirectory named inventory.template.keystores (if you followed the commands above, otherwise named according to the inventory file you specified) will be created under your current directory. This will contain the following files:

inventory.template.keystores
├── ca
│   ├── rootCA.key
│   └── rootCA.pem
├── cert
│   ├── node1.crt
│   ├── node1.csr
│   ├── node2.crt
│   ├── node2.csr
│   ├── node3.crt
│   ├── node3.csr
│   ├── user1.crt
│   ├── user1.csr
│   ├── user2.crt
│   └── user2.csr
├── node1.jks
├── node2.jks
├── node3.jks
├── truststore.jks
├── user1.jks
└── user2.jks

As you can see this contains the promised three server and two user keystores as well as a truststore with the CA certificate. For most programs that work with java keystores this should be enough to get you started. The password for the keystores will be secret by default but can be changed via variables in the inventory file - more on that below.

All the intermediate files that were generated along the way are also kept, the ca folder contains all CA files and the certificate signing requests and certificates that were imported into the keystores are kept in cert.

The provided inventory file is supposed to serve as a template for further environments. I'd suggest copying and renaming this for any set of hosts that you want to generate certificates for. But if you come up with an alternative/better way of doing things, give me a shout!

Configuration

The following is an example of the relevant section of the inventory file which allows you to configure the hosts that server certificates are generated for:

[servers]
node1
node2 san=ip:10.0.0.2,dns:node2.testcluster
node3 san=ip:10.0.0.3

Values given in the variable san will be added to the SubjectAlternateName field of the certificates, so this is where you would put all IP addresses and DNS names of your servers. The CommonName Property will be filled with the Ansible inventory name - some software may validate the content of this field instead of the SAN, if this is the case for you, you will have to name the hosts accordingly.

The variables section in the inventory file contains some configuration values that can be used to change the behavior of the generation script. They are all commented out in the template inventory file, as the default values are set in the Ansible role. However, anything you define here will override these defaults.

For a list of the options and what they do please check the docs of the ansible role.

Further plans

I will probably adapt and change these scripts a little as I go along and find new use cases that they are not yet suitable for. A couple of items that are currently on the list are:

  • have ansible gather facts from the hosts and populate certificate fields from those facts
  • Extract keys from keystores for software that does not use keystores but rather specific key files
  • add generate.bat file for things to work on windows, but I have very limited experience with Ansible on Windows, so have not yet gotten around to it

Let me know if you can think of other things to add, or - even better - create a pull request on GitHub!

I hope this saves some of you some work in the future, I know it has already saved me quite a bit of time.

If you enjoy working on new technologies, traveling, consulting clients, writing software or documentation please reach out to us. We're always looking for new colleagues!