This module installs the Let's Encrypt client from source and allows you to request certificates.
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
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 stahnma/epel
to set up the repo by setting the configure_epel parameter to true (the default for RedHat) and
installing the module.
On Debian Jessie the module assumes the package certbot is available. This package can be found in jessie-backports. When using puppetlabs/apt the following code can be used:
include apt
include apt::backports
apt::pin { 'jessie-backports-letsencrypt':
release => 'jessie-backports',
packages => prefix(['acme', 'cryptography', 'openssl', 'psutil', 'setuptools', 'pyasn1', 'pkg-resources'], 'python-'),
priority => 700,
}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 => '[email protected]',
}If using Ubuntu16.04 with install_method to default package, you can enforce upgrade of package from 0.4 to 0.7 with :
class { letsencrypt:
email => '[email protected]',
package_ensure => 'latest',
}If using EL7 without EPEL-preconfigured, add configure_epel:
class { letsencrypt:
configure_epel => true,
email => '[email protected]',
}(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 => '[email protected]',
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.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 => '[email protected]',
server => 'https://acme-v02.api.letsencrypt.org/directory',
}
}To request a certificate for foo.example.com using the certonly installer
and the standalone authenticator:
letsencrypt::certonly { 'foo.example.com': }To request a certificate for foo.example.com and bar.example.com with the
certonly installer and the apache authenticator:
letsencrypt::certonly { 'foo':
domains => ['foo.example.com', 'bar.example.com'],
plugin => 'apache',
}To request a certificate using the webroot plugin, the paths to the webroots
for all domains must be given through webroot_paths. If domains and
webroot_paths are not the same length, the last webroot_paths element will
be used for all subsequent domains.
letsencrypt::certonly { 'foo':
domains => ['foo.example.com', 'bar.example.com'],
plugin => 'webroot',
webroot_paths => ['/var/www/foo', '/var/www/bar'],
}To request a certificate using the dns-rfc2136 plugin, you will at a minimum
need to pass server, key_name and key_secret to the class
letsencrypt::plugin::dns_rfc2136. Ideally the key secret should be encrypted,
eg. with eyaml if using Hiera. It's also recommended to only enable access to
the specific DNS records needed by the Let's Encrypt client.
Plugin documentation and it's parameters can be found here: https://certbot-dns-rfc2136.readthedocs.io
Parameter defaults:
key_algorithmHMAC-SHA512port53propagation_seconds10 (the plugin defaults to 60)
Example:
class { 'letsencrypt::plugin::dns_rfc2136':
server => '1.2.3.4',
key_name => 'certbot',
key_secret => '[...]==',
}
letsencrypt::certonly { 'foo':
domains => ['foo.example.com', 'bar.example.com'],
plugin => 'dns-rfc2136',
}If you need to pass a command line flag to the letsencrypt-auto command that
is not supported natively by this module, you can use the additional_args
parameter to pass those arguments:
letsencrypt::certonly { 'foo':
domains => ['foo.example.com', 'bar.example.com'],
plugin => 'apache',
additional_args => ['--foo bar', '--baz quuz'],
}There are two ways to automatically renew certificates with cron using this module.
All installed certificates will be renewed using certbot renew using their
original settings, including any not managed by Puppet.
renew_cron_ensuremanages the cron resource. Set topresentto enable. Default:absentrenew_cron_minutesets minute(s) to run the cron job. Default: Seeded random minuterenew_cron_hoursets hour(s) to run the cron job. Default: Seeded random hourrenew_cron_monthdaysets month day(s) to run the cron job. Default: Every day
class { 'letsencrypt':
config => {
email => '[email protected]',
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'Only specific certificates will be renewed using certbot certonly.
manage_croncan be used to automatically renew the certificatecron_success_commandcan be used to run a shell command on a successful renewalcron_before_commandcan be used to run a shell command before a renewalcron_monthdaycan be used to specify one or multiple days of the month to run the cron job (defaults to every day)cron_hourcan be used to specify hour(s) to run the cron job (defaults to a seeded random hour)cron_minutecan be used to specify minute(s) to run the cron job (defaults to a seeded random minute)suppress_cron_outputcan be used to disable output (and resulting emails) generated by the cron command
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',
suppress_cron_output => true,
}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,
}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
CONFIG_DIR/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_commands parameters), 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 by letsencrypt::certonly are unaffected as they renew certificates
directly using certbot certonly.
Hooks created with letsencrypt::certonly will behave the following way:
prehooks will be run before each certificate is attempted issued or renewed, even if the action fails.posthooks will be run after each certificate is attempted issued or renewed, even if the action fails.deployhooks will be run after successfully issuing or renewing each certificate. It will not be run if no action is taken or if the action fails.
letsencrypt::certonly { 'foo':
domains => ['foo.example.com', 'bar.example.com'],
pre_hook_commands => ['...'],
post_hook_commands => ['...'],
deploy_hooks_commands => ['...'],
}Hooks passed to certbot renew will behave the following way:
prehook will be run once total before any certificates are attempted issued or renewed. It will not be run if no actions are taken. Overrides all pre hooks created byletsencrypt::certonly.posthook will be run once total after all certificates are issued or renewed. It will not be run if no actions are taken. Overrides all post hooks created byletsencrypt::certonly.deployhook will be run once for each successfully issued or renewed certificate. It will not be run otherwise. Overrides all deploy hooks created byletsencrypt::certonly.
class { 'letsencrypt':
config => {
email => '[email protected]',
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:
- '...'- Fork it
- Create a feature branch
- Write a failing test
- Write the code to make that test pass
- Refactor the code
- 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!
