diff --git a/REFERENCE.md b/REFERENCE.md index 4fed1a26..a04a2617 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -11,6 +11,7 @@ * [`letsencrypt`](#letsencrypt): Install and configure Certbot, the LetsEncrypt client * [`letsencrypt::install`](#letsencrypt--install): Installs the Let's Encrypt client. * [`letsencrypt::plugin::dns_cloudflare`](#letsencrypt--plugin--dns_cloudflare): Installs and configures the dns-cloudflare plugin +* [`letsencrypt::plugin::dns_gandi`](#letsencrypt--plugin--dns_gandi): Installs and configures the dns-gandi 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 @@ -408,6 +409,50 @@ Data type: `Stdlib::Absolutepath` Default value: `"${letsencrypt::config_dir}/dns-cloudflare.ini"` +### `letsencrypt::plugin::dns_gandi` + +This class installs and configures the Let's Encrypt dns-gandi plugin. +https://pypi.org/project/certbot-plugin-gandi/ + +#### Parameters + +The following parameters are available in the `letsencrypt::plugin::dns_gandi` class: + +* [`api_key`](#api_key) +* [`package_name`](#package_name) +* [`config_file`](#config_file) +* [`manage_package`](#manage_package) + +##### `api_key` + +Data type: `String[1]` + +Gandi production api key secret. You can get it in you security tab of your account + +##### `package_name` + +Data type: `Optional[String[1]]` + +The name of the package to install when $manage_package is true. + +Default value: ``undef`` + +##### `config_file` + +Data type: `Stdlib::Absolutepath` + +The path to the configuration file. + +Default value: `"${letsencrypt::config_dir}/dns-gandi.ini"` + +##### `manage_package` + +Data type: `Boolean` + +Manage the plugin package. + +Default value: ``true`` + ### `letsencrypt::plugin::dns_rfc2136` This class installs and configures the Let's Encrypt dns-rfc2136 plugin. @@ -1059,5 +1104,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-rfc2136', 'dns-gandi', 'manual']` diff --git a/data/os/Debian/11.yaml b/data/os/Debian/11.yaml new file mode 100644 index 00000000..78ee20ed --- /dev/null +++ b/data/os/Debian/11.yaml @@ -0,0 +1,2 @@ +--- +letsencrypt::plugin::dns_gandi::package_name: python3-certbot-dns-gandi diff --git a/data/os/Ubuntu/20.04.yaml b/data/os/Ubuntu/20.04.yaml new file mode 100644 index 00000000..78ee20ed --- /dev/null +++ b/data/os/Ubuntu/20.04.yaml @@ -0,0 +1,2 @@ +--- +letsencrypt::plugin::dns_gandi::package_name: python3-certbot-dns-gandi diff --git a/data/os/Ubuntu/22.04.yaml b/data/os/Ubuntu/22.04.yaml new file mode 100644 index 00000000..78ee20ed --- /dev/null +++ b/data/os/Ubuntu/22.04.yaml @@ -0,0 +1,2 @@ +--- +letsencrypt::plugin::dns_gandi::package_name: python3-certbot-dns-gandi diff --git a/manifests/certonly.pp b/manifests/certonly.pp index 1eb91435..6b8b441a 100644 --- a/manifests/certonly.pp +++ b/manifests/certonly.pp @@ -214,6 +214,17 @@ } } + 'dns-gandi': { + require letsencrypt::plugin::dns_gandi + $_domains = join($domains, '\' -d \'') + $plugin_args = [ + "--cert-name '${cert_name}' -d", + "'${_domains}'", + '-a certbot-plugin-gandi:dns', + "--certbot-plugin-gandi:dns-credentials ${letsencrypt::config_dir}/dns-gandi.ini", + ] + } + default: { if $ensure == 'present' { $_domains = join($domains, '\' -d \'') diff --git a/manifests/plugin/dns_gandi.pp b/manifests/plugin/dns_gandi.pp new file mode 100644 index 00000000..c920993d --- /dev/null +++ b/manifests/plugin/dns_gandi.pp @@ -0,0 +1,39 @@ +# @summary Installs and configures the dns-gandi plugin +# +# This class installs and configures the Let's Encrypt dns-gandi plugin. +# https://pypi.org/project/certbot-plugin-gandi/ +# +# @param api_key Gandi production api key secret. You can get it in you security tab of your account +# @param package_name The name of the package to install when $manage_package is true. +# @param config_file The path to the configuration file. +# @param manage_package Manage the plugin package. +# +class letsencrypt::plugin::dns_gandi ( + String[1] $api_key, + String[1] $package_name, + Stdlib::Absolutepath $config_file = "${letsencrypt::config_dir}/dns-gandi.ini", + Boolean $manage_package = true, +) { + require letsencrypt + + if $manage_package { + package { $package_name: + ensure => installed, + before => File[$config_file], + } + } + + $ini_vars = { + 'certbot_plugin_gandi:dns_api_key' => $api_key, + } + + file { $config_file: + ensure => file, + owner => 'root', + group => 'root', + mode => '0400', + content => epp('letsencrypt/ini.epp', { + vars => { '' => $ini_vars }, + }), + } +} diff --git a/spec/acceptance/letsencrypt_plugin_dns_gandi_spec.rb b/spec/acceptance/letsencrypt_plugin_dns_gandi_spec.rb new file mode 100644 index 00000000..8f026857 --- /dev/null +++ b/spec/acceptance/letsencrypt_plugin_dns_gandi_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper_acceptance' + +describe 'letsencrypt::plugin::dns_gandi', if: supported_os_gandi(fact('os')) do + it_behaves_like 'an idempotent resource' do + let(:manifest) do + <<-PUPPET + include letsencrypt + class { 'letsencrypt::plugin::dns_gandi': + api_key => 'dummy-gandi-api-token', + } + PUPPET + end + end + + describe file('/etc/letsencrypt/dns-gandi.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_gandi_spec.rb b/spec/classes/plugin/dns_gandi_spec.rb new file mode 100644 index 00000000..6f87ceec --- /dev/null +++ b/spec/classes/plugin/dns_gandi_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'letsencrypt::plugin::dns_gandi' do + on_supported_os.each do |os, facts| + next unless supported_os_gandi(facts[:os]) + + context "on #{os} based operating systems" do + let(:facts) { facts } + let(:params) { { 'api_key' => 'dummy-gandi-api-token' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + } + PUPPET + end + let(:package_name) do + 'python3-certbot-dns-gandi' + end + + context 'with required parameters' do + it do + is_expected.to compile.with_all_deps + end + + describe 'with manage_package => true' do + let(:params) { super().merge(manage_package: true) } + + it do + is_expected.to contain_class('letsencrypt::plugin::dns_gandi').with_package_name(package_name) + is_expected.to contain_package(package_name).with_ensure('installed') + end + end + + describe 'with manage_package => false' do + let(:params) { super().merge(manage_package: false, package_name: 'dns-gandi-package') } + + it { is_expected.not_to contain_package('dns-gandi-package') } + end + end + end + end +end diff --git a/spec/defines/letsencrypt_certonly_spec.rb b/spec/defines/letsencrypt_certonly_spec.rb index 88f78c58..d6107aa1 100644 --- a/spec/defines/letsencrypt_certonly_spec.rb +++ b/spec/defines/letsencrypt_certonly_spec.rb @@ -207,6 +207,45 @@ 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-gandi plugin' do + let(:title) { 'foo.example.com' } + let(:params) { { plugin: 'dns-gandi', letsencrypt_command: 'letsencrypt' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + config_dir => '/etc/letsencrypt', + } + class { 'letsencrypt::plugin::dns_gandi': + package_name => 'irrelevant', + api_key => 'dummy-gandi-api-token', + } + PUPPET + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('letsencrypt::plugin::dns_gandi') } + 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-gandi --cert-name 'foo.example.com' -d 'foo.example.com' -a certbot-plugin-gandi:dns --certbot-plugin-gandi:dns-credentials /etc/letsencrypt/dns-gandi.ini" } + end + + context 'with dns-gandi plugin without api_key' do + let(:title) { 'foo.example.com' } + let(:params) { { plugin: 'dns-gandi', letsencrypt_command: 'letsencrypt' } } + let(:pre_condition) do + <<-PUPPET + class { 'letsencrypt': + email => 'foo@example.com', + config_dir => '/etc/letsencrypt', + } + class { 'letsencrypt::plugin::dns_gandi': + package_name => 'irrelevant', + } + PUPPET + end + + it { is_expected.to compile.and_raise_error(%r{expects a value for parameter 'api_key'}) } + end + context 'with custom plugin' do let(:title) { 'foo.example.com' } let(:params) { { plugin: 'apache' } } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6515b7bf..40a560a0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,6 +8,7 @@ ENV['COVERAGE'] ||= 'yes' if Dir.exist?(File.expand_path('../lib', __dir__)) require 'voxpupuli/test/spec_helper' +require 'spec_helper_local' add_mocked_facts! diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index b4f352d4..6421f5ba 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'voxpupuli/acceptance/spec_helper_acceptance' +require 'spec_helper_local' configure_beaker do |host| # docker image does not provide cron in all cases diff --git a/spec/spec_helper_local.rb b/spec/spec_helper_local.rb new file mode 100644 index 00000000..ae675a9b --- /dev/null +++ b/spec/spec_helper_local.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +def supported_os_gandi(os) + # Gandi plugin is only supported on debian 11 and ubuntu 20.04 and superiors + (os['name'] == 'Debian' && os['release']['major'].to_i >= 11) || (os['name'] == 'Ubuntu' && os['release']['major'].to_i >= 20) +end diff --git a/spec/type_aliases/plugin_spec.rb b/spec/type_aliases/plugin_spec.rb index 0891edfe..657c1e5b 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-gandi') } 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..7af0a3bf 100644 --- a/types/plugin.pp +++ b/types/plugin.pp @@ -9,5 +9,6 @@ 'dns-google', 'dns-cloudflare', 'dns-rfc2136', + 'dns-gandi', 'manual', ]