Let's Encrypt certificates - ghomem/legacy_puppet_infrastructure GitHub Wiki

Introduction

This article documents an example where Let's Encrypt certificates are automatically managed via Puppet. This requires automatic management of DNS records for proof of domain ownership. Currently two providers are supported: Digital Ocean and Hetzner.

Module installation

In case you didn't install the puppet-letsencrypt module in the Puppet master installation, you can just install it with:

sudo /opt/puppetlabs/bin/puppet module install puppet-letsencrypt --version 9.2.0

Puppet node configuration

In order to install the Letsencrypt client on the Puppet node we need to declare the following Puppet resources:

  • The Letsencrypt client
  • The Puppet class that holds all of the SSL certificate declarations

Following is a Puppet declaration example:

node 'puppet' {
  
  # The actual DO API token to be written to the file above
  $dns_api_token  = lookup('puppet::letsencrypt_token')

  ( . . . )


  # this installs the Letsencrypt client and required dependencies
  class { 'puppet_infrastructure::letsencrypt_base':
    email               => '[email protected]',
    dns_api_token       => $dns_api_token,
    domains             => ['solidangle.eu'],
    renew_cron_monthday => [5,10,15,20,25],
    provider            => "your_provider", # We currently support only digitalocean and hetzner
  }

  # this class will contain all the SSL certificate declarations
  class { 'ssl_certificates':
    provider => 'your_provider',
    require  => Class['puppet_infrastructure::letsencrypt_base'],
  }
}

SSL Certificate creation

All the SSL certificates should be declared in the ssl_certificates class.

The SSL certificate wrapper class has the following mandatory parameters:

  • domain - the SSL certificate domain
  • provider - the dns provider

The following parameters are optional:

  • certificate_path - sets a different certificate path from the domain if necessary, useful for wildcard certificates so we don't get a * in the file path.
  • credentials_path - sets a different path for the file that contains the API token. The default is at /opt/puppet-infrastructure/etc/dns-creds.ini

Following is an example ssl_certificates declaration:

class ssl_certificates ( String $provider )
{

  # creates a wildcard certificate for '*.solidangle.eu'
  # in the following path: /etc/letsencrypt/live/star.solidangle.eu/
  puppet_infrastructure::letsencrypt_certificate { 'star.solidangle.eu'  : 
    domain           => '*.solidangle.eu',
    provider         => $provider,
    certificate_path => 'star.solidangle.eu',
    include_root     => true
  }

  # creates a certificate for 'domain.solidangle.eu'
  # in the following path: /etc/letsencrypt/live/domain.solidangle.eu/
  puppet_infrastructure::letsencrypt_certificate { 'domain.solidangle.eu':
    domain   => 'domain.solidangle.eu',
    provider => $provider
  }

}

After a certificate is created the certificate files must be copied over to the Puppet extra_files directory in order to be available to the nodes. In order to perform this copy we need to execute the following script:

sudo /opt/puppet-infrastructure/bin/deploy_maintained_certificates.sh

Whenever the certificates are (see below) renewed a similar copy is performed automatically.

Certificate renewal

Automated procedure

The Let's Encrypt client is installed along with a cronjob that will attempt to renew all the Letsencrypt certificates every 5 days and will only renew the ones that need to be renewed. Another cronjob is in charge of copying the renewed certificated to the puppet extra_files directory. Therefore, under normal conditions nothing needs to be done manually and as long as the DNS token remains valid the renewal + redeploy process will be performed automatically.

Manual procedure

In case we want to manually renew the certificates we can run: sudo certbot renew

To check the amount of time until the expiration of a certificate run: sudo certbot certificates --cert-name domain.solidangle.eu

Following is an example output:

$ sudo certbot certificates --cert-name domain.solidangle.eu
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following matching certs:
  Certificate Name: domain.solidangle.eu
    Domains:domain.solidangle.eu
    Expiry Date: 2022-08-15 16:26:28+00:00 (VALID: 88 days)
    Certificate Path: /etc/letsencrypt/live/domain.solidangle.eu/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/domain.solidangle.eu/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Certificates are renewed 30 days prior to the expiration date of the certificate as commented here.

If a certificate is renewed execute the same script in the section above to move it to the Puppet extra_files directory.

Certificate deletion

To remove certificates we can run the following command: sudo certbot delete

A prompt will appear listing all of the Letsencrypt certificates currently present on the server, from which we can choose to delete.

After deleting the certificates with sudo certbot delete we must manually remove the directory where the certificates reside so that we get no facter errors when running the Puppet agent. We can execute the following script to do so:

CERT_PATH=domain.solidangle.eu
sudo rm -r /etc/letsencrypt/live/$CERT_PATH

Use with Nginx related classes

For Let's Encrypt cerificates to be used with the nginx_frontend and nginx_static classes, the letsencrypt_certificate boolean needs to be made true in the class declaration. The same applies do the hasman_web class which includes the nginx_frontend class:

class { 'puppet_infrastructure::hashman_web' : letsencrypt_certificate => true }