Create and renew Let's Encrypt certificates using Ansible - and the acme_certificate module

Posted by ads' corner on Tuesday, 2020-03-24
Posted in [Ansible][Lets-Encrypt][Software]

About two years ago I blogged about how to create and renew Let’s Encrypt certificates using Ansible. Back then, the “letsencrypt” module was State of the Art. This changed, and with all the Let’s Encrypt API changes, the Ansible module changed quite a lot, and is now “acme_certificate”. ACME stands for: Automatic Certificate Management Environment, and is the idea that every step along the way of creating and renewing certificates should be automated. No more manual creation of CSR (Certificate Signing Request), sending them per mail or manually uploading them to a CA website, enter your credit card details, and at some point get a mail back with the new signed certificate. All of this (except the credit card - you no longer need one) can be automated, and handled in a matter of seconds.

Time to write an updated blog post for the new module.

Besides the obvious change in the module name, a couple other things changed as well. Let’s Encrypt bumped their API version to v2, and it is no longer possible to create new certificates for websites using the old v1 API. It is however - for the time being - possible to renew certificates. If you are still use the v1 API: now it’s a good time to update to v2. Let’s Encrypt is sending out reminders to the email addresses which still use the v1 API.

So, what changed? For starters, I added a step which verifies beforehand if a certificate must be renewed. That’s documented here. Using this, I don’t need to run through the entire Playbook, and can decide beforehand if a certificate is still OK or needs to be renewed. That saves quite a bit of time.

The create challenge step is now using the acme_certificate module, and a couple different parameters:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
- name: Create challenge
  local_action:
    module: acme_certificate
    account_key_src: "{{ letsencrypt_cert_dir }}/{{ domain }}/account.key"
    csr: "{{ letsencrypt_cert_dir }}/{{ domain }}/domain.csr"
    dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/signed.crt"
    chain_dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/intermediate.pem"
    fullchain_dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/combined.pem"
    account_email: "{{ letsencrypt_account_email }}"
    acme_directory: "{{ letsencrypt_acme_directory }}"
    acme_version: "{{ letsencrypt_acme_version }}"
    challenge: "{{ letsencrypt_challenge }}"
    #agreement: "{{ letsencrypt_agreement }}"
    remaining_days: "{{ letsencrypt_remaining_days }}"
    terms_agreed: yes
  become: no
  run_once: true
  register: create_challenge

The new parameter is: terms_agreed: yes. The following parameters changed:

  • letsencrypt_acme_directory, from https://acme-v01.api.letsencrypt.org/directory to https://acme-v02.api.letsencrypt.org/directory
  • letsencrypt_acme_version, from 1 to 2

The create certificate step also changed slightly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
- name: Create certificate
  local_action:
    module: acme_certificate
    account_key_src: "{{ letsencrypt_cert_dir }}/{{ domain }}/account.key"
    csr: "{{ letsencrypt_cert_dir }}/{{ domain }}/domain.csr"
    dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/signed.crt"
    chain_dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/intermediate.pem"
    fullchain_dest: "{{ letsencrypt_cert_dir }}/{{ domain }}/combined.pem"
    account_email: "{{ letsencrypt_account_email }}"
    acme_directory: "{{ letsencrypt_acme_directory }}"
    acme_version: "{{ letsencrypt_acme_version }}"
    challenge: "{{ letsencrypt_challenge }}"
    #agreement: "{{ letsencrypt_agreement }}"
    remaining_days: "{{ letsencrypt_remaining_days }}"
    data: "{{ create_challenge }}"
    terms_agreed: yes
  become: no
  run_once: true
  when: create_challenge is changed
  register: verify_challenge

Here as well the terms_agreed: yes parameter is new, otherwise the same variables are used as in the create challenge step.

That’s it. All the other Playbook code is still the same as in the previous blog post. After about 90 days, all your certificates are on API v2.


Categories: [Ansible] [Lets-Encrypt] [Software]