diff --git a/REFERENCE.md b/REFERENCE.md index e807f6af3b684dddffc5ab5a2860932adf632e4a..b85156e40a0c121f6290b5c8bb66450f05986c0a 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -46,6 +46,13 @@ The following parameters are available in the `sympa` class: * [`listmaster`](#-sympa--listmaster) * [`lang`](#-sympa--lang) * [`topics`](#-sympa--topics) +* [`dkim_feature`](#-sympa--dkim_feature) +* [`dkim_selector`](#-sympa--dkim_selector) +* [`dkim_signature_apply_on`](#-sympa--dkim_signature_apply_on) +* [`dkim_private_key`](#-sympa--dkim_private_key) +* [`dmarc_protection`](#-sympa--dmarc_protection) +* [`dmarc_protection_mode`](#-sympa--dmarc_protection_mode) +* [`dmarc_protection_phrase`](#-sympa--dmarc_protection_phrase) ##### <a name="-sympa--manage_user"></a>`manage_user` @@ -176,6 +183,62 @@ Defines topics (categories) of the mailing lists. Default value: `{}` +##### <a name="-sympa--dkim_feature"></a>`dkim_feature` + +Data type: `Boolean` + +If true, Sympa may verify DKIM signatures of incoming messages and/or insert DKIM signature to outgoing messages. + +Default value: `false` + +##### <a name="-sympa--dkim_selector"></a>`dkim_selector` + +Data type: `String[1]` + +Selector for DNS lookup of DKIM public key. + +Default value: `'lists-sympa'` + +##### <a name="-sympa--dkim_signature_apply_on"></a>`dkim_signature_apply_on` + +Data type: `Array[String[1]]` + +It controls in which case messages must be signed using DKIM + +Default value: `['any']` + +##### <a name="-sympa--dkim_private_key"></a>`dkim_private_key` + +Data type: `Optional[String[1]]` + +RSA private key used by DKIM, must contain a PEM encoded private key + +Default value: `undef` + +##### <a name="-sympa--dmarc_protection"></a>`dmarc_protection` + +Data type: `Boolean` + +If true, enable some dmarc protections + +Default value: `false` + +##### <a name="-sympa--dmarc_protection_mode"></a>`dmarc_protection_mode` + +Data type: `Array[String[1]]` + +Protection modes. Details : https://www.sympa.community/gpldoc/man/sympa_config.5.html + +Default value: `['all']` + +##### <a name="-sympa--dmarc_protection_phrase"></a>`dmarc_protection_phrase` + +Data type: `String[1]` + +This is the format to be used for the sender name part of the new From header field. + +Default value: `'name_via_list'` + ## Data types ### <a name="Sympa--Topics"></a>`Sympa::Topics` diff --git a/manifests/init.pp b/manifests/init.pp index fc481e624a5e006f7653f74656549ef46fccd269..d5dc6ff41db8d85beae99d45af753968a65b4c64 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -20,6 +20,13 @@ # @param listmaster Email addresses of listmasters # @param lang Supported language # @param topics Defines topics (categories) of the mailing lists. +# @param dkim_feature If true, Sympa may verify DKIM signatures of incoming messages and/or insert DKIM signature to outgoing messages. +# @param dkim_selector Selector for DNS lookup of DKIM public key. +# @param dkim_signature_apply_on It controls in which case messages must be signed using DKIM +# @param dkim_private_key RSA private key used by DKIM, must contain a PEM encoded private key +# @param dmarc_protection If true, enable some dmarc protections +# @param dmarc_protection_mode Protection modes. Details : https://www.sympa.community/gpldoc/man/sympa_config.5.html +# @param dmarc_protection_phrase This is the format to be used for the sender name part of the new From header field. # # @example # include sympa @@ -40,6 +47,13 @@ class sympa ( Array[Stdlib::Email] $listmaster = ['listmaster@example.org'], Enum['fr'] $lang = 'fr', Sympa::Topics $topics = {}, + Boolean $dkim_feature = false, + String[1] $dkim_selector = 'lists-sympa', + Optional[String[1]] $dkim_private_key = undef, + Array[String[1]] $dkim_signature_apply_on = ['any'], + Boolean $dmarc_protection = false, + Array[String[1]] $dmarc_protection_mode = ['all'], + String[1] $dmarc_protection_phrase = 'name_via_list', ) { $_required = [ 'debconf-utils', @@ -194,7 +208,34 @@ class sympa ( ], } - if $topics.type == Undef { + if $dkim_feature { + if !$dkim_private_key { + fail('With dkim_feature true, dkim_private_key is mandatory.') + } + + $_dkim_directories = [ + "${sympa::prefix_path}/${sympa::sysconf_dir}/dkim", + "${sympa::prefix_path}/${sympa::sysconf_dir}/dkim/${sympa::listdomain}", + ] + + file { $_dkim_directories: + ensure => directory, + mode => '0700', + owner => $sympa::user, + group => $sympa::group, + require => File["${sympa::prefix_path}/${sympa::sysconf_dir}/sympa.conf"], + } + -> file { "${sympa::prefix_path}/${sympa::sysconf_dir}/dkim/${sympa::listdomain}/${sympa::dkim_selector}.key": + ensure => file, + mode => '0600', + owner => $sympa::user, + group => $sympa::group, + content => epp('sympa/dkim_priv.key.epp'), + notify => Service['sympa.service'], + } + } + + if $sympa::topics.type == Undef { # topics are undefined so Sympa defaults are used file { "${sympa::prefix_path}/${sympa::sysconf_dir}/topics.conf": ensure => 'absent', diff --git a/spec/acceptance/sympa_spec.rb b/spec/acceptance/sympa_spec.rb index 69f1a5f131fd26ffba7acfd8741053fe24f6bc1e..7f2b963b53efbe54d6d90733a3fd8b82e89f9562 100644 --- a/spec/acceptance/sympa_spec.rb +++ b/spec/acceptance/sympa_spec.rb @@ -30,4 +30,52 @@ describe 'sympa' do end end end + + context 'with basic DKIM and DMARC settings enabled' do + pp = %( + class { 'sympa': + dkim_feature => true, + dmarc_protection => true, + dkim_private_key => '-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvcUm36bRVm3hcXoSQr70l6+gTyqGOpCKVJE8xlJoApr85uZP +9tNveGmnnQUoRzMKYZo0Tl26YweY376lPgZ7AQRXDMqyGPMzeKOEIsOF4vVCElva +Lt7hSRYBAoGAVYvoY0gvOQKFNJBHMSEKiC+jt/+1ZNWvHg8Y/XepsIJVf4bBpN18 +d9c1L/EPHOm6fmY3PwioRU9V6gnr0zUrtdlvHbWE/2iCRez+QFIf+sCLpXE3K7Xe +20xz5Rs87WC4/QLhQHtP5qTe+reOu8GzUglHo14TMH5KbjmClX0r9sQ= +-----END RSA PRIVATE KEY-----', + } + ) + + it 'applies without error' do + apply_manifest(pp, catch_failures: true) + end + it 'applies idempotently' do + apply_manifest(pp, catch_changes: true) + end + + srv = [ + 'sympa.service', + 'sympa-archive.service', + 'sympa-bounce.service', + 'sympa-outgoing.service', + 'sympa-task.service', + 'wwsympa.socket', + 'wwsympa.service', + ] + + srv.each do |s| + describe service(s.to_s) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + end + + describe file('/home/sympa/etc/dkim/listes.example.org/lists-sympa.key') do + it { is_expected.to be_file } + it { is_expected.to be_owned_by 'sympa' } + it { is_expected.to be_grouped_into 'sympa' } + it { is_expected.to be_mode 600 } + it { is_expected.to contain('BEGIN RSA PRIVATE KEY') } + end + end end diff --git a/spec/classes/sympa_spec.rb b/spec/classes/sympa_spec.rb index af93be34f0c988eabfdbdace163d30b772435883..3986fe63d39b1a7b1d4f2647a7f1b52c3910b433 100644 --- a/spec/classes/sympa_spec.rb +++ b/spec/classes/sympa_spec.rb @@ -89,6 +89,16 @@ describe 'sympa' do .with_content(%r{personnel}) end end + + context 'with dkim_feature enabled and missing private key' do + let(:params) do + { + dkim_feature: true, + } + end + + it { is_expected.to compile.and_raise_error(%r{With dkim_feature true, dkim_private_key is mandatory.}) } + end end end end diff --git a/templates/dkim_priv.key.epp b/templates/dkim_priv.key.epp new file mode 100644 index 0000000000000000000000000000000000000000..9be03282672f897304185e658fa9381fce7e5332 --- /dev/null +++ b/templates/dkim_priv.key.epp @@ -0,0 +1 @@ +<%= $sympa::dkim_private_key %> diff --git a/templates/sympa.conf.epp b/templates/sympa.conf.epp index e11f7fa6f9c993804a5dc1fecb2add65054de023..3c1dc54af620a402633659a2f15707881fe357b7 100644 --- a/templates/sympa.conf.epp +++ b/templates/sympa.conf.epp @@ -32,7 +32,6 @@ db_passwd <%= $sympa::db_password %> # domain setting (recommended), you should define them in robot.conf by # each domain. -#wwsympa_url https://<%= $sympa::listdomain %> wwsympa_url https://<%= $sympa::listdomain %>/sympa ######################################################################## @@ -42,3 +41,19 @@ wwsympa_url https://<%= $sympa::listdomain %>/sympa # domain. # For more details see https://www.sympa.community/manual/customize.html ######################################################################## + +<% if $sympa::dkim_feature { -%> +dkim_feature on +dkim_parameters.private_key_path <%= $sympa::prefix_path %>/<%= $sympa::sysconf_dir %>/dkim/<%= $sympa::listdomain %>/<%= $sympa::dkim_selector %>.key +dkim_parameters.selector <%= $sympa::dkim_selector %> +dkim_signature_apply_on <%= $sympa::dkim_signature_apply_on %> +<% } else { -%> +dkim_feature off +<% } -%> + +<% if $sympa::dmarc_protection { -%> +dmarc_protection.mode <%= $sympa::dmarc_protection_mode %> +dmarc_protection.phrase <%= $sympa::dmarc_protection_phrase %> +<% } else { -%> +dmarc_protection.mode none +<% } -%>