voxpupuli / puppet-letsencrypt

A Puppet module to install the Letsencrypt client and request certificates.
https://forge.puppet.com/puppet/letsencrypt
Apache License 2.0
87 stars 136 forks source link
bsd-puppet-module centos-puppet-module debian-puppet-module fedora-puppet-module freebsd-puppet-module hacktoberfest linux-puppet-module openbsd-puppet-module puppet redhat-puppet-module ubuntu-puppet-module

Let's Encrypt

Build Status Puppet Forge Puppet Forge - downloads Puppet Forge - endorsement Puppet Forge - scores Documentation Status

This module installs the Let's Encrypt client (certbot) and allows you to request certificates.

Support

This module is currently only written to work on Debian and RedHat based operating systems, although it may work on others. The supported Puppet versions are defined in the metadata.json

Dependencies

On EL (Red Hat, CentOS etc.) systems, the EPEL repository needs to be enabled for the Let's Encrypt client package.

The module can integrate with puppet/epel to set up the repo by setting the configure_epel parameter to true (the default for RedHat) and installing the module.

Usage

Setting up the Let's Encrypt client

To install the Let's Encrypt client with the default configuration settings you must provide your email address to register with the Let's Encrypt servers:

class { 'letsencrypt':
  email => 'foo@example.com',
}

You can enforce upgrade of package to the latest available version (in your repositories):

class { 'letsencrypt':
  email          => 'foo@example.com',
  package_ensure => 'latest',
}

If using EL7 without EPEL-preconfigured, add configure_epel:

class { 'letsencrypt':
  configure_epel => true,
  email          => 'foo@example.com',
}

(If you manage epel some other way, disable it with configure_epel => false.)

This will install the Let's Encrypt client and its dependencies, agree to the Terms of Service, initialize the client, and install a configuration file for the client.

Alternatively, you can specify your email address in the $config hash:

class { 'letsencrypt':
  config => {
    email  => 'foo@example.com',
    server => 'https://acme-v01.api.letsencrypt.org/directory',
  }
}

During testing, you probably want to direct to the staging server instead with server => 'https://acme-staging-v02.api.letsencrypt.org/directory'

If you don't wish to provide your email address, you can set the unsafe_registration parameter to true (this is not recommended):

class { 'letsencrypt':
  unsafe_registration => true,
}

To request a wildcard certificate, you must use the ACME v2 endpoint and use a DNS-01 challenge. See https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578

class { 'letsencrypt':
  config => {
    email  => 'foo@example.com',
    server => 'https://acme-v02.api.letsencrypt.org/directory',
  }
}

Issuing certificates

Create letsencrypt::certonly defines. See the letsencrypt::certonly examples in the REFERENCE.md for more details.

Renewing certificates

There are two ways to automatically renew certificates with cron using this module.

cron using certbot renew

All installed certificates will be renewed using certbot renew using their original settings, including any not managed by Puppet.

class { 'letsencrypt':
  config => {
    email  => 'foo@example.com',
    server => 'https://acme-v01.api.letsencrypt.org/directory',
  },
  renew_cron_ensure => 'present',
}

With Hiera, at 6 AM (roughly) every other day:

---
letsencrypt::renew_cron_ensure: 'present'
letsencrypt::renew_cron_minute: 0
letsencrypt::renew_cron_hour: 6
letsencrypt::renew_cron_monthday: '1-31/2'

cron using certbot certonly

Only specific certificates will be renewed using certbot certonly.

letsencrypt::certonly { 'foo':
  domains              => ['foo.example.com', 'bar.example.com'],
  manage_cron          => true,
  cron_hour            => [0,12],
  cron_minute          => '30',
  cron_before_command  => 'service nginx stop',
  cron_success_command => '/bin/systemctl reload nginx.service',
  cron_output          => 'suppress',
}

Deprovisioning

If a domain needs to be removed for any reason this can be done by setting ensure to 'absent', this will remove the certificates for this domain from the server. If manage_cron is set to true, the certificate renewal cronjob and shell scripts for the domain will also be removed.

letsencrypt::certonly { 'foo':
  ensure      => 'absent',
  domains     => ['foo.example.com', 'bar.example.com'],
  manage_cron => true,
}

Hooks

Certbot supports hooks since certbot v0.5.0, however this module uses the newer --deploy-hook replacing the deprecated --renew-hook. Because of this the minimum version you will need to manage hooks with this module is v0.17.0.

All hook command parameters support both string and array.

Note on certbot hook behavior: Hooks created by letsencrypt::certonly will be configured in the renewal config file of the certificate by certbot (stored in CONFIGDIR/renewal/), which means all hooks created this way are used when running certbot renew without hook arguments. This allows you to easily create individual hooks for each certificate with just one cron job for renewal. HOWEVER, when running certbot renew with any of the hook arguments (setting any of the `letsencrypt::renew*_hook_commandsparameters), hooks of the corresponding types in all renewal configs will be ignored by certbot. It's recommended to keep these two ways of using hooks mutually exclusive to avoid confusion. Cron jobs created byletsencrypt::certonlyare unaffected as they renew certificates directly usingcertbot certonly`.

certbot certonly

Hooks created with letsencrypt::certonly will behave the following way:

letsencrypt::certonly { 'foo':
  domains               => ['foo.example.com', 'bar.example.com'],
  pre_hook_commands     => ['...'],
  post_hook_commands    => ['...'],
  deploy_hook_commands  => ['...'],
}

certbot renew

Hooks passed to certbot renew will behave the following way:

class { 'letsencrypt':
  config => {
    email  => 'foo@example.com',
    server => 'https://acme-v01.api.letsencrypt.org/directory',
  },
  renew_pre_hook_commands: [...],
  renew_post_hook_commands: [...],
  renew_deploy_hook_commands: [...],
}

With Hiera:

---
letsencrypt::renew_pre_hook_commands:
  - '...'
letsencrypt::renew_post_hook_commands:
  - '...'
letsencrypt::renew_deploy_hook_commands:
  - '...'

Facts

Fact: certbot_version

A fact that contains the current version of certbot installed on your operating system/distribution.

Fact: letsencrypt_directory

Facts about your live certificates are available through facter. You can query the list of live certificates from puppet using $facts['letsencrypt_directory'] in your puppet code, hiera data or from the command line.

facter -p letsencrypt_directory
{
  legacyfiles.ijc.org => "/etc/letsencrypt/live/legacyfiles.ijc.org",
  static.ijc.org => "/etc/letsencrypt/live/static.ijc.org",
  ijc.org => "/etc/letsencrypt/live/ijc.org",
  new.ijc.org => "/etc/letsencrypt/live/new.ijc.org",
  www.ijc.org => "/etc/letsencrypt/live/ijc.org",
  training.ijc.org => "/etc/letsencrypt/live/training.ijc.org"
}

Puppet Functions

This module profiles a custom puppet function letsencrypt::letsencrypt_lookup which allows you to load information about your certificates into puppet. This returns the same information as in the facts but for a particular domain. It accepts a single argument for your domain or wildcard domain.

Development

  1. Fork it
  2. Create a feature branch
  3. Write a failing test
  4. Write the code to make that test pass
  5. Refactor the code
  6. Submit a pull request

We politely request (demand) tests for all new features. Pull requests that contain new features without a test will not be considered. If you need help, just ask!