From 007a9bd025ea441a45b0c8e891738c6f627a339a Mon Sep 17 00:00:00 2001 From: Fabien COMBERNOUS Date: Sat, 2 May 2020 11:32:08 +0200 Subject: add install_method parameter --- README.md | 11 +++++++++++ REFERENCE.md | 26 ++++++++++++++++++++++++- manifests/config.pp | 10 ++++++++++ manifests/init.pp | 8 +++++++- manifests/install.pp | 36 ++++++++++++++++++++++++++++++++-- manifests/service.pp | 2 +- metadata.json | 8 ++++++++ spec/acceptance/ferm_spec.rb | 44 +++++++++++++++++++++++++++++++++++++----- templates/dropin_ferm.conf.epp | 6 ++++++ 9 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 templates/dropin_ferm.conf.epp diff --git a/README.md b/README.md index 01217bd..64a9f84 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,17 @@ This will install the package, but nothing more. It won't explicitly enable it or write any rules. Be careful here: The default Debian package enabled autostart for the service and only allows incoming SSH/IPSec connections. +It is also possible to install ferm from sources: +```puppet +class {'ferm': + install_method = 'vcsrepo', +} +``` + +When `install_method` is `vcsrepo`, the `git` binary is required, this module should handle Git installation. + +When `install_method` is `vcsrepo` with `vcstag` >= `v2.5` ferm call "legacy" xtables tools because nft based tools are incompatible. + You can easily define rules in Puppet (they don't need to be exported resources): ```puppet diff --git a/REFERENCE.md b/REFERENCE.md index 5c85d38..eef0dc5 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -220,11 +220,35 @@ Default value: ['ip','ip6'] Data type: `Hash[String[1],Array[String[1]]]` -Hash with table:chains[] to use ferm @preserve for +Hash with table:chains[] to use ferm @preserve for (since ferm v2.4) Example: {'nat' => ['PREROUTING', 'POSTROUTING']} Default value: {} +##### `install_method` + +Data type: `Enum['package','vcsrepo']` + +method used to install ferm + +Default value: 'package' + +##### `vcsrepo` + +Data type: `Stdlib::HTTPSUrl` + +git repository where ferm sources are hosted + +Default value: 'https://github.com/MaxKellermann/ferm.git' + +##### `vcstag` + +Data type: `String[1]` + +git tag used when install_method is vcsrepo + +Default value: 'v2.5.1' + ## Defined types ### ferm::chain diff --git a/manifests/config.pp b/manifests/config.pp index 5876bd7..8ed0f57 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -10,6 +10,16 @@ class ferm::config { $_ip = join($ferm::ip_versions, ' ') + if $facts['systemd'] { #fact provided by systemd module + if $ferm::install_method == 'vcsrepo' and $ferm::manage_service { + systemd::dropin_file { 'ferm.conf': + unit => 'ferm.service', + content => epp("${module_name}/dropin_ferm.conf.epp"), + before => Service['ferm'], + } + } + } + # copy static files to ferm # on a long term point of view, we want to package this file{$ferm::configdirectory: diff --git a/manifests/init.pp b/manifests/init.pp index b1d051e..251effe 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -45,8 +45,11 @@ # @param output_log_dropped_packets Enable/Disable logging in the OUTPUT chain of packets to the kernel log, if no explicit chain matched # @param input_log_dropped_packets Enable/Disable logging in the INPUT chain of packets to the kernel log, if no explicit chain matched # @param ip_versions Set list of versions of ip we want ot use. -# @param preserve_chains_in_tables Hash with table:chains[] to use ferm @preserve for +# @param preserve_chains_in_tables Hash with table:chains[] to use ferm @preserve for (since ferm v2.4) # Example: {'nat' => ['PREROUTING', 'POSTROUTING']} +# @param install_method method used to install ferm +# @param vcsrepo git repository where ferm sources are hosted +# @param vcstag git tag used when install_method is vcsrepo class ferm ( Stdlib::Absolutepath $configfile, Stdlib::Absolutepath $configdirectory, @@ -67,6 +70,9 @@ class ferm ( Hash $chains = {}, Array[Enum['ip','ip6']] $ip_versions = ['ip','ip6'], Hash[String[1],Array[String[1]]] $preserve_chains_in_tables = {}, + Enum['package','vcsrepo'] $install_method = 'package', + Stdlib::HTTPSUrl $vcsrepo = 'https://github.com/MaxKellermann/ferm.git', + String[1] $vcstag = 'v2.5.1', ) { contain ferm::install contain ferm::config diff --git a/manifests/install.pp b/manifests/install.pp index 4337a99..5755ead 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -8,8 +8,40 @@ class ferm::install { # this is a private class assert_private("You're not supposed to do that!") - package{'ferm': - ensure => 'latest', + case $ferm::install_method { + 'package': { + package{'ferm': + ensure => 'latest', + } + } + 'vcsrepo': { + $_source_path = '/opt/ferm' + ensure_packages (['git', 'iptables', 'perl', 'make'], { ensure => present }) + + package{'ferm': + ensure => absent, + } + -> vcsrepo { $_source_path : + ensure => present, + provider => git, + source => $ferm::vcsrepo, + revision => $ferm::vcstag, + } + -> exec { 'make install': + cwd => $_source_path, + path => '/usr/sbin:/usr/bin:/sbin:/bin', + creates => '/usr/sbin/ferm', + } + -> file { '/etc/ferm': + ensure => directory, + owner => 0, + group => 0, + mode => '0700', + } + } + default: { + fail("unexpected install_method ${ferm::install_method}") + } } if $ferm::manage_initfile { diff --git a/manifests/service.pp b/manifests/service.pp index e9eb369..9fb1737 100644 --- a/manifests/service.pp +++ b/manifests/service.pp @@ -15,7 +15,7 @@ class ferm::service { } # on Ubuntu, we can't start the service, unless we set ENABLED=true in /etc/default/ferm... - if ($facts['os']['name'] in ['Ubuntu', 'Debian']) { + if ($facts['os']['name'] in ['Ubuntu', 'Debian']) and ($ferm::install_method == 'package') { file_line{'enable_ferm': path => '/etc/default/ferm', line => 'ENABLED="yes"', diff --git a/metadata.json b/metadata.json index ee832e8..08032e3 100644 --- a/metadata.json +++ b/metadata.json @@ -15,6 +15,14 @@ { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.25.0 < 7.0.0" + }, + { + "name": "puppetlabs/vcsrepo", + "version_requirement": ">= 3.0.0 < 4.0.0" + }, + { + "name": "camptocamp-systemd", + "version_requirement": ">= 2.9.0 < 3.0.0" } ], "operatingsystem_support": [ diff --git a/spec/acceptance/ferm_spec.rb b/spec/acceptance/ferm_spec.rb index 8c5c454..f8f0ef4 100644 --- a/spec/acceptance/ferm_spec.rb +++ b/spec/acceptance/ferm_spec.rb @@ -30,6 +30,15 @@ iptables_output = case sut_os iptables_output_custom = ['-A FORWARD -s 10.8.0.0/24 -p udp -m comment --comment "OpenVPN - FORWORD all udp traffic from network 10.8.0.0/24 to subchain OPENVPN_FORWORD_RULES" -j OPENVPN_FORWORD_RULES', '-A OPENVPN_FORWORD_RULES -s 10.8.0.0/24 -i tun0 -o enp4s0 -p udp -m conntrack --ctstate NEW -j ACCEPT'] +# When `install_method` is `vcsrepo` with `vcstag` >= `v2.5` ferm call "legacy" +# xtables tools because nft based tools are incompatible. +iptables_save_cmd = case sut_os + when 'Debian-10' + 'iptables-legacy-save' + else + 'iptables-save' + end + basic_manifest = %( class { 'ferm': manage_service => true, @@ -47,12 +56,36 @@ basic_manifest = %( }, }, ip_versions => ['ip'], #only ipv4 available with CI - } ) describe 'ferm' do - context 'with basics settings' do - pp = basic_manifest + context 'with basics settings and vcsrepo install_method' do + pp = [basic_manifest, "install_method => 'vcsrepo',}"].join("\n") + + it 'works with no error' do + apply_manifest(pp, catch_failures: true) + end + it 'works idempotently' do + apply_manifest(pp, catch_changes: true) + end + + describe package('ferm') do + it { is_expected.not_to be_installed } + end + + describe service('ferm') do + it { is_expected.to be_running } + end + + describe command("#{iptables_save_cmd} -t filter") do + its(:stdout) { is_expected.to match %r{.*filter.*:INPUT DROP.*:FORWARD DROP.*:OUTPUT ACCEPT.*}m } + its(:stdout) { is_expected.not_to match %r{state INVALID -j DROP} } + its(:stdout) { is_expected.to match %r{allow_acceptance_tests.*-j ACCEPT}m } + end + end + + context 'with basics settings and default install_method' do + pp = [basic_manifest, '}'].join("\n") it 'works with no error' do apply_manifest(pp, catch_failures: true) @@ -105,7 +138,7 @@ describe 'ferm' do require => Ferm::Chain['check-http'], } ) - pp = [basic_manifest, advanced_manifest].join("\n") + pp = [basic_manifest, '}', advanced_manifest].join("\n") it 'works with no error' do apply_manifest(pp, catch_failures: true) @@ -193,7 +226,8 @@ describe 'ferm' do proto => 'udp', } ) - pp = [basic_manifest, advanced_manifest].join("\n") + + pp = [basic_manifest, '}', advanced_manifest].join("\n") it 'works with no error' do apply_manifest(pp, catch_failures: true) diff --git a/templates/dropin_ferm.conf.epp b/templates/dropin_ferm.conf.epp new file mode 100644 index 0000000..d5ed63b --- /dev/null +++ b/templates/dropin_ferm.conf.epp @@ -0,0 +1,6 @@ +# THIS SNIPPET IS MANAGED BY PUPPET +[Service] +ExecStart= +ExecStart=/usr/sbin/ferm <%= $ferm::configfile %> +ExecStop= +ExecStop=/usr/sbin/ferm -F <%= $ferm::configfile %> -- cgit v1.2.3