Ansible role to obtain Let's Encrypt SSL certificates
GPL-3.0 License
This role is meant to request SSL certificates from Let's Encrypt, using the HTTP or the DNS challenge for their ACME API.
Features:
apache
, nginx
, standalone
webroot
are supportedSupported distributions:
Tested on:
It does the following:
When letsencrypt_setup is True (the default) this role will:
When invoked with filled variable 'letsencrypt_cert':
ansible-playbook site.yml -l localhost -t letsencrypt
webroot
ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub.example.org","domains":["sub.example.org"],"challenge":"http","http_auth":"webroot","webroot_path":"/var/www/sub.example.org","services":["apache2"]}}'
ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub2","domains":["sub2.example.org","sub2.another.example.org"],"challenge":"dns","services":["dovecot","exim4"],"users":["Debian-exim"]}}'
standalone
ansible-playbook site.yml -l localhost -t letsencrypt -e '{"letsencrypt_cert":{"name":"sub3","domains":["sub3.example.org"],"challenge":"http","http_auth":"standalone","reuse_key":True,"post_hook":"/usr/local/bin/cert-post-hook.sh"}}'
letsencrypt_cert
The variable letsencrypt_cert
is expected to be a dictionary:
letsencrypt_opts_extra: "--register-unsafely-without-email"
letsencrypt_cert:
name: sub.example.org
domains:
- sub.example.org
challenge: http
http_auth: webroot
webroot_path: /var/www/sub.example.org
services:
- apache2
or:
letsencrypt_cert:
name: sub2
domains:
- sub2.example.org
- sub2.another.example.org
challenge: dns
services:
- dovecot
- exim4
users:
- Debian-exim
or:
letsencrypt_cert:
name: sub3
domains:
- sub3.example.org
challenge: http
http_auth: standalone
reuse_key: True
post_hook: "/usr/local/bin/cert-post-hook.sh"
letsencrypt_cert:
name: sub3
domains:
- sub3.example.org
challenge: http
http_auth: standalone
reuse_key: True
deploy_hook: "/usr/local/bin/cert-post-hook.sh"
The dictionary supports the following keys:
name
: name of the certificate [optional]domains
: list of domains for the certificate [required]challenge
: 'http' or 'dns' [required]
http_auth
: 'webroot', 'apache' or 'nginx' [optional, default 'webroot']
webroot_path
[optional, default '/var/www']services
: list of services to be restarted in the post-hook [optional]reuse_key
: Reuse same private key at certificate renewal. 'True' or 'False'post_hook
: Custom post-hook to be executed after attempt to obtain/renewdeploy_hook
: Custom deploy-hook to be executed after a successful attemptrenew_hook
: Custom renew-hook to be executed once for each renewedusers
: list of users to be added to system group 'letsencrypt' [optional]The role takes care of installing certbot and requesting SSL certificates using either the HTTP or the DNS challenge. It doesn't install or configure the required infrastructure (i.e. the Apache webserver or a DNS server).
The role is tested with Ansible 2.2 only. No guaranties that it runs with earlier versions of Ansible.
Requirements:
Requirements:
_acme-challenge.sub.example.org
for all domainsub.example.org._le.example.org
(inside the dedicated zone for theletsencrypt_ddns_key
andletsencrypt_ddns_privkey
(preferably inside a vault).This role installs a helper script for the DNS challenge to
/usr/local/bin/certbot-dns-hook.sh
. This script will add the validation
token to the TXT record at sub.example.org._le.example.org
during the DNS
challenge and remove it afterwards.
Obtaining wildcard certificates should work out of the box via DNS challenge.
(Another option would be to use the acme-dns server for this)
Generate a key for dynamic updates:
cd /etc/bind/keys
dnssec-keygen -a HMAC-SHA512 -b 512 -n USER _le.example.org_ddns_update
chown -R bind:bind /etc/bind/keys
Add the key to your bind config (e.g. at /etc/bind/named.conf.options
):
key "_le.example.org_ddns_update" {
algorithm hmac-sha512;
secret "...";
};
Create the zone for dynamic updates:
$ORIGIN .
$TTL 86400 ; 1 day
_le.example.org IN SOA ns1.example.org. postmaster.example.org. (
2017061501 ; serial
86400 ; refresh (1 day)
3600 ; retry (1 hour)
2419200 ; expire (4 weeks)
86400 ; minimum (1 day)
)
NS ns1.example.org.
NS ns2.example.org.
TXT "v=spf1 -all"
and configure it in your bind config (e.g. at /etc/bind/named.conf.local
):
zone "_le.example.org" {
type master;
file "/etc/bind/zones/db._le.example.org";
update-policy { grant _le.example.org_ddns_update wildcard *._le.example.org. TXT; };
};
Format for /etc/letsencrypt/keys/ddns_update.key
(from bind)
key "<key>" {
algorithm HMAC-SHA512;
secret "<key>";
};
Format for /etc/letsencrypt/keys/ddns_update.private
Private-key-format: v1.3
Algorithm: 165 (HMAC_SHA512)
Key: <key>
Bits: AAA=
Created: 20181017144534
Publish: 20181017144534
Activate: 20181017144534
# Perform setup step; set false to disable
letsencrypt_setup: True
# Provide existing account data to be copied over
letsencrypt_account: ""
# letsencrypt_account:
# hash: 1234567890abcdef1234567890abcdef
# id: 123456789
# creation_host: localhost
# creation_dt: 2020-12-13T13:12:00Z
# private_key:
# n: 1234
# e: 5678
# d: 90ab
# p: cdef
# q: 1234
# dp: 5678
# dq: 90ab
# qi: cdef
# kty: RSA
# Set the email address associated with the Let's Encrypt account
letsencrypt_account_email: ""
# Default authenticator for the HTTP challenge ('webroot' or 'apache')
letsencrypt_http_auth: webroot
# Default webroot path for the authenticator 'webroot'
letsencrypt_webroot_path: /var/www
# Install the DNS challenge helper script and DNS update key
letsencrypt_dns_challenge: yes
# Settings for the dynamic DNS zone updates
# letsencrypt_ddns_server: ""
# letsencrypt_ddns_zone: ""
# letsencrypt_ddns_key: ""
# letsencrypt_ddns_privkey: ""
# Create system group 'letsencrypt' for access to certificates
letsencrypt_group: yes
# Reuse private key at certificate renewal?
letsencrypt_reuse_key: False
# Allow subset of names?
letsencrypt_subset_names: True
# Set global extra commandline options for certbot
letsencrypt_opts_extra: ""
# Set path for letsencrypt directory (no trailing "/" !!)
letsencrypt_directory: /etc/letsencrypt
For testing purposes, variable letsencrypt_test
can be set. If set to
True, the role will use Let's Encrypt test servers for account creation
and obtaining the certificate.
For developing and testing the role we use Molecule and Vagrant/Github Actions. On the local environment you can easily test the role with
molecule test
This Ansible role is licensed under the GNU GPLv3.
Copyright 2017-2019 systemli.org (https://www.systemli.org/)