Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / spec / classes / nftables_spec.rb @ 4c3d5d6b

Historique | Voir | Annoter | Télécharger (9,73 ko)

1
# frozen_string_literal: true
2

    
3
require 'spec_helper'
4

    
5
describe 'nftables' do
6
  let(:pre_condition) { 'Exec{path => "/bin"}' }
7

    
8
  on_supported_os.each do |os, os_facts|
9
    context "on #{os}" do
10
      let(:facts) { os_facts }
11

    
12
      nft_path = case os_facts[:os]['family']
13
                 when 'Archlinux'
14
                   '/usr/bin/nft'
15
                 else
16
                   '/usr/sbin/nft'
17
                 end
18
      nft_config = case os_facts[:os]['family']
19
                   when 'RedHat'
20
                     '/etc/sysconfig/nftables.conf'
21
                   else
22
                     '/etc/nftables.conf'
23
                   end
24

    
25
      nft_mode = case os_facts[:os]['family']
26
                 when 'RedHat'
27
                   '0600'
28
                 else
29
                   '0640'
30
                 end
31

    
32
      it { is_expected.to compile.with_all_deps }
33

    
34
      it { is_expected.to contain_package('nftables') }
35

    
36
      it {
37
        is_expected.to contain_file('/etc/nftables').with(
38
          ensure: 'directory',
39
          owner: 'root',
40
          group: 'root',
41
          mode: nft_mode
42
        )
43
      }
44

    
45
      it {
46
        expect(subject).to contain_file('/etc/nftables/puppet.nft').with(
47
          ensure: 'file',
48
          owner: 'root',
49
          group: 'root',
50
          mode: nft_mode,
51
          content: %r{flush ruleset}
52
        )
53
      }
54

    
55
      it {
56
        expect(subject).to contain_file('/etc/nftables/puppet.nft').with(
57
          content: %r{^include "file-\*\.nft"$}
58
        )
59
      }
60

    
61
      it {
62
        expect(subject).to contain_file('/etc/nftables/puppet').with(
63
          ensure: 'directory',
64
          owner: 'root',
65
          group: 'root',
66
          mode: nft_mode,
67
          purge: true,
68
          force: true,
69
          recurse: true
70
        )
71
      }
72

    
73
      it {
74
        expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').with(
75
          ensure: 'file',
76
          owner: 'root',
77
          group: 'root',
78
          mode: nft_mode,
79
          content: %r{flush ruleset}
80
        )
81
      }
82

    
83
      it {
84
        expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').with(
85
          content: %r{^include "file-\*\.nft"$}
86
        )
87
      }
88

    
89
      it {
90
        expect(subject).to contain_file('/etc/nftables/puppet-preflight').with(
91
          ensure: 'directory',
92
          owner: 'root',
93
          group: 'root',
94
          mode: nft_mode,
95
          purge: true,
96
          force: true,
97
          recurse: true
98
        )
99
      }
100

    
101
      it {
102
        expect(subject).to contain_exec('nft validate').with(
103
          refreshonly: true,
104
          command: %r{^#{nft_path} -I /etc/nftables/puppet-preflight -c -f /etc/nftables/puppet-preflight.nft.*}
105
        )
106
      }
107

    
108
      it {
109
        expect(subject).to contain_service('nftables').with(
110
          ensure: 'running',
111
          enable: true,
112
          hasrestart: true,
113
          restart: %r{PATH=/usr/bin:/bin systemctl reload nft.*}
114
        )
115
      }
116

    
117
      it {
118
        expect(subject).to contain_systemd__dropin_file('puppet_nft.conf').with(
119
          content: %r{^ExecReload=#{nft_path} -I /etc/nftables/puppet -f #{nft_config}$}
120
        )
121
      }
122

    
123
      case os_facts[:os]['family']
124
      when 'Archlinux'
125

    
126
        it {
127
          expect(subject).to contain_service('firewalld').with(
128
            ensure: 'stopped',
129
            enable: false
130
          )
131
        }
132
      when 'Debian'
133
        it {
134
          is_expected.to contain_service('firewalld').with(
135
            ensure: 'stopped',
136
            enable: false
137
          )
138
        }
139
      else
140
        it {
141
          expect(subject).to contain_service('firewalld').with(
142
            ensure: 'stopped',
143
            enable: 'mask'
144
          )
145
        }
146
      end
147

    
148
      it { is_expected.to contain_class('nftables::inet_filter') }
149
      it { is_expected.to contain_class('nftables::ip_nat') }
150
      it { is_expected.to contain_class('nftables::rules::out::http') }
151
      it { is_expected.to contain_class('nftables::rules::out::https') }
152
      it { is_expected.to contain_class('nftables::rules::out::dns') }
153
      it { is_expected.to contain_class('nftables::rules::out::chrony') }
154
      it { is_expected.not_to contain_class('nftables::rules::out::all') }
155
      it { is_expected.not_to contain_nftables__rule('default_out-all') }
156

    
157
      context 'with out_all set true' do
158
        let(:params) do
159
          {
160
            out_all: true,
161
          }
162
        end
163

    
164
        it { is_expected.to contain_class('nftables::rules::out::all') }
165
        it { is_expected.not_to contain_class('nftables::rules::out::http') }
166
        it { is_expected.not_to contain_class('nftables::rules::out::https') }
167
        it { is_expected.not_to contain_class('nftables::rules::out::dns') }
168
        it { is_expected.not_to contain_class('nftables::rules::out::chrony') }
169
        it { is_expected.to contain_nftables__rule('default_out-all').with_content('accept') }
170
        it { is_expected.to contain_nftables__rule('default_out-all').with_order('90') }
171
      end
172

    
173
      context 'with custom rules' do
174
        let(:params) do
175
          {
176
            rules: {
177
              'INPUT-web_accept' => {
178
                order: '50',
179
                content: 'iifname eth0 tcp dport { 80, 443 } accept',
180
              },
181
            },
182
          }
183
        end
184

    
185
        it {
186
          expect(subject).to contain_concat__fragment('nftables-inet-filter-chain-INPUT-rule-web_accept').with(
187
            target: 'nftables-inet-filter-chain-INPUT',
188
            content: %r{^  iifname eth0 tcp dport \{ 80, 443 \} accept$},
189
            order: '50-nftables-inet-filter-chain-INPUT-rule-web_accept-b'
190
          )
191
        }
192
      end
193

    
194
      context 'with custom sets' do
195
        let(:params) do
196
          {
197
            sets: {
198
              'testset1' => {
199
                type: 'ipv4_addr',
200
                gc_interval: 2,
201
              },
202
              'testset2' => {
203
                type: 'ipv6_addr',
204
                elements: ['2a02:62:c601::dead:beef'],
205
              },
206
            },
207
          }
208
        end
209

    
210
        it {
211
          expect(subject).to contain_nftables__set('testset1').with(
212
            type: 'ipv4_addr',
213
            gc_interval: 2,
214
            table: 'inet-filter'
215
          )
216
        }
217

    
218
        it {
219
          expect(subject).to contain_nftables__set('testset2').with(
220
            type: 'ipv6_addr',
221
            elements: ['2a02:62:c601::dead:beef'],
222
            table: 'inet-filter'
223
          )
224
        }
225
      end
226

    
227
      context 'without masking firewalld' do
228
        let(:params) do
229
          {
230
            'firewalld_enable' => false,
231
          }
232
        end
233

    
234
        it {
235
          expect(subject).to contain_service('firewalld').with(
236
            ensure: 'stopped',
237
            enable: false
238
          )
239
        }
240
      end
241

    
242
      context 'with no default filtering rules' do
243
        let(:params) do
244
          {
245
            'inet_filter' => false,
246
          }
247
        end
248

    
249
        it { is_expected.to contain_class('nftables::ip_nat') }
250
        it { is_expected.not_to contain_class('nftables::inet_filter') }
251
      end
252

    
253
      context 'with no default tables, chains or rules' do
254
        let(:params) do
255
          {
256
            'inet_filter' => false,
257
            'nat' => false,
258
          }
259
        end
260

    
261
        it { is_expected.not_to contain_class('nftables::ip_nat') }
262
        it { is_expected.not_to contain_class('nftables::inet_filter') }
263
        it { is_expected.to have_nftables__config_resource_count(0) }
264
        it { is_expected.to have_nftables__chain_resource_count(0) }
265
        it { is_expected.to have_nftables__rule_resource_count(0) }
266
        it { is_expected.to have_nftables__set_resource_count(0) }
267
      end
268

    
269
      %w[ip ip6 inet arp bridge netdev].each do |family|
270
        context "with noflush_tables parameter set to valid family #{family}" do
271
          let(:params) do
272
            {
273
              noflush_tables: ["#{family}-f2b-table"],
274
            }
275
          end
276

    
277
          context 'with no nftables fact' do
278
            it { is_expected.to contain_file('/etc/nftables/puppet-preflight.nft').with_content(%r{^flush ruleset$}) }
279
          end
280

    
281
          context 'with nftables fact matching' do
282
            let(:facts) do
283
              super().merge(nftables: { tables: %W[#{family}-abc #{family}-f2b-table] })
284
            end
285

    
286
            it {
287
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
288
                with_content(%r{^table #{family} abc \{\}$})
289
            }
290

    
291
            it {
292
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
293
                with_content(%r{^flush table #{family} abc$})
294
            }
295
          end
296

    
297
          context 'with nftables fact not matching' do
298
            let(:facts) do
299
              super().merge(nftables: { tables: %W[#{family}-abc #{family}-ijk] })
300
            end
301

    
302
            it {
303
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
304
                with_content(%r{^table #{family} abc \{\}$})
305
            }
306

    
307
            it {
308
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
309
                with_content(%r{^flush table #{family} abc$})
310
            }
311

    
312
            it {
313
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
314
                with_content(%r{^table #{family} ijk \{\}$})
315
            }
316

    
317
            it {
318
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
319
                with_content(%r{^flush table #{family} ijk$})
320
            }
321
          end
322
        end
323
      end
324

    
325
      %w[it ip7 inter arpa brid netdevs].each do |family|
326
        context "with noflush_tables parameter set to invalid family #{family}" do
327
          let(:params) do
328
            {
329
              noflush_tables: ["#{family}-f2b-table"],
330
            }
331
          end
332

    
333
          it { is_expected.not_to compile }
334
        end
335
      end
336
    end
337
  end
338
end