diff --git a/.fixtures.yml b/.fixtures.yml
index 3a637f1..80616ed 100644
--- a/.fixtures.yml
+++ b/.fixtures.yml
@@ -5,4 +5,5 @@ fixtures:
concat: https://github.com/puppetlabs/puppetlabs-concat.git
cron_core: https://github.com/puppetlabs/puppetlabs-cron_core.git
stdlib: https://github.com/puppetlabs/puppetlabs-stdlib.git
+ systemd: https://github.com/voxpupuli/puppet-systemd.git
vcsrepo: https://github.com/puppetlabs/puppetlabs-vcsrepo.git
diff --git a/REFERENCE.md b/REFERENCE.md
index 24dbd0d..4f0ce4a 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -19,6 +19,7 @@
* `dehydrated::domains`: Manage the domains.txt file
* `dehydrated::package`: Manage the dehydrated package
* `dehydrated::repo`: Manage the dehydrated code
+* `dehydrated::systemd`: Manage a system timer to refresh certificates
* `dehydrated::user`: Manage the dehydrated user
### Defined types
@@ -63,7 +64,8 @@ The following parameters are available in the `dehydrated` class:
* [`repo_revision`](#-dehydrated--repo_revision)
* [`dependencies`](#-dehydrated--dependencies)
* [`apache_integration`](#-dehydrated--apache_integration)
-* [`cron_integration`](#-dehydrated--cron_integration)
+* [`renewal_provider`](#-dehydrated--renewal_provider)
+* [`renewal_interval`](#-dehydrated--renewal_interval)
* [`dehydrated_user`](#-dehydrated--dehydrated_user)
* [`dehydrated_group`](#-dehydrated--dehydrated_group)
* [`ip_version`](#-dehydrated--ip_version)
@@ -175,13 +177,21 @@ Setup apache to serve the generated challenges.
Default value: `false`
-##### `cron_integration`
+##### `renewal_provider`
-Data type: `Boolean`
+Data type: `Enum['cron','systemd','none']`
-Setup cron to automatically renew certificates.
+Which provider should trigger certificat renewal attempts.
-Default value: `false`
+Default value: `'none'`
+
+##### `renewal_interval`
+
+Data type: `Enum['never','daily','weekly']`
+
+How long to wait between certificate renewal attempts.
+
+Default value: `'daily'`
##### `dehydrated_user`
diff --git a/manifests/cron.pp b/manifests/cron.pp
index 3543516..890ef09 100644
--- a/manifests/cron.pp
+++ b/manifests/cron.pp
@@ -4,19 +4,24 @@
class dehydrated::cron {
assert_private()
- if $dehydrated::cron_integration {
- $ensure = 'present'
- } else {
- $ensure = 'absent'
- }
+ $supported_renewal_intervals = [
+ 'daily',
+ 'weekly',
+ ]
case $facts['os']['family'] {
'Debian', 'RedHat': {
- cron { 'weekly_letsencrypt':
- ensure => absent,
+ cron { 'daily_dehydrated':
+ ensure => bool2str($dehydrated::renewal_interval == 'daily', 'present', 'absent'),
+ command => "${dehydrated::bin} --accept-terms --cron --keep-going",
+ user => $dehydrated::user,
+ weekday => '*',
+ hour => 3,
+ minute => 30,
}
+
cron { 'weekly_dehydrated':
- ensure => $ensure,
+ ensure => bool2str($dehydrated::renewal_interval == 'weekly', 'present', 'absent'),
command => "${dehydrated::bin} --accept-terms --cron --keep-going",
user => $dehydrated::user,
weekday => 0,
@@ -25,17 +30,19 @@
}
}
'FreeBSD': {
- file_line { 'weekly_dehydrated_enable':
- ensure => $ensure,
- path => '/etc/periodic.conf',
- line => 'weekly_dehydrated_enable="YES"',
- match => '^weekly_(letsencrypt|dehydrated)_enable=',
- }
- file_line { 'weekly_dehydrated_user':
- ensure => $ensure,
- path => '/etc/periodic.conf',
- line => "weekly_dehydrated_user=\"${dehydrated::user}\"",
- match => '^weekly_(letsencrypt|dehydrated)_user=',
+ $supported_renewal_intervals.each |$interval| {
+ file_line { "${interval}_dehydrated_enable":
+ ensure => bool2str($interval == $dehydrated::renewal_interval, 'present', 'absent'),
+ path => '/etc/periodic.conf',
+ line => "${interval}_dehydrated_enable=\"YES\"",
+ match => "^${interval}_dehydrated_enable=",
+ }
+ file_line { "${interval}_dehydrated_user":
+ ensure => bool2str($interval == $dehydrated::renewal_interval, 'present', 'absent'),
+ path => '/etc/periodic.conf',
+ line => "${interval}_dehydrated_user=\"${dehydrated::user}\"",
+ match => "^${interval}_dehydrated_user=",
+ }
}
}
default: {
diff --git a/manifests/init.pp b/manifests/init.pp
index b53bf4f..b2d7333 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -10,7 +10,8 @@
# @param repo_revision Revision to fetch from the repository providing dehydrated.
# @param dependencies Extra dependencies needed to run dehydrated.
# @param apache_integration Setup apache to serve the generated challenges.
-# @param cron_integration Setup cron to automatically renew certificates.
+# @param renewal_provider Which provider should trigger certificat renewal attempts.
+# @param renewal_interval How long to wait between certificate renewal attempts.
# @param dehydrated_user Which user should dehydrated run as? This will be implicitly enforced when running as root.
# @param dehydrated_group Which group should dehydrated run as? This will be implicitly enforced when running as root.
# @param ip_version Resolve names to addresses of IP version only. (curl)
@@ -63,7 +64,9 @@
Array[String] $dependencies = [],
Boolean $apache_integration = false,
- Boolean $cron_integration = false,
+
+ Enum['cron','systemd','none'] $renewal_provider = 'none',
+ Enum['never','daily','weekly'] $renewal_interval = 'daily',
Optional[String[1]] $dehydrated_user = undef,
Optional[String[1]] $dehydrated_group = undef,
@@ -135,5 +138,10 @@
include dehydrated::apache
}
- include dehydrated::cron
+ case $renewal_provider {
+ 'cron': { include dehydrated::cron }
+ 'systemd': { include dehydrated::systemd }
+ 'none': {}
+ default: { fail("Unsupported renewal_provider ${renewal_provider}") }
+ }
}
diff --git a/manifests/systemd.pp b/manifests/systemd.pp
new file mode 100644
index 0000000..73f0b9b
--- /dev/null
+++ b/manifests/systemd.pp
@@ -0,0 +1,14 @@
+# @summary Manage a system timer to refresh certificates
+#
+# @api private
+class dehydrated::systemd {
+ assert_private()
+
+ systemd::timer { 'dehydrated.timer':
+ ensure => bool2str($dehydrated::renewal_interval != 'never', 'present', 'absent'),
+ active => true,
+ enable => true,
+ timer_content => epp('dehydrated/systemd.timer.epp'),
+ service_content => epp('dehydrated/systemd.service.epp'),
+ }
+}
diff --git a/spec/classes/cron_spec.rb b/spec/classes/cron_spec.rb
new file mode 100644
index 0000000..14558a5
--- /dev/null
+++ b/spec/classes/cron_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'dehydrated::cron' do
+ let(:pre_condition) do
+ <<~PP
+ class { 'dehydrated':
+ contact_email => 'dummy@example.com',
+ renewal_provider => 'cron',
+ }
+ PP
+ end
+
+ on_supported_os.each do |os, facts|
+ context "on #{os}" do
+ let(:facts) { facts }
+
+ it { is_expected.to compile.with_all_deps }
+
+ if facts[:os]['family'] == 'Debian'
+ it { is_expected.to contain_cron('daily_dehydrated') }
+ it { is_expected.to contain_cron('weekly_dehydrated') }
+ end
+ end
+ end
+end
diff --git a/spec/classes/systemd_spec.rb b/spec/classes/systemd_spec.rb
new file mode 100644
index 0000000..715f35a
--- /dev/null
+++ b/spec/classes/systemd_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'dehydrated::systemd' do
+ let(:pre_condition) do
+ <<~PP
+ class { 'dehydrated':
+ contact_email => 'dummy@example.com',
+ renewal_provider => 'systemd',
+ }
+ PP
+ end
+
+ on_supported_os.each do |os, facts|
+ next unless facts[:os]['family'] == 'Debian'
+
+ context "on #{os}" do
+ let(:facts) { facts }
+
+ it { is_expected.to compile.with_all_deps }
+
+ it { is_expected.to contain_systemd__timer('dehydrated.timer') }
+ end
+ end
+end
diff --git a/templates/systemd.service.epp b/templates/systemd.service.epp
new file mode 100644
index 0000000..2762ff3
--- /dev/null
+++ b/templates/systemd.service.epp
@@ -0,0 +1,10 @@
+# Managed by Puppet, DO NOT EDIT
+
+[Unit]
+Description=Renew dehydrated certificates about to expire
+
+[Service]
+Type=oneshot
+ExecStart=<%= $dehydrated::bin %> --accept-terms --cron --keep-going
+User=<%= $dehydrated::user %>
+Group=<%= $dehydrated::user %>
diff --git a/templates/systemd.timer.epp b/templates/systemd.timer.epp
new file mode 100644
index 0000000..882b7b6
--- /dev/null
+++ b/templates/systemd.timer.epp
@@ -0,0 +1,11 @@
+# Managed by Puppet, DO NOT EDIT
+
+[Unit]
+Description=Trigger dehydrated certificates renewal
+
+[Timer]
+OnCalendar=<%= $dehydrated::renewal_interval %>
+Persistent=true
+
+[Install]
+WantedBy=timers.target