Skip to content

Commit a0bfa89

Browse files
CallumBanberybkuebler
authored andcommitted
Add Cloudflare DNS plugin support
Adding feature support for the Certbot DNS Cloudflare plugin. The plugin itself allows for two types of authentication, API token or Global API Key and corresponding Email; as Cloudflare recommends the use of API tokens since they're more secure the plugin will prioritize token authentication if both a token and key are provided.
1 parent 291f4b2 commit a0bfa89

File tree

11 files changed

+271
-0
lines changed

11 files changed

+271
-0
lines changed

REFERENCE.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
* [`letsencrypt`](#letsencrypt): Install and configure Certbot, the LetsEncrypt client
1212
* [`letsencrypt::install`](#letsencryptinstall): Installs the Let's Encrypt client.
13+
* [`letsencrypt::plugin::dns_cloudflare`](#letsencryptplugindns_cloudflare): Installs and configures the dns-cloudflare plugin
1314
* [`letsencrypt::plugin::dns_rfc2136`](#letsencryptplugindns_rfc2136): Installs and configures the dns-rfc2136 plugin
1415
* [`letsencrypt::plugin::dns_route53`](#letsencryptplugindns_route53): Installs and configures the dns-route53 plugin
1516
* [`letsencrypt::plugin::nginx`](#letsencryptpluginnginx): install and configure the Let's Encrypt nginx plugin
@@ -329,6 +330,84 @@ Name of package to use when installing the client package.
329330

330331
Default value: `$letsencrypt::package_name`
331332

333+
### <a name="letsencryptplugindns_cloudflare"></a>`letsencrypt::plugin::dns_cloudflare`
334+
335+
This class installs and configures the Let's Encrypt dns-cloudflare plugin.
336+
https://certbot-dns-cloudflare.readthedocs.io
337+
338+
#### Parameters
339+
340+
The following parameters are available in the `letsencrypt::plugin::dns_cloudflare` class:
341+
342+
* [`package_name`](#package_name)
343+
* [`api_key`](#api_key)
344+
* [`api_token`](#api_token)
345+
* [`email`](#email)
346+
* [`config_dir`](#config_dir)
347+
* [`manage_package`](#manage_package)
348+
* [`propagation_seconds`](#propagation_seconds)
349+
* [`config_path`](#config_path)
350+
351+
##### <a name="package_name"></a>`package_name`
352+
353+
Data type: `Optional[String[1]]`
354+
355+
The name of the package to install when $manage_package is true.
356+
357+
Default value: ``undef``
358+
359+
##### <a name="api_key"></a>`api_key`
360+
361+
Data type: `Optional[String[1]]`
362+
363+
Optional string, cloudflare api key value for authentication.
364+
365+
Default value: ``undef``
366+
367+
##### <a name="api_token"></a>`api_token`
368+
369+
Data type: `Optional[String[1]]`
370+
371+
Optional string, cloudflare api token value for authentication.
372+
373+
Default value: ``undef``
374+
375+
##### <a name="email"></a>`email`
376+
377+
Data type: `Optional[String[1]]`
378+
379+
Optional string, cloudflare account email address, used in conjunction with api_key.
380+
381+
Default value: ``undef``
382+
383+
##### <a name="config_dir"></a>`config_dir`
384+
385+
The path to the configuration directory.
386+
387+
##### <a name="manage_package"></a>`manage_package`
388+
389+
Data type: `Boolean`
390+
391+
Manage the plugin package.
392+
393+
Default value: ``true``
394+
395+
##### <a name="propagation_seconds"></a>`propagation_seconds`
396+
397+
Data type: `Integer`
398+
399+
Number of seconds to wait for the DNS server to propagate the DNS-01 challenge.
400+
401+
Default value: `10`
402+
403+
##### <a name="config_path"></a>`config_path`
404+
405+
Data type: `Stdlib::Absolutepath`
406+
407+
408+
409+
Default value: `"${letsencrypt::config_dir}/dns-cloudflare.ini"`
410+
332411
### <a name="letsencryptplugindns_rfc2136"></a>`letsencrypt::plugin::dns_rfc2136`
333412

334413
This class installs and configures the Let's Encrypt dns-rfc2136 plugin.

data/Debian-family.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
---
22
letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136'
33
letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53'
4+
letsencrypt::plugin::dns_cloudflare::package_name: 'python3-certbot-dns-cloudflare'

data/FreeBSD-family.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ letsencrypt::config_dir: '/usr/local/etc/letsencrypt'
44
letsencrypt::cron_owner_group: 'wheel'
55
letsencrypt::plugin::dns_rfc2136::package_name: 'py38-certbot-dns-rfc2136'
66
letsencrypt::plugin::dns_route53::package_name: 'py38-certbot-dns-route53'
7+
letsencrypt::plugin::dns_cloudflare::package_name: 'py38-certbot-dns-cloudflare'

data/RedHat-family.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
letsencrypt::configure_epel: true
33
letsencrypt::plugin::dns_rfc2136::package_name: 'python3-certbot-dns-rfc2136'
44
letsencrypt::plugin::dns_route53::package_name: 'python3-certbot-dns-route53'
5+
letsencrypt::plugin::dns_cloudflare::package_name: 'python3-certbot-dns-cloudflare'

data/os/CentOS/7.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
22
letsencrypt::plugin::dns_rfc2136::package_name: 'python2-certbot-dns-rfc2136'
33
letsencrypt::plugin::dns_route53::package_name: 'python2-certbot-dns-route53'
4+
letsencrypt::plugin::dns_cloudflare::package_name: 'python2-certbot-dns-cloudflare'
45
letsencrypt::plugin::nginx::package_name: 'python2-certbot-nginx'

data/os/RedHat/7.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
22
letsencrypt::plugin::dns_rfc2136::package_name: 'python2-certbot-dns-rfc2136'
33
letsencrypt::plugin::dns_route53::package_name: 'python2-certbot-dns-route53'
4+
letsencrypt::plugin::dns_cloudflare::package_name: 'python2-certbot-dns-cloudflare'
45
letsencrypt::plugin::nginx::package_name: 'python2-certbot-nginx'

manifests/certonly.pp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,17 @@
168168
$plugin_args = ["--cert-name '${cert_name}'"] + $_plugin_args
169169
}
170170

171+
'dns-cloudflare': {
172+
require letsencrypt::plugin::dns_cloudflare
173+
$_domains = join($domains, '\' -d \'')
174+
$plugin_args = [
175+
"--cert-name '${cert_name}' -d '${_domains}'",
176+
'--dns-cloudflare',
177+
"--dns-cloudflare-credentials ${letsencrypt::plugin::dns_cloudflare::config_path}",
178+
"--dns-cloudflare-propagation-seconds ${letsencrypt::plugin::dns_cloudflare::propagation_seconds}",
179+
]
180+
}
181+
171182
'dns-rfc2136': {
172183
require letsencrypt::plugin::dns_rfc2136
173184
$_domains = join($domains, '\' -d \'')

manifests/plugin/dns_cloudflare.pp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# @summary Installs and configures the dns-cloudflare plugin
2+
#
3+
# This class installs and configures the Let's Encrypt dns-cloudflare plugin.
4+
# https://certbot-dns-cloudflare.readthedocs.io
5+
#
6+
# @param package_name The name of the package to install when $manage_package is true.
7+
# @param api_key
8+
# Optional string, cloudflare api key value for authentication.
9+
# @param api_token
10+
# Optional string, cloudflare api token value for authentication.
11+
# @param email
12+
# Optional string, cloudflare account email address, used in conjunction with api_key.
13+
# @param config_dir The path to the configuration directory.
14+
# @param manage_package Manage the plugin package.
15+
# @param propagation_seconds Number of seconds to wait for the DNS server to propagate the DNS-01 challenge.
16+
#
17+
class letsencrypt::plugin::dns_cloudflare (
18+
Optional[String[1]] $package_name = undef,
19+
Optional[String[1]] $api_key = undef,
20+
Optional[String[1]] $api_token = undef,
21+
Optional[String[1]] $email = undef,
22+
Stdlib::Absolutepath $config_path = "${letsencrypt::config_dir}/dns-cloudflare.ini",
23+
Boolean $manage_package = true,
24+
Integer $propagation_seconds = 10,
25+
) {
26+
require letsencrypt::install
27+
28+
if ! $api_key and ! $api_token {
29+
fail('No authentication method provided, please specify either api_token or api_key and api_email.')
30+
}
31+
32+
if $manage_package {
33+
if ! $package_name {
34+
fail('No package name provided for certbot dns cloudflare plugin.')
35+
}
36+
37+
package { $package_name:
38+
ensure => installed,
39+
}
40+
}
41+
42+
if $api_token {
43+
$ini_vars = {
44+
dns_cloudflare_api_token => $api_token,
45+
}
46+
}
47+
else {
48+
if ! $email {
49+
fail('Cloudflare email not provided for specified api_key.')
50+
}
51+
52+
$ini_vars = {
53+
dns_cloudflare_api_key => $api_key,
54+
dns_cloudflare_email => $email,
55+
}
56+
}
57+
58+
file { $config_path:
59+
ensure => file,
60+
owner => 'root',
61+
group => 'root',
62+
mode => '0400',
63+
content => epp('letsencrypt/ini.epp', {
64+
vars => { '' => $ini_vars },
65+
}),
66+
}
67+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper_acceptance'
4+
5+
describe 'letsencrypt::plugin::dns_cloudflare' do
6+
it_behaves_like 'an idempotent resource' do
7+
let(:manifest) do
8+
<<-PUPPET
9+
class { 'letsencrypt' :
10+
email => '[email protected]',
11+
config => {
12+
'server' => 'https://acme-staging-v02.api.letsencrypt.org/directory',
13+
},
14+
}
15+
class { 'letsencrypt::plugin::dns_cloudflare':
16+
api_token => 'dummy-cloudflare-api-token',
17+
}
18+
PUPPET
19+
end
20+
end
21+
22+
describe file('/etc/letsencrypt/dns-cloudflare.ini') do
23+
it { is_expected.to be_file }
24+
it { is_expected.to be_owned_by 'root' }
25+
it { is_expected.to be_grouped_into 'root' }
26+
it { is_expected.to be_mode 400 }
27+
end
28+
end
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe 'letsencrypt::plugin::dns_cloudflare' do
6+
on_supported_os.each do |os, os_facts|
7+
context "on #{os} based operating systems" do
8+
let(:facts) { os_facts }
9+
let(:params) { { 'api_token' => 'dummy-cloudflare-api-token' } }
10+
let(:pre_condition) do
11+
<<-PUPPET
12+
class { 'letsencrypt':
13+
email => '[email protected]',
14+
}
15+
PUPPET
16+
end
17+
let(:package_name) do
18+
osname = facts[:os]['name']
19+
osrelease = facts[:os]['release']['major']
20+
osfull = "#{osname}-#{osrelease}"
21+
if %w[RedHat-7 CentOS-7].include?(osfull)
22+
'python2-certbot-dns-cloudflare'
23+
elsif %w[Debian RedHat].include?(facts[:os]['family'])
24+
'python3-certbot-dns-cloudflare'
25+
elsif %w[FreeBSD].include?(facts[:os]['family'])
26+
'py38-certbot-dns-cloudflare'
27+
end
28+
end
29+
30+
context 'with required parameters' do
31+
it do
32+
if package_name.nil?
33+
is_expected.not_to compile
34+
else
35+
is_expected.to compile.with_all_deps
36+
end
37+
end
38+
39+
describe 'with manage_package => true' do
40+
let(:params) { super().merge(manage_package: true) }
41+
42+
it do
43+
if package_name.nil?
44+
is_expected.not_to compile
45+
else
46+
is_expected.to contain_class('letsencrypt::plugin::dns_cloudflare').with_package_name(package_name)
47+
is_expected.to contain_package(package_name).with_ensure('installed')
48+
end
49+
end
50+
end
51+
52+
describe 'with manage_package => false' do
53+
let(:params) { super().merge(manage_package: false, package_name: 'dns-cloudflare-package') }
54+
55+
it { is_expected.not_to contain_package('dns-cloudflare-package') }
56+
end
57+
end
58+
end
59+
end
60+
end

0 commit comments

Comments
 (0)