From 779531bd1dbc39412a3b7cf5d12fd3e4c0352a5e Mon Sep 17 00:00:00 2001 From: Sally Young Date: Fri, 18 Oct 2024 21:16:09 +0100 Subject: [PATCH] Add support for certbot-dns-linode (#363) * Add support for certbot-dns-linode * Update manifests/plugin/dns_linode.pp Co-authored-by: Kenyon Ralph * Make api_key required and increase propogation seconds to recommended amount * Regenerate docs * parameter ordering * propogation seconds --------- Co-authored-by: Kenyon Ralph --- REFERENCE.md | 65 ++++++++++++++++++- data/Debian-family.yaml | 1 + data/FreeBSD-family.yaml | 1 + data/RedHat-family.yaml | 1 + data/os/Fedora.yaml | 1 + manifests/certonly.pp | 11 ++++ manifests/plugin/dns_linode.pp | 57 ++++++++++++++++ .../letsencrypt_plugin_dns_linode_spec.rb | 23 +++++++ spec/classes/plugin/dns_linode_spec.rb | 55 ++++++++++++++++ spec/defines/letsencrypt_certonly_spec.rb | 21 ++++++ spec/type_aliases/plugin_spec.rb | 2 +- types/plugin.pp | 1 + 12 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 manifests/plugin/dns_linode.pp create mode 100644 spec/acceptance/letsencrypt_plugin_dns_linode_spec.rb create mode 100644 spec/classes/plugin/dns_linode_spec.rb diff --git a/REFERENCE.md b/REFERENCE.md index 3936bc75..5c3db159 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -10,6 +10,7 @@ * [`letsencrypt`](#letsencrypt): Install and configure Certbot, the LetsEncrypt client * [`letsencrypt::plugin::dns_cloudflare`](#letsencrypt--plugin--dns_cloudflare): Installs and configures the dns-cloudflare plugin +* [`letsencrypt::plugin::dns_linode`](#letsencrypt--plugin--dns_linode): Installs and configures the dns-linode plugin * [`letsencrypt::plugin::dns_rfc2136`](#letsencrypt--plugin--dns_rfc2136): Installs and configures the dns-rfc2136 plugin * [`letsencrypt::plugin::dns_route53`](#letsencrypt--plugin--dns_route53): Installs and configures the dns-route53 plugin * [`letsencrypt::plugin::nginx`](#letsencrypt--plugin--nginx): install and configure the Let's Encrypt nginx plugin @@ -411,6 +412,68 @@ Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. Default value: `10` +### `letsencrypt::plugin::dns_linode` + +This class installs and configures the Let's Encrypt dns-linode plugin. +https://certbot-dns-linode.readthedocs.io + +#### Parameters + +The following parameters are available in the `letsencrypt::plugin::dns_linode` class: + +* [`package_name`](#-letsencrypt--plugin--dns_linode--package_name) +* [`api_key`](#-letsencrypt--plugin--dns_linode--api_key) +* [`version`](#-letsencrypt--plugin--dns_linode--version) +* [`config_path`](#-letsencrypt--plugin--dns_linode--config_path) +* [`manage_package`](#-letsencrypt--plugin--dns_linode--manage_package) +* [`propagation_seconds`](#-letsencrypt--plugin--dns_linode--propagation_seconds) + +##### `package_name` + +Data type: `Optional[String[1]]` + +The name of the package to install when $manage_package is true. + +Default value: `undef` + +##### `api_key` + +Data type: `String[1]` + +Optional string, linode api key value for authentication. + +##### `version` + +Data type: `String[1]` + +string, linode api version. + +Default value: `'4'` + +##### `config_path` + +Data type: `Stdlib::Absolutepath` + +The path to the configuration directory. + +Default value: `"${letsencrypt::config_dir}/dns-linode.ini"` + +##### `manage_package` + +Data type: `Boolean` + +Manage the plugin package. + +Default value: `true` + +##### `propagation_seconds` + +Data type: `Integer` + +Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. + +Default value: `120` + ### `letsencrypt::plugin::dns_rfc2136` This class installs and configures the Let's Encrypt dns-rfc2136 plugin. @@ -1072,5 +1135,5 @@ Variant[Integer[0,31], String[1], Array[ List of accepted plugins -Alias of `Enum['apache', 'standalone', 'webroot', 'nginx', 'dns-azure', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136', 'manual']` +Alias of `Enum['apache', 'standalone', 'webroot', 'nginx', 'dns-azure', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-linode', 'dns-rfc2136', 'manual']` diff --git a/data/Debian-family.yaml b/data/Debian-family.yaml index c52a03b6..a4242b73 100644 --- a/data/Debian-family.yaml +++ b/data/Debian-family.yaml @@ -2,3 +2,4 @@ letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' letsencrypt::plugin::dns_cloudflare::package_name: 'python3-certbot-dns-cloudflare' +letsencrypt::plugin::dns_linode::package_name: 'python3-certbot-dns-linode' diff --git a/data/FreeBSD-family.yaml b/data/FreeBSD-family.yaml index 46a0d2e7..42bc65c1 100644 --- a/data/FreeBSD-family.yaml +++ b/data/FreeBSD-family.yaml @@ -5,3 +5,4 @@ letsencrypt::cron_owner_group: 'wheel' letsencrypt::plugin::dns_rfc2136::package_name: 'py311-certbot-dns-rfc2136' letsencrypt::plugin::dns_route53::package_name: 'py311-certbot-dns-route53' letsencrypt::plugin::dns_cloudflare::package_name: 'py311-certbot-dns-cloudflare' +letsencrypt::plugin::dns_linode::package_name: 'py311-certbot-dns-linode' diff --git a/data/RedHat-family.yaml b/data/RedHat-family.yaml index 35f52041..c8a02590 100644 --- a/data/RedHat-family.yaml +++ b/data/RedHat-family.yaml @@ -3,3 +3,4 @@ letsencrypt::configure_epel: true letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' letsencrypt::plugin::dns_cloudflare::package_name: 'python3-certbot-dns-cloudflare' +letsencrypt::plugin::dns_linode::package_name: 'python3-certbot-dns-linode' diff --git a/data/os/Fedora.yaml b/data/os/Fedora.yaml index 56c3cd56..6541eac1 100644 --- a/data/os/Fedora.yaml +++ b/data/os/Fedora.yaml @@ -2,3 +2,4 @@ letsencrypt::configure_epel: false letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136' letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53' +letsencrypt::plugin::dns_linode::package_name: 'python3-certbot-dns-linode' diff --git a/manifests/certonly.pp b/manifests/certonly.pp index b04f94b5..c9106a1c 100644 --- a/manifests/certonly.pp +++ b/manifests/certonly.pp @@ -205,6 +205,17 @@ ] } + 'dns-linode': { + require letsencrypt::plugin::dns_linode + $_domains = join($domains, '\' -d \'') + $plugin_args = [ + "--cert-name '${cert_name}' -d '${_domains}'", + '--dns-linode', + "--dns-linode-credentials ${letsencrypt::plugin::dns_linode::config_path}", + "--dns-linode-propagation-seconds ${letsencrypt::plugin::dns_linode::propagation_seconds}", + ] + } + 'nginx': { require letsencrypt::plugin::nginx diff --git a/manifests/plugin/dns_linode.pp b/manifests/plugin/dns_linode.pp new file mode 100644 index 00000000..250406bd --- /dev/null +++ b/manifests/plugin/dns_linode.pp @@ -0,0 +1,57 @@ +# @summary Installs and configures the dns-linode plugin +# +# This class installs and configures the Let's Encrypt dns-linode plugin. +# https://certbot-dns-linode.readthedocs.io +# +# @param package_name The name of the package to install when $manage_package is true. +# @param api_key +# Optional string, linode api key value for authentication. +# @param version +# string, linode api version. +# @param config_path The path to the configuration directory. +# @param manage_package Manage the plugin package. +# @param propagation_seconds Number of seconds to wait for the DNS server to propagate the DNS-01 challenge. +# +class letsencrypt::plugin::dns_linode ( + String[1] $api_key, + Optional[String[1]] $package_name = undef, + String[1] $version = '4', + Stdlib::Absolutepath $config_path = "${letsencrypt::config_dir}/dns-linode.ini", + Boolean $manage_package = true, + Integer $propagation_seconds = 120, +) { + include letsencrypt + + if $manage_package { + if ! $package_name { + fail('No package name provided for certbot dns linode plugin.') + } + + $requirement = if $letsencrypt::configure_epel { + Class['epel'] + } else { + undef + } + + package { $package_name: + ensure => $letsencrypt::package_ensure, + require => $requirement, + } + } + + $ini_vars = { + dns_linode_key => $api_key, + dns_linode_version => $version, + } + + file { $config_path: + ensure => file, + owner => 'root', + group => 0, + mode => '0400', + content => epp('letsencrypt/ini.epp', { + vars => { '' => $ini_vars }, + }, + ), + } +} diff --git a/spec/acceptance/letsencrypt_plugin_dns_linode_spec.rb b/spec/acceptance/letsencrypt_plugin_dns_linode_spec.rb new file mode 100644 index 00000000..79909831 --- /dev/null +++ b/spec/acceptance/letsencrypt_plugin_dns_linode_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'letsencrypt::plugin::dns_linode' do + it_behaves_like 'an idempotent resource' do + let(:manifest) do + <<-PUPPET + include letsencrypt + class { 'letsencrypt::plugin::dns_linode': + api_key => 'dummy-linode-api-key', + } + PUPPET + end + end + + describe file('/etc/letsencrypt/dns-linode.ini') do + it { is_expected.to be_file } + it { is_expected.to be_owned_by 'root' } + it { is_expected.to be_grouped_into 'root' } + it { is_expected.to be_mode 400 } + end +end diff --git a/spec/classes/plugin/dns_linode_spec.rb b/spec/classes/plugin/dns_linode_spec.rb new file mode 100644 index 00000000..8f297d36 --- /dev/null +++ b/spec/classes/plugin/dns_linode_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'letsencrypt::plugin::dns_linode' do + on_supported_os.each do |os, os_facts| + context "on #{os} based operating systems" do + let(:facts) { os_facts } + let(:params) { { 'api_key' => 'dummy-linode-api-token' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + } + PUPPET + end + let(:package_name) do + if %w[Debian RedHat].include?(facts['os']['family']) + 'python3-certbot-dns-linode' + elsif %w[FreeBSD].include?(facts['os']['family']) + 'py311-certbot-dns-linode' + end + end + + context 'with required parameters' do + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to compile.with_all_deps + end + end + + describe 'with manage_package => true' do + let(:params) { super().merge(manage_package: true) } + + it do + if package_name.nil? + is_expected.not_to compile + else + is_expected.to contain_class('letsencrypt::plugin::dns_linode').with_package_name(package_name) + is_expected.to contain_package(package_name).with_ensure('installed') + end + end + end + + describe 'with manage_package => false' do + let(:params) { super().merge(manage_package: false, package_name: 'dns-linode-package') } + + it { is_expected.not_to contain_package('dns-linode-package') } + end + end + end + end +end diff --git a/spec/defines/letsencrypt_certonly_spec.rb b/spec/defines/letsencrypt_certonly_spec.rb index 6ded37de..3456b017 100644 --- a/spec/defines/letsencrypt_certonly_spec.rb +++ b/spec/defines/letsencrypt_certonly_spec.rb @@ -206,6 +206,27 @@ class { 'letsencrypt::plugin::dns_cloudflare': it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-cloudflare --cert-name 'foo.example.com' -d 'foo.example.com' --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/dns-cloudflare.ini --dns-cloudflare-propagation-seconds 10" } end + context 'with dns-linode plugin' do + let(:title) { 'foo.example.com' } + let(:params) { { plugin: 'dns-linode', letsencrypt_command: 'letsencrypt' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + config_dir => '/etc/letsencrypt', + } + class { 'letsencrypt::plugin::dns_linode': + package_name => 'irrelevant', + api_key => 'dummy-linode-api-key', + } + PUPPET + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('letsencrypt::plugin::dns_linode') } + it { is_expected.to contain_exec('letsencrypt certonly foo.example.com').with_command "letsencrypt --text --agree-tos --non-interactive certonly --rsa-key-size 4096 -a dns-linode --cert-name 'foo.example.com' -d 'foo.example.com' --dns-linode --dns-linode-credentials /etc/letsencrypt/dns-linode.ini --dns-linode-propagation-seconds 120" } + end + context 'with custom plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'apache' } } diff --git a/spec/type_aliases/plugin_spec.rb b/spec/type_aliases/plugin_spec.rb index 0891edfe..f5df70b5 100644 --- a/spec/type_aliases/plugin_spec.rb +++ b/spec/type_aliases/plugin_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Letsencrypt::Plugin' do - it { is_expected.to allow_values('apache', 'standalone', 'webroot', 'nginx', 'dns-azure', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136') } + it { is_expected.to allow_values('apache', 'standalone', 'webroot', 'nginx', 'dns-azure', 'dns-route53', 'dns-google', 'dns-cloudflare', 'dns-rfc2136', 'dns-linode') } it { is_expected.not_to allow_value(nil) } it { is_expected.not_to allow_value('foo') } it { is_expected.not_to allow_value('custom') } diff --git a/types/plugin.pp b/types/plugin.pp index 56dffb61..6083293a 100644 --- a/types/plugin.pp +++ b/types/plugin.pp @@ -8,6 +8,7 @@ 'dns-route53', 'dns-google', 'dns-cloudflare', + 'dns-linode', 'dns-rfc2136', 'manual', ]