Projet

Général

Profil

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

root / spec / classes / nftables_spec.rb @ 331b8d85

Historique | Voir | Annoter | Télécharger (9,55 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
      it { is_expected.to compile.with_all_deps }
26

    
27
      it { is_expected.to contain_package('nftables') }
28

    
29
      it {
30
        is_expected.to contain_file('/etc/nftables').with(
31
          ensure: 'directory',
32
          owner: 'root',
33
          group: 'root',
34
          mode: '0750'
35
        )
36
      }
37

    
38
      it {
39
        expect(subject).to contain_file('/etc/nftables/puppet.nft').with(
40
          ensure: 'file',
41
          owner: 'root',
42
          group: 'root',
43
          mode: '0640',
44
          content: %r{flush ruleset}
45
        )
46
      }
47

    
48
      it {
49
        expect(subject).to contain_file('/etc/nftables/puppet.nft').with(
50
          content: %r{^include "file-\*\.nft"$}
51
        )
52
      }
53

    
54
      it {
55
        expect(subject).to contain_file('/etc/nftables/puppet').with(
56
          ensure: 'directory',
57
          owner: 'root',
58
          group: 'root',
59
          mode: '0750',
60
          purge: true,
61
          force: true,
62
          recurse: true
63
        )
64
      }
65

    
66
      it {
67
        expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').with(
68
          ensure: 'file',
69
          owner: 'root',
70
          group: 'root',
71
          mode: '0640',
72
          content: %r{flush ruleset}
73
        )
74
      }
75

    
76
      it {
77
        expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').with(
78
          content: %r{^include "file-\*\.nft"$}
79
        )
80
      }
81

    
82
      it {
83
        expect(subject).to contain_file('/etc/nftables/puppet-preflight').with(
84
          ensure: 'directory',
85
          owner: 'root',
86
          group: 'root',
87
          mode: '0750',
88
          purge: true,
89
          force: true,
90
          recurse: true
91
        )
92
      }
93

    
94
      it {
95
        expect(subject).to contain_exec('nft validate').with(
96
          refreshonly: true,
97
          command: %r{^#{nft_path} -I /etc/nftables/puppet-preflight -c -f /etc/nftables/puppet-preflight.nft.*}
98
        )
99
      }
100

    
101
      it {
102
        expect(subject).to contain_service('nftables').with(
103
          ensure: 'running',
104
          enable: true,
105
          hasrestart: true,
106
          restart: %r{PATH=/usr/bin:/bin systemctl reload nft.*}
107
        )
108
      }
109

    
110
      it {
111
        expect(subject).to contain_systemd__dropin_file('puppet_nft.conf').with(
112
          content: %r{^ExecReload=#{nft_path} -I /etc/nftables/puppet -f #{nft_config}$}
113
        )
114
      }
115

    
116
      case os_facts[:os]['family']
117
      when 'Archlinux'
118

    
119
        it {
120
          expect(subject).to contain_service('firewalld').with(
121
            ensure: 'stopped',
122
            enable: false
123
          )
124
        }
125
      when 'Debian'
126
        it {
127
          is_expected.to contain_service('firewalld').with(
128
            ensure: 'stopped',
129
            enable: false
130
          )
131
        }
132
      else
133
        it {
134
          expect(subject).to contain_service('firewalld').with(
135
            ensure: 'stopped',
136
            enable: 'mask'
137
          )
138
        }
139
      end
140

    
141
      it { is_expected.to contain_class('nftables::inet_filter') }
142
      it { is_expected.to contain_class('nftables::ip_nat') }
143
      it { is_expected.to contain_class('nftables::rules::out::http') }
144
      it { is_expected.to contain_class('nftables::rules::out::https') }
145
      it { is_expected.to contain_class('nftables::rules::out::dns') }
146
      it { is_expected.to contain_class('nftables::rules::out::chrony') }
147
      it { is_expected.not_to contain_class('nftables::rules::out::all') }
148
      it { is_expected.not_to contain_nftables__rule('default_out-all') }
149

    
150
      context 'with out_all set true' do
151
        let(:params) do
152
          {
153
            out_all: true,
154
          }
155
        end
156

    
157
        it { is_expected.to contain_class('nftables::rules::out::all') }
158
        it { is_expected.not_to contain_class('nftables::rules::out::http') }
159
        it { is_expected.not_to contain_class('nftables::rules::out::https') }
160
        it { is_expected.not_to contain_class('nftables::rules::out::dns') }
161
        it { is_expected.not_to contain_class('nftables::rules::out::chrony') }
162
        it { is_expected.to contain_nftables__rule('default_out-all').with_content('accept') }
163
        it { is_expected.to contain_nftables__rule('default_out-all').with_order('90') }
164
      end
165

    
166
      context 'with custom rules' do
167
        let(:params) do
168
          {
169
            rules: {
170
              'INPUT-web_accept' => {
171
                order: '50',
172
                content: 'iifname eth0 tcp dport { 80, 443 } accept',
173
              },
174
            },
175
          }
176
        end
177

    
178
        it {
179
          expect(subject).to contain_concat__fragment('nftables-inet-filter-chain-INPUT-rule-web_accept').with(
180
            target: 'nftables-inet-filter-chain-INPUT',
181
            content: %r{^  iifname eth0 tcp dport \{ 80, 443 \} accept$},
182
            order: '50-nftables-inet-filter-chain-INPUT-rule-web_accept-b'
183
          )
184
        }
185
      end
186

    
187
      context 'with custom sets' do
188
        let(:params) do
189
          {
190
            sets: {
191
              'testset1' => {
192
                type: 'ipv4_addr',
193
                gc_interval: 2,
194
              },
195
              'testset2' => {
196
                type: 'ipv6_addr',
197
                elements: ['2a02:62:c601::dead:beef'],
198
              },
199
            },
200
          }
201
        end
202

    
203
        it {
204
          expect(subject).to contain_nftables__set('testset1').with(
205
            type: 'ipv4_addr',
206
            gc_interval: 2,
207
            table: 'inet-filter'
208
          )
209
        }
210

    
211
        it {
212
          expect(subject).to contain_nftables__set('testset2').with(
213
            type: 'ipv6_addr',
214
            elements: ['2a02:62:c601::dead:beef'],
215
            table: 'inet-filter'
216
          )
217
        }
218
      end
219

    
220
      context 'without masking firewalld' do
221
        let(:params) do
222
          {
223
            'firewalld_enable' => false,
224
          }
225
        end
226

    
227
        it {
228
          expect(subject).to contain_service('firewalld').with(
229
            ensure: 'stopped',
230
            enable: false
231
          )
232
        }
233
      end
234

    
235
      context 'with no default filtering rules' do
236
        let(:params) do
237
          {
238
            'inet_filter' => false,
239
          }
240
        end
241

    
242
        it { is_expected.to contain_class('nftables::ip_nat') }
243
        it { is_expected.not_to contain_class('nftables::inet_filter') }
244
      end
245

    
246
      context 'with no default tables, chains or rules' do
247
        let(:params) do
248
          {
249
            'inet_filter' => false,
250
            'nat' => false,
251
          }
252
        end
253

    
254
        it { is_expected.not_to contain_class('nftables::ip_nat') }
255
        it { is_expected.not_to contain_class('nftables::inet_filter') }
256
        it { is_expected.to have_nftables__config_resource_count(0) }
257
        it { is_expected.to have_nftables__chain_resource_count(0) }
258
        it { is_expected.to have_nftables__rule_resource_count(0) }
259
        it { is_expected.to have_nftables__set_resource_count(0) }
260
      end
261

    
262
      %w[ip ip6 inet arp bridge netdev].each do |family|
263
        context "with noflush_tables parameter set to valid family #{family}" do
264
          let(:params) do
265
            {
266
              noflush_tables: ["#{family}-f2b-table"],
267
            }
268
          end
269

    
270
          context 'with no nftables fact' do
271
            it { is_expected.to contain_file('/etc/nftables/puppet-preflight.nft').with_content(%r{^flush ruleset$}) }
272
          end
273

    
274
          context 'with nftables fact matching' do
275
            let(:facts) do
276
              super().merge(nftables: { tables: %W[#{family}-abc #{family}-f2b-table] })
277
            end
278

    
279
            it {
280
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
281
                with_content(%r{^table #{family} abc \{\}$})
282
            }
283

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

    
290
          context 'with nftables fact not matching' do
291
            let(:facts) do
292
              super().merge(nftables: { tables: %W[#{family}-abc #{family}-ijk] })
293
            end
294

    
295
            it {
296
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
297
                with_content(%r{^table #{family} abc \{\}$})
298
            }
299

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

    
305
            it {
306
              expect(subject).to contain_file('/etc/nftables/puppet-preflight.nft').
307
                with_content(%r{^table #{family} ijk \{\}$})
308
            }
309

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

    
318
      %w[it ip7 inter arpa brid netdevs].each do |family|
319
        context "with noflush_tables parameter set to invalid family #{family}" do
320
          let(:params) do
321
            {
322
              noflush_tables: ["#{family}-f2b-table"],
323
            }
324
          end
325

    
326
          it { is_expected.not_to compile }
327
        end
328
      end
329
    end
330
  end
331
end