From d21390519026e6d31ffb2cfbb08bd77aebfce7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 5 Jan 2023 16:29:24 +0100 Subject: Initial code. --- data/Archlinux.yaml | 3 +++ data/FreeBSD.yaml | 3 +++ files/letsencrypt-renew.service | 8 ++++++++ files/letsencrypt-renew.timer | 8 ++++++++ manifests/cert.pp | 39 ++++++++++++++++++++++++++++++++++++++ manifests/domain.pp | 18 ++++++++++++++++++ manifests/init.pp | 28 +++++++++++++++++++++++++++ manifests/nginx.pp | 42 +++++++++++++++++++++++++++++++++++++++++ manifests/renew.pp | 13 +++++++++++++ manifests/renew/cron.pp | 6 ++++++ manifests/renew/setup.pp | 17 +++++++++++++++++ manifests/renew/systemd.pp | 16 ++++++++++++++++ metadata.json | 35 ++++++++++++++++++++++++++++++++++ 13 files changed, 236 insertions(+) create mode 100644 data/Archlinux.yaml create mode 100644 data/FreeBSD.yaml create mode 100644 files/letsencrypt-renew.service create mode 100644 files/letsencrypt-renew.timer create mode 100644 manifests/cert.pp create mode 100644 manifests/domain.pp create mode 100644 manifests/init.pp create mode 100644 manifests/nginx.pp create mode 100644 manifests/renew.pp create mode 100644 manifests/renew/cron.pp create mode 100644 manifests/renew/setup.pp create mode 100644 manifests/renew/systemd.pp create mode 100644 metadata.json diff --git a/data/Archlinux.yaml b/data/Archlinux.yaml new file mode 100644 index 0000000..386801e --- /dev/null +++ b/data/Archlinux.yaml @@ -0,0 +1,3 @@ +--- +letsencrypt::nginx::certbot_plugin_package: certbot-nginx +letsencrypt::apache::certbot_plugin_package: certbot-apache diff --git a/data/FreeBSD.yaml b/data/FreeBSD.yaml new file mode 100644 index 0000000..6e2fe58 --- /dev/null +++ b/data/FreeBSD.yaml @@ -0,0 +1,3 @@ +--- +letsencrypt::nginx::certbot_plugin_package: py38-certbot-nginx +letsencrypt::apache::certbot_plugin_package: py38-certbot-apache diff --git a/files/letsencrypt-renew.service b/files/letsencrypt-renew.service new file mode 100644 index 0000000..253f260 --- /dev/null +++ b/files/letsencrypt-renew.service @@ -0,0 +1,8 @@ +[Unit] +Description=Renew certificate %i +Documentation=man:certbot(1) + +[Service] +Type=oneshot +EnvironmentFile=/etc/letsencrypt/env/%i +ExecStart=certbot --text --agree-tos --non-interactive certonly --rsa-key-size 4086 --cert-name '%i' -a $AUTHENTICATOR $DOMAINS --post-hook $POST_HOOK --quiet --keep-until-expiring diff --git a/files/letsencrypt-renew.timer b/files/letsencrypt-renew.timer new file mode 100644 index 0000000..f9c5d7a --- /dev/null +++ b/files/letsencrypt-renew.timer @@ -0,0 +1,8 @@ +[Unit] +Description=Renew certificate %i +Documentation=man:certbot(1) + +[Timer] +FixedRandomDelay=true +OnCalendar=*-*-* 00:00 +RandomizedDelaySec=24h diff --git a/manifests/cert.pp b/manifests/cert.pp new file mode 100644 index 0000000..a8cc94e --- /dev/null +++ b/manifests/cert.pp @@ -0,0 +1,39 @@ +# A single certificate +# TODO possibly default cert_name to $::fqdn instead +define letsencrypt::cert ( + String $cert_name => $::name, + Enum['present', 'absent'] $ensure => 'present', + Boolean $include_self => true, +) { + + # TODO these env files are systemd specific + # TODO concat::fragment is clumsy, look at re-implementing the + # functionallity internally + + concat { "${letsencrypt::config_dir}/env/${cert_name}": + ensure => present, + warn => true, + } + + concat::fragment { "letsencrypt ${cert_name} preamble": + target => "${letsencrypt::config_dir}/env/${cert_name}", + order => '0', + content => @(EOF) + AUTHENTICATOR = '' + POST_HOOK = '' + DOMAINS = + |- EOF + } + concat::fragment { "letsencrypt ${cert_name} postamble": + target => "${letsencrypt::config_dir}/env/${cert_name}", + order => '99', + content => "\n\n", + } + + if $include_self { + letsencrypt::domain { $cert_name: } + } + + letsencrypt::renew { $cert_name: + } +} diff --git a/manifests/domain.pp b/manifests/domain.pp new file mode 100644 index 0000000..cc9e2af --- /dev/null +++ b/manifests/domain.pp @@ -0,0 +1,18 @@ +# A single domain belonging to a certificate +# Example +# letsencrypt::domain { 'www.example.com': +# cert_name => 'example.com', +# } +define letsencrypt::domain ( + String $domain_name => $name, + String $cert_name => $::fqdn, +) { + ensure_resource('letsencrypt::cert', $cert_name, { + ensure => present, + }) + + concat::fragment { "letsencrypt ${cert_name} - ${domain_name}": + target => "${letsencrypt::config_dir}/env/${cert_name}", + content => " -d ${domain_name}", + } +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..0fedb85 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,28 @@ +class letsencrypt ( + String $email, + String $default_cert_name = $::fqdn, + Stdlib::Unixpath $config_dir = '/etc/letsencrypt', + Boolean $default_cert = true, + # TODO renewal provider here? +) { + + if $default_cert { + letsencrypt::cert { $default_cert_name: + ensure => present, + } + } + + + file { $config_dir: + ensure => directory, + } + + file { "${config_dir}/cli.ini": + content = @("EOF") + email = $email + | EOF + } + + + include letsencrypt::renew::setup +} diff --git a/manifests/nginx.pp b/manifests/nginx.pp new file mode 100644 index 0000000..82fcda4 --- /dev/null +++ b/manifests/nginx.pp @@ -0,0 +1,42 @@ +# Sets up nginx specific configuration, and provides access to +# variables for enterpolating into nginx configurations +# Usage: +# +# These use the default cert name +# +# nginx::resource::server { 'servername': +# * => $letsescrypt::nginx::server_ssl +# } +# $letsencrypt::nginx::location_ssl +class letsencrypt::nginx ( + Boolean $manage_package: true, + String $certbot_plugin_package, +) { + + # TODO $cert_path + $cert_path = "/etc/letsencrypt/live/${certname}" + + $server_ssl = if $ssl_configured { + { + ssl => true, + ssl_redirect => true, + ssl_cert => "${cert_path}/fullchain.pem", + ssl_key => "${cert_path}/privkey.pem", + } + } else { + { + ssl => false, + } + } + + $location_ssl = if $ssl_configured { + { + ssl => true, + ssl_only => true, + } + } else { + { + ssl => false, + } + } +} diff --git a/manifests/renew.pp b/manifests/renew.pp new file mode 100644 index 0000000..681a236 --- /dev/null +++ b/manifests/renew.pp @@ -0,0 +1,13 @@ +define letsencrypt::renew ( + String $cert_name = $name, +) { + + # TODO this is systemd specific + # TODO ensure letsencrypt::renew::setup is included beforehand + service { "${letsencrypt::renew::systemd::service_name}@${cert_name}.timer": + ensure => 'running', + enable => true, + } + +} + diff --git a/manifests/renew/cron.pp b/manifests/renew/cron.pp new file mode 100644 index 0000000..91d5483 --- /dev/null +++ b/manifests/renew/cron.pp @@ -0,0 +1,6 @@ +# Handles renewal certificates through CRON +# private +class letsencrypt::renew::cron ( +) { + fail("Not yet implemented") +} diff --git a/manifests/renew/setup.pp b/manifests/renew/setup.pp new file mode 100644 index 0000000..360136c --- /dev/null +++ b/manifests/renew/setup.pp @@ -0,0 +1,17 @@ +# Sets up timers for automatically renewing certificates +# TODO +# - make provider OS dependant +# - is provider the correct name? +# private +class letsencrypt::renew::setup ( + Enum['systemd', 'cron'] $provider = 'systemd', +) { + file { [ + '/etc/letsencrypt/env', + ]: + ensure => directory, + } + + include "letsencrypt::renew::${provider}" +} + diff --git a/manifests/renew/systemd.pp b/manifests/renew/systemd.pp new file mode 100644 index 0000000..4b6f23e --- /dev/null +++ b/manifests/renew/systemd.pp @@ -0,0 +1,16 @@ +# Handles renewal certificates through systemd timers +# private +class letsencrypt::renew::systemd ( + String $service_name = 'letsencrypt-renew' + String $service_path = '/etc/systemd/system', +) { + + + file { "${service_path}/${service_name}@.service": + source => "puppet:///modules/${module_name}/letsencrypt-renew.service", + } + + file { "${service_path}/${service_name}@.timer": + source => "puppet:///modules/${module_name}/letsencrypt-renew.timer", + } +} diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..8ec88ca --- /dev/null +++ b/metadata.json @@ -0,0 +1,35 @@ +{ + "name": "HugoNikanor-letsencrypt", + "version": "0.1.0", + "author": "HugoNikanor", + "license": "Apache-2.0", + "tags": [ + "letsencrypt", + "let's encrypt", + "certbot", + "acme" + ], + "operatingsystem_support": [ + { + "operatingsystem": "Archlinux" + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "7", "8" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "36" + ] + }, + { + "operatingsystem": "FreeBSD, Debian, Ubuntu, ..." + } + ], + "dependencies": { + "stdlib": {} + } +} -- cgit v1.2.3