Révision 03d9e7da
New parameter noflush_tables to selectivly skip flush
Introduces a new structured fact nftables
```yaml
nftables:
tables:
- inet-filter
- ip-nat
- ip6-nat
- inet-f2b-table
```
By default the nft script will continue to contain `nft flush ruleset`
If noflush_tables is specified e.g.
```puppet
class{nftables:
noflush_tables => ['inet-f2b-table'],
}
```
the results script will explicity flush the other tables only.
i.e.
```
flush table inet filter
flush table ip nat
flush table ip6 nat
```
Motivation here is to allow a maintence of chain to managed by something else.
This example for fail2ban but could be docker, ...
files/systemd/puppet_nft.conf | ||
---|---|---|
1 |
# Specify directory to look for relative includes |
|
2 |
[Service] |
|
3 |
ExecStart= |
|
4 |
ExecStart=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf |
|
5 |
ExecReload= |
|
6 |
ExecReload=/sbin/nft -I /etc/nftables/puppet 'flush ruleset; include "/etc/sysconfig/nftables.conf";' |
|
7 |
|
lib/facter/nftables.rb | ||
---|---|---|
1 |
# |
|
2 |
# Produce an array of nftables. |
|
3 |
# nft list tables |
|
4 |
# table inet filter |
|
5 |
# table ip nat |
|
6 |
# table ip6 nat |
|
7 |
# table inet f2b-table |
|
8 |
# |
|
9 |
Facter.add(:nftables) do |
|
10 |
@nft_cmd = Facter::Util::Resolution.which('nft') |
|
11 |
confine { @nft_cmd } |
|
12 |
|
|
13 |
setcode do |
|
14 |
tables = [] |
|
15 |
table_result = Facter::Core::Execution.execute(%(#{@nft_cmd} list tables)) |
|
16 |
table_result.each_line do |line| |
|
17 |
tables.push(line.split(' ')[1, 2].join('-')) |
|
18 |
end |
|
19 |
{ 'tables' => tables } |
|
20 |
end |
|
21 |
end |
manifests/init.pp | ||
---|---|---|
1 | 1 |
# @summary Configure nftables |
2 | 2 |
# |
3 |
# @example |
|
3 |
# @example allow dns out and do not allow ntp out
|
|
4 | 4 |
# class{'nftables: |
5 | 5 |
# out_ntp = false, |
6 | 6 |
# out_dns = true, |
7 | 7 |
# } |
8 | 8 |
# |
9 |
# @example do not flush particular tables |
|
10 |
# In this case ignoring the fail2ban maintained |
|
11 |
# table |
|
12 |
# class{'nftables': |
|
13 |
# noflush_tables = ['inet-f2b-table'], |
|
14 |
# } |
|
15 |
# |
|
9 | 16 |
# @param out_all |
10 | 17 |
# Allow all outbound connections. If `true` then all other |
11 | 18 |
# out parameters `out_ntp`, `out_dns`, ... will be assuemed |
... | ... | |
64 | 71 |
# useful to set this to false if you're externaly removing firewalld from |
65 | 72 |
# the system completely. |
66 | 73 |
# |
74 |
# @param noflush_tables |
|
75 |
# If specified only other existings tables will be flushed. |
|
76 |
# If left unset all tables will be flushed via a `flush ruleset` |
|
77 |
# |
|
67 | 78 |
class nftables ( |
68 | 79 |
Boolean $in_ssh = true, |
69 | 80 |
Boolean $in_icmp = true, |
... | ... | |
85 | 96 |
$reject_with = 'icmpx type port-unreachable', |
86 | 97 |
Variant[Boolean[false], Enum['mask']] |
87 | 98 |
$firewalld_enable = 'mask', |
99 |
Optional[Array[Pattern[/^(ip|ip6|inet)-[-a-zA-Z0-9_]+$/],1]] |
|
100 |
$noflush_tables = undef, |
|
88 | 101 |
) { |
89 | 102 |
|
90 | 103 |
package{'nftables': |
... | ... | |
107 | 120 |
recurse => true; |
108 | 121 |
'/etc/nftables/puppet-preflight.nft': |
109 | 122 |
ensure => file, |
110 |
content => epp('nftables/config/puppet.nft.epp', { 'nat' => $nat }); |
|
123 |
content => epp('nftables/config/puppet.nft.epp', { 'nat' => $nat, 'noflush' => $noflush_tables });
|
|
111 | 124 |
} ~> exec{ |
112 | 125 |
'nft validate': |
113 | 126 |
refreshonly => true, |
... | ... | |
119 | 132 |
mode => '0640'; |
120 | 133 |
'/etc/nftables/puppet.nft': |
121 | 134 |
ensure => file, |
122 |
content => epp('nftables/config/puppet.nft.epp', { 'nat' => $nat }); |
|
135 |
content => epp('nftables/config/puppet.nft.epp', { 'nat' => $nat, 'noflush' => $noflush_tables });
|
|
123 | 136 |
'/etc/nftables/puppet': |
124 | 137 |
ensure => directory, |
125 | 138 |
mode => '0750', |
... | ... | |
134 | 147 |
} |
135 | 148 |
|
136 | 149 |
systemd::dropin_file{'puppet_nft.conf': |
137 |
ensure => present, |
|
138 |
unit => 'nftables.service', |
|
139 |
source => 'puppet:///modules/nftables/systemd/puppet_nft.conf',
|
|
140 |
notify => Service['nftables'], |
|
150 |
ensure => present,
|
|
151 |
unit => 'nftables.service',
|
|
152 |
content => epp('nftables/systemd/puppet_nft.conf.epp', { 'noflush' => $noflush_tables }),
|
|
153 |
notify => Service['nftables'],
|
|
141 | 154 |
} |
142 | 155 |
|
143 | 156 |
service{'firewalld': |
spec/classes/nftables_spec.rb | ||
---|---|---|
167 | 167 |
) |
168 | 168 |
} |
169 | 169 |
end |
170 |
|
|
171 |
context 'with with noflush_tables parameter' do |
|
172 |
let(:params) do |
|
173 |
{ |
|
174 |
noflush_tables: ['inet-f2b-table'], |
|
175 |
} |
|
176 |
end |
|
177 |
|
|
178 |
context 'with no nftables fact' do |
|
179 |
it { |
|
180 |
is_expected.to contain_systemd__dropin_file('puppet_nft.conf') |
|
181 |
.with_content(%r{^ExecReload.*flush ruleset; include.*$}) |
|
182 |
} |
|
183 |
it { is_expected.to contain_file('/etc/nftables/puppet-preflight.nft').with_content(%r{^flush ruleset$}) } |
|
184 |
end |
|
185 |
|
|
186 |
context 'with nftables fact matching' do |
|
187 |
let(:facts) do |
|
188 |
super().merge(nftables: { tables: ['inet-abc', 'inet-f2b-table'] }) |
|
189 |
end |
|
190 |
|
|
191 |
it { |
|
192 |
is_expected.to contain_systemd__dropin_file('puppet_nft.conf') |
|
193 |
.with_content(%r{^ExecReload.*flush table inet abc; include.*$}) |
|
194 |
} |
|
195 |
it { |
|
196 |
is_expected.to contain_file('/etc/nftables/puppet-preflight.nft') |
|
197 |
.with_content(%r{^flush table inet abc$}) |
|
198 |
} |
|
199 |
end |
|
200 |
context 'with nftables fact not matching' do |
|
201 |
let(:facts) do |
|
202 |
super().merge(nftables: { tables: ['inet-abc', 'inet-ijk'] }) |
|
203 |
end |
|
204 |
|
|
205 |
it { |
|
206 |
is_expected.to contain_systemd__dropin_file('puppet_nft.conf') |
|
207 |
.with_content(%r{^ExecReload.*flush table inet abc; flush table inet ijk; include.*$}) |
|
208 |
} |
|
209 |
it { |
|
210 |
is_expected.to contain_file('/etc/nftables/puppet-preflight.nft') |
|
211 |
.with_content(%r{^flush table inet abc; flush table inet ijk$}) |
|
212 |
} |
|
213 |
end |
|
214 |
end |
|
170 | 215 |
end |
171 | 216 |
end |
172 | 217 |
end |
spec/unit/facter/nftables_spec.rb | ||
---|---|---|
1 |
require 'spec_helper' |
|
2 |
|
|
3 |
describe 'nftables' do |
|
4 |
before(:each) do |
|
5 |
Facter.clear |
|
6 |
Process.stubs(:uid).returns(0) |
|
7 |
Facter::Util::Resolution.stubs(:which).with('nft').returns('/usr/sbin/nft') |
|
8 |
Facter::Core::Execution.stubs(:execute).with('/usr/sbin/nft list tables').returns(nft_result) |
|
9 |
end |
|
10 |
|
|
11 |
context 'nft rules present' do |
|
12 |
let(:nft_result) { "table inet firewalld\ntable ip firewalld\n" } |
|
13 |
|
|
14 |
it 'returns valid tables' do |
|
15 |
expect(Facter.fact('nftables').value).to eq('tables' => ['inet-firewalld', 'ip-firewalld']) |
|
16 |
end |
|
17 |
end |
|
18 |
|
|
19 |
context 'nft fails' do |
|
20 |
let(:nft_result) { :failed } |
|
21 |
|
|
22 |
it 'does not return a fact' do |
|
23 |
Facter::Core::Execution.stubs(:execute).with('/usr/sbin/nft list tables', on_fail: :failed).returns(:failed) |
|
24 |
|
|
25 |
expect(Facter.fact('nftables').value).to be_nil |
|
26 |
end |
|
27 |
end |
|
28 |
end |
templates/config/puppet.nft.epp | ||
---|---|---|
1 |
<%- | |
|
2 |
Boolean $nat, |
|
3 |
Optional[Array[String[1],1]] $noflush = undef, |
|
4 |
|-%> |
|
5 |
<%- |
|
6 |
if $noflush and $facts['nftables'] and $facts['nftables']['tables'] { |
|
7 |
$_flush_command = $facts['nftables']['tables'].filter |$_tab| { ! ($_tab in $noflush) }.map |$_table| { |
|
8 |
"flush table ${regsubst($_table,'-',' ')}" |
|
9 |
} |
|
10 |
} else { |
|
11 |
$_flush_command = ['flush ruleset'] |
|
12 |
} |
|
13 |
-%> |
|
1 | 14 |
# puppet-preflight.nft is only used by puppet for validating new configs |
2 | 15 |
# puppet.nft is real configuration that the nftables services uses. |
3 | 16 |
# To process either the -I flag must be specified. |
... | ... | |
5 | 18 |
# nft -c -I /etc/nftables/puppet-preflight -f /etc/nftables/puppet-preflight.nft |
6 | 19 |
|
7 | 20 |
# drop any existing nftables ruleset |
8 |
flush ruleset
|
|
21 |
<%= $_flush_command.join('; ') %>
|
|
9 | 22 |
|
10 | 23 |
include "custom-*.nft" |
11 | 24 |
include "inet-filter.nft" |
templates/systemd/puppet_nft.conf.epp | ||
---|---|---|
1 |
<%- | |
|
2 |
Optional[Array[String[1]]] $noflush = undef, |
|
3 |
| -%> |
|
4 |
<%- |
|
5 |
if $noflush and $facts['nftables'] and $facts['nftables']['tables'] { |
|
6 |
$_flush_command = $facts['nftables']['tables'].filter |$_tab| { !( $_tab in $noflush) }.map |$_table| { |
|
7 |
"flush table ${regsubst($_table,'-',' ')}" |
|
8 |
} |
|
9 |
} else { |
|
10 |
$_flush_command = ['flush ruleset'] |
|
11 |
} |
|
12 |
-%> |
|
13 |
# Specify directory to look for relative includes |
|
14 |
[Service] |
|
15 |
ExecStart= |
|
16 |
ExecStart=/sbin/nft -I /etc/nftables/puppet -f /etc/sysconfig/nftables.conf |
|
17 |
ExecReload= |
|
18 |
ExecReload=/sbin/nft -I /etc/nftables/puppet '<%= $_flush_command.join('; ') %>; include "/etc/sysconfig/nftables.conf";' |
|
19 |
|
Formats disponibles : Unified diff