Module of the Week: java_ks – Build Java Keystores From Existing Keys and Certificates

Purpose Build Java keystores form existing keys and certificates.
Module puppet/java_ks
Puppet Version 2.7+
Platforms OpenJDK 6, OpenJDK 7
This module attempts to ease and shorten the workflow associated with Java applications.
  • When building a Java keystore outside of the Java tool chain, you have to go through a process that spans a couple different tools and intermediary formats before you have a valid keystore. The java_ks module attempts to relieve this by giving you one interface: Puppet. Puppet handles the conversion and intermediary formats for you.
  • This module contains no manifests, only a composite namevar type and its supporting provider.
  • This module allows for keystores to be provisioned along with your Puppet deployed Java application servers.
The reason this module came to life was my frustration over the workflow needed to get a SSL protected ActiveMQ broker set up. When I wanted to integrate the Java keystore build workflow into the rest of ActiveMQ's setup using a Puppet manifest... well, it got ugly. Converting a string of shell commands into Puppet exec resources eventually led me to a dark dark place. Personally I find that if you are running into a need for a lot of exec resources, especially when they are using the same command or operating on the same file, it is time to grab a copy of Puppet Types and Providers and get your hands dirty with some Ruby. You'll usually notice a speed increase of your agent runs after a conversion to a type/provider to replace all the exec resources and always end up with easier to maintain manifests.

Installing the module

Complexity Easy
Installation Time 10 minutes
Installation is straightforward thanks to the Puppet Forge.
  • Make sure Java is installed on your Java application nodes by installing the “puppetlabs/java” module.
    root@pm01:~# puppet module install puppetlabs/java
    Notice: Preparing to install into /etc/puppet/modules ...
    Notice: Downloading from https://forge.puppetlabs.com ...
    Notice: Installing -- do not interrupt ...
    /etc/puppet/modules
    └─┬ puppetlabs-java (v0.2.0)
      └── puppetlabs-stdlib (v3.2.0)
     
  • Classify your Java application node (this is probably highly dependent on your organization).
    class { 'java': distribution => 'jre' }
     
  • Install the java_ks module from the Puppet Forge
    root@pm01:~# puppet module install puppetlabs/java_ks
    Notice: Preparing to install into /etc/puppet/modules ...
    Notice: Downloading from https://forge.puppetlabs.com ...
    Notice: Installing -- do not interrupt ...
    /etc/puppet/modules
    └── puppetlabs-java_ks (v0.0.6)
     
  • Make sure pluginsync is set to true on your puppet master and agents.

Resource Overview

Java_ks is special in that it uses an uncommonly used feature of Puppet's resource api, the composite namevar. A composite namevar allows you to construct unique resource definitions from more than one resource parameter. This is employed to overcome the possible need to install the same certificate into multiple keystores from within the same catalog. Example 1: Defining the resource with an arbitrary title.
java_ks { 'accounting_dev_broker':
  ensure       => latest,
  name         => 'accounting.dev.example.com',
  certificate  => '/etc/ssl/certs/accounting.dev.example.com.crt',
  private_key  => '/etc/ssl/private/accounting.dev.example.com.key',
  target       => '/etc/activemq/broker.jks',
  password     => 'not_so_secret',
}
  Example 2: Defining a resource where title maps to name AND target parameters. You'll notice that “:” is between the fqdn of the cert, which I am using as the name of this resource and the path to the broker.ks file. The “:” is the namevar separator I chose for this type.
java_ks { 'accounting.dev.example.com:/etc/activemq/broker.jks':
  ensure       => latest,
  certificate  => '/etc/ssl/certs/accounting.dev.example.com.crt',
  private_key  => '/etc/ssl/private/accounting.dev.example.com.key',
  password     => 'not_so_secret',
}
  Example 3: Build two keystores, one for our activemq broker and another for a Java web application.
java_ks { 'accounting_dev_broker':
  ensure       => latest,
  name         => 'accounting.dev.example.com',
  certificate  => '/etc/ssl/certs/accounting.dev.example.com.crt',
  private_key  => '/etc/ssl/private/accounting.dev.example.com.key',
  target       => '/etc/activemq/broker.jks',
  password     => 'not_so_secret',
}

java_ks { 'accounting_dev_app':
  ensure       => latest,
  name         => 'accounting.dev.example.com',
  certificate  => '/etc/ssl/certs/accounting.dev.example.com.crt',
  private_key  => '/etc/ssl/private/accounting.dev.example.com.key',
  target       => '/etc/tomcat/application.jks',
  password     => 'not_so_secret',
}

Testing the module

Because this module is 100% Ruby, it ships with a set of rspec unit tests.

  • Running tests:
    • Install your operating system's Ruby Development package.
    • gem install puppetlabs_spec_helper
    • cd /etc/puppet/modules/java_ks
    • rspec spec
  • If tests fail...

Configuring the module

Complexity N/A
Installation Time N/A

This module being just a type and provider means there is not further configuration beyond installation.

Example usage

I illustrated some example usage while we were reviewing the resources earlier. To see this type actually used in the wild, you can take a look at the puppetlabs-operations fork of the puppetlabs-activemq module, which unfortunately isn't Puppet Forge ready.

Conclusion

This type reduced the number of resources I needed to configure my Java keystore from six to two, one to create the store and then a simple file resource to manage permissions. It also helped readability enormously. Anyone that has ever used an exec resource knows that reading inline bash can be eye straining.

  • Possible improvements
    • The unit tests currently stub the return on some commands and methods more frequently than they should. This reduces the validity of the tests when applied to a real world environment.
    • Passwords for private keys and keystores are currently set to the same thing. This means you need to either know the password to the private key and use it when you create the keystore or you need to strip the password from the private key.

Learn More

Puppet sites use proprietary and third-party cookies. By using our sites, you agree to our cookie policy.