Puppet Class: ferm

Defined in:
modules/ferm/manifests/init.pp

Overview

ferm is a frontend for iptables wiki.debian.org/ferm

Parameters:

  • ensure (Wmflib::Ensure) (defaults to: 'present')

    ensure parameter

  • ferm_status_restart (Boolean) (defaults to: false)


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'modules/ferm/manifests/init.pp', line 4

class ferm (
    Wmflib::Ensure $ensure = 'present',
    Boolean $ferm_status_restart = false,
) {
    # @resolve requires libnet-dns-perl
    ensure_packages('libnet-dns-perl')
    package {'iptables':
        ensure => stdlib::ensure($ensure, package),
    }

    if $ensure == 'present' {
        ensure_packages('ferm')
    } elsif $ensure == 'absent' {
        ensure_packages(['ferm'], {'ensure' => 'purged'})
    }

    if !$facts['wmflib']['is_container'] {
        file { '/etc/modprobe.d/nf_conntrack.conf':
            ensure => stdlib::ensure($ensure, 'file'),
            owner  => 'root',
            group  => 'root',
            mode   => '0444',
            source => 'puppet:///modules/base/firewall/nf_conntrack.conf',
        }

        # The nf_conntrack kernel module is usually auto-loaded during ferm startup.
        # But some additional configuration options for timewait handling are configured
        #   via sysctl settings and if ferm autoloads the kernel module after
        #   systemd-sysctl.service has run, the sysctl settings are not applied.
        # Add the nf_conntrack module via /etc/modules-load.d/ which loads
        #   them before systemd-sysctl.service is executed.
        file { '/etc/modules-load.d/conntrack.conf':
            ensure  => stdlib::ensure($ensure, 'file'),
            owner   => 'root',
            group   => 'root',
            mode    => '0444',
            content => "nf_conntrack\n",
            require => File['/etc/modprobe.d/nf_conntrack.conf'],
            before  => Package['ferm', 'libnet-dns-perl', 'conntrack'],
        }
    }

    file { '/usr/local/sbin/ferm-status':
        ensure  => stdlib::ensure($ensure, 'file'),
        mode    => '0550',
        owner   => 'root',
        group   => 'root',
        content => file('ferm/ferm_status.py'),
    }

    file { '/etc/ferm' :
        ensure => stdlib::ensure($ensure, 'directory'),
        force  => true,
        mode   => '2751',
        group  => 'adm',
    }

    if $ensure == 'present' {
        if $ferm_status_restart {
            service { 'ferm':
                ensure  => running,
                # When restartcmd ('systemctl restart') is called it will call the ferm init script with stop and start sequentially.
                # This does flush all(!) rules before reapplying them, so we use reload-or-restart here as well to prevent this.
                # Note that start,reload,restart,force-reload are all handled by the same ferm init script (apart from different
                # log messages).
                restart => '/bin/systemctl reload-or-restart ferm',
            }
        } else {
            service { 'ferm':
                ensure  => running,
                # This is a bit of an abuse of the puppet DSL.
                # We use the status command to ensure that the rules on disk match the rules loaded in the
                # kernel (ferm-status returns 0); if not we want to reload the rule base (ferm-status returns 1).
                status  => '/usr/local/sbin/ferm-status',
                # When the service status command returns 1, puppet sets the service status to stopped:
                # https://github.com/puppetlabs/puppet/blob/main/lib/puppet/provider/service/base.rb#L77
                # which means that it calls the startcmd (instead of restartcmd).
                # As such we need to update the start command so that it calls systemd reload instead of systemd restart.
                # However we also need to account for when the service is actually stopped which is why we use reload-or-restart.
                start   => '/bin/systemctl reload-or-restart ferm',
                # When the service status command returns 0, puppet sets the service status to running, which means that
                # restartcmd ('systemctl restart') is called which will call the ferm init script with stop and start sequentially.
                # When restartcmd ('systemctl restart') is called it will call the ferm init script with stop and start sequentially.
                # This does flush all(!) rules before reapplying them, so we use reload-or-restart here as well to prevent this.
                # Note that start,reload,restart,force-reload are all handled by the same ferm init script (apart from different
                # log messages).
                restart => '/bin/systemctl reload-or-restart ferm',
            }
        }
        systemd::override { 'ferm-service-status-restart':
            ensure => stdlib::ensure($ferm_status_restart),
            unit   => 'ferm',
            source => 'puppet:///modules/ferm/ferm_systemd_override',
        }

        file { '/etc/ferm/ferm.conf':
            ensure  => stdlib::ensure($ensure, 'file'),
            owner   => 'root',
            group   => 'root',
            mode    => '0400',
            source  => 'puppet:///modules/ferm/ferm.conf',
            require => Package['ferm'],
            notify  => Service['ferm'],
        }

        file { '/etc/ferm/functions.conf' :
            ensure  => stdlib::ensure($ensure, 'file'),
            owner   => 'root',
            group   => 'root',
            mode    => '0400',
            source  => 'puppet:///modules/ferm/functions.conf',
            require => Package['ferm'],
            notify  => Service['ferm'],
        }

        file { '/etc/ferm/conf.d' :
            ensure  => stdlib::ensure($ensure, 'directory'),
            owner   => 'root',
            group   => 'adm',
            mode    => '0551',
            recurse => true,
            purge   => true,
            force   => true,
            require => Package['ferm'],
            notify  => Service['ferm'],
        }

        file { '/etc/default/ferm' :
            ensure  => stdlib::ensure($ensure, 'file'),
            owner   => 'root',
            group   => 'root',
            mode    => '0400',
            source  => 'puppet:///modules/ferm/ferm.default',
            require => Package['ferm'],
            notify  => Service['ferm'],
        }
    }

    # Starting with Bullseye iptables default to the nft backend, but for ferm
    # we need the legacy backend
    if debian::codename::ge('bullseye') and $ensure == 'present' {
        alternatives::select { 'iptables':
            path    => '/usr/sbin/iptables-legacy',
            require => Package['iptables'],
        }

        alternatives::select { 'ip6tables':
            path    => '/usr/sbin/ip6tables-legacy',
            require => Package['iptables'],
        }
    }

    # the rules are virtual resources for cases where they are defined in a
    # class but the host doesn't have the ferm class included
    File <| tag == 'ferm' |>
}