bzed-dehydrated

Puppet module for centralized CSR signing using Let’s Encrypt™ and lukas2511/dehydrated - keeping your keys safe on the host they belong to.


Keywords
bzed, dehydrated, lets-encrypt, letsencrypt, puppet, puppet-module
License
Apache-2.0
Install
puppet module install bzed-dehydrated --version 0.1.8

Documentation

dehydrated

Puppet Forge Build Status

Centralized CSR signing using Let’s Encrypt™ - keeping your keys safe on the host they belong to.

Table of Contents

  1. Description
  2. Setup - The basics of getting started with dehydrated
  3. Usage - Configuration options and additional functionality
  4. Migrating from bzed-letsencrypt
  5. Limitations - OS compatibility, Deployment time, etc.
  6. Development - Guide for contributing to the module

Description

bzed-dehydrated creates private keys and CSRs, transfers the CSR to a central host (for example your puppetmaster) where it is signed using the well known dehydrated https://github.com/dehydrated-io/dehydrated

Signed certificates are shipped back to the requesting host.

You need to provide an appropriate hook script for dehydrated. The default is to use the DNS-01 challenge, but if your hook supports it you could also create the necessary files for http-01.

Let’s Encrypt is a trademark of the Internet Security Research Group. All rights reserved.

Deprecation of bzed-letsencrypt

With the release of bzed-dehydrated my old module bzed-letsencrypt will be deprecated. Renaming the module to avoid trademark related troubles is one of the reasons for a new module, the other is that I did not want to break the API for all users of the old module. If there is enough interest I'll change bzed-letsencrypt to become a wrapper around the new module, but with all the new features and options I don't think that makes much sense. So I'm sorry for the extra trouble of migrating an existing installation (to make it easier, see below), but I hope that the extra amount of flexibility and less hacks in the code make it worth to migrate.

Setup

What dehydrated affects

dehydrated needs to use facter to retrieve the signed certificates and other data from your central signing hosts if you are not using a puppet master host to handle it. Although only certificates which need to be renewed are transferred, it is unknown how well this approach scales if you plan to request lots of certificates. Using a (designated) puppet master is the better option.

Setup Requirements

You need to ensure that exported resources are working and pluginsync is enabled.

Beginning with dehydrated

Basic things you need:

  • a host with internet access, preferable a puppet master. This will be known as dehydrated_host now.
  • a working hook script for dehydrated, for exampes and documentation see dehydrated-io/dehydrated
  • bzed-dehydrated installed as dehydrated module in your Puppet environment. You will also need recent versions of puppetlabs-stdlib, puppetlabs-concat, puppetlabs-vcsrepo. For puppet >= 6.0 you'll also need puppetlabs-cron\_core.
  • I'd assume at least puppet version 4.8. Not tested or developed for older version.
  • Working exportable ressources. Make sure your puppetdb is working well, this module heavily depends on it.

Usage

This only describes the very basic usage. Almost all things are configurable, see the reference for details. So for a basic setup, the following steps should give you a running setup.

  1. Do a basic setup of your dehydrated_host:

        class { 'dehydrated' :
            dehydrated_host => 'your.dehydrated.host.example.com',
        }
    
  2. As example we'll use the dehydrated hook for Cloudflare®. Take socram8888/dehydrated-hook-cloudflare and on your dehydrated_host install it into /opt/dehydrated/hooks/dns-01.sh

  3. Add the hook configuration to your config from above:

    class { 'dehydrated' :
        dehydrated_host => 'your.dehydrated.host.example.com',
        dehydrated_environment => {
            'CF_EMAIL' => 'your@email.address',
            'CF_KEY'   => 'your-long-Cloudflare-api-key',
        }
    }
    
  4. On the host that needs a new certificate, add this to your puppet code:

    class { 'dehydrated' :
        dehydrated_host => 'your.dehydrated.host.example.com',
        challengetype   => 'dns-01',
    }
    ::dehydrated::certificate { 'my-https-host.example.com' :
        subject_alternative_names => [ 'example.com', 'host2.example.com' ],
    }
    
  5. Wait.... it will take a few puppet runs until your certificate will appear. The certificates will be requestd by a cronjob, not directly from puppet. Otherwise puppet runs will take way too much time. For detailed description of the workflow see Deployment workflow

Using hiera

To use hiera, make sure you include your dehdrated class somewhere. As default configuration for all hosts setup the defaults, in this case we are using dehydrated in the way to be compatible to the old bzed-letsencrypt setup:

dehydrated::dehydrated_host: 'my.dehydrated.host'
dehydrated::base_dir: '/etc/letsencrypt'
dehydrated::group: 'letsencrypt'
dehydrated::letsencrypt_ca: 'v2-production'
dehydrated::challengetype: 'dns-01'
dehydrated::dehydrated_hook: 'tophosting_hook.py'
dehydrated::dehydrated_domain_validation_hook: 'domain_validation_hook.sh'

And to request certificates:

dehydrated::certificates:
    - "*.subdomain.example.com"
    - "subdomain.example.com"
    - - "san.example.com"
      - [ "second_domain.san.example.com", "third_domain.san.example.com" ]

With the yaml snippet above you'd request the following certificates:

  • wildcard certificate *.subdomain.example.com
  • "normal" certificate subdomain.example.com
  • SAN certificate san.example.com with second_domain.san.example.com and third_domain.san.example.com as subject alternative names.

Monitoring & debugging

  • usual Puppet debugging rules apply >:-)

  • you'll find the output and errors from the last cronjob run in /opt/dehydrated/status.json. Unfortunately proper logging and maybe a better error handling is not implemented yet. Pull requests are welcome :-)

  • monitoring the cronjob results is possible by using check_statusfile. On Debian and derivates this is available in the nagios-plugins-contrib package. Or find the source here: check_statusfile

    # /usr/lib/nagios/plugins/check_statusfile /opt/dehydrated/monitoring.status
    dehydrated certificates: OK: 2, FAILED: 1
    foo.example.com (from bar.example.com): OCSP update failed
    

Migrating from bzed-letsencrypt

If you were using the bzed-letsencrypt module before, I'd suggest to use the following settings on the hosts that request certificates:

class { 'dehydrated' :
    group    => 'letsencrypt',
    base_dir => '/etc/letsencrypt',
}

Migrating the files on the dehydrated_host (former letsencrypt_host) is a harder task and not implemented. A new setup or manual migration is preferred.

Reference

An html version of the reference is available here: https://bzed.github.io/bzed-dehydrated/ There is also a markdown version in REFERENCE.md

Monitoring

The cron-triggered dehydrated worker creates a status file in a format compatible with check_statusfile, which is - in Debian and derivates - packaged in the nagios-plugins-contrib package. If you ar enot using Debian you can retrieve the source code here: check_statusfile

Limitations

Don't forget that Let’s Encrypt limits apply! Also: this code might not work for your use-case out of the box, please test it properly against the Let’s Encrypt testing CA instead of running into the limit for failed authorizations and blaiming me for it ;)

Deployment workflow

The cerfificates take some time to appear on the target host. This is due to the way this modules works. The Following Steps are taken to create all cerficate files. The time depends on your puppet and cron schedule.

Step Server System Description Relevant Source
1 target puppet Create Key and CSR dehydrated::certificate dehydrated::certificate::csr
2 target puppet get CSR from $fact['dehydrated_domains'] and export it as a dehydrated::certificate::request. dehydrated
3 dehydrated_host puppet Collect all dehydrated::certificate::request and save them for the cronjob. dehydrated dehydrated::certificate::request
4 dehydrated_host cron finds the files from previous step and requests the certificates. dehydrated_job_runner
5 dehydrated_host puppet Find the certificates and export them as dehydrated::certificate::transfer dehydrated dehydrated::certificate:collect
6 target puppet Collect all dehydrated::certificate::transfer and save them to the files. dehydrated dehydrated::certificate::transfer
7. target puppet identify deployed certificates by $fact['dehydrated_domains::dn::'ready_for_merge] and create joined files like *_fullchain.pem. dehydrated::certificate dehydrated::certificate::deploy

Development

Please use the github issue tracker and send pull requests. Make sure that your pull requests keep travis happy!

For a release:

  • Update gh_pages:

    bundle exec rake strings:gh_pages:update
    
  • Update REFERENCE.md:

    puppet strings generate --format markdown --out REFERENCE.md
    
  • Create changelog:

    bundle exec rake changelog
    
  • Release:

    pdk build
    
  • Bump version number: bump/change the version in metadata.json.

Support and help

There is no official commercial support for this puppet module, but I'm happy to help you if you open a bug in the issue tracker. Please make sure to add enough information about what you have done so far and how your setup looks like. I'm also reachable by email. Use GPG to encrypt confidential data:

ECA1 E3F2 8E11 2432 D485  DD95 EB36 171A 6FF9 435F

If you are happy, I also have an amazon wishlist :)