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.
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:
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.
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!
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.
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:
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.