aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRehan Mahmood <rehanone@gmail.com>2020-05-04 14:11:05 -0400
committerRehan Mahmood <rehanone@gmail.com>2020-05-07 00:27:49 -0400
commit6be13799d8a2ee49c3af88ffd7a474c39f1475e3 (patch)
tree77bc411088472f3e6db4e5095857d7cc550e0cb8
parent6362585d53490ff9e837af1359d8e80f8053d0fc (diff)
downloadpuppet-ferm-6be13799d8a2ee49c3af88ffd7a474c39f1475e3.tar.gz
puppet-ferm-6be13799d8a2ee49c3af88ffd7a474c39f1475e3.tar.bz2
Allow adding custom ferm dsl for subchains. This is important for using complex iptable rules that are currently not supported by this module or would be very hard to manage just using puppet.
-rw-r--r--REFERENCE.md36
-rw-r--r--manifests/chain.pp54
-rw-r--r--spec/acceptance/ferm_spec.rb63
-rw-r--r--spec/defines/chain_spec.rb28
-rw-r--r--templates/ferm_chain_custom.conf.epp4
5 files changed, 163 insertions, 22 deletions
diff --git a/REFERENCE.md b/REFERENCE.md
index 2d0a4e3..5c85d38 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -243,6 +243,34 @@ ferm::chain{'check-ssh':
}
```
+##### create a custom chain, e.g. for managing custom FORWARD chain rule for OpenVPN using custom ferm DSL.
+
+```puppet
+$my_rules = @(EOT)
+chain OPENVPN_FORWORD_RULES {
+ proto udp {
+ interface tun0 {
+ outerface enp4s0 {
+ mod conntrack ctstate (NEW) saddr @ipfilter((10.8.0.0/24)) ACCEPT;
+ }
+ }
+ }
+}
+| EOT
+
+ferm::chain{'OPENVPN_FORWORD_RULES':
+ chain => 'OPENVPN_FORWORD_RULES',
+ content => $my_rules,
+}
+
+ferm::rule { "OpenVPN - FORWORD all udp traffic from network 10.8.0.0/24 to subchain OPENVPN_FORWORD_RULES":
+ chain => 'FORWARD',
+ action => 'OPENVPN_FORWORD_RULES',
+ saddr => '10.8.0.0/24',
+ proto => 'udp',
+}
+```
+
#### Parameters
The following parameters are available in the `ferm::chain` defined type.
@@ -306,6 +334,14 @@ Set list of versions of ip we want ot use.
Default value: $ferm::ip_versions
+##### `content`
+
+Data type: `Optional[String]`
+
+Can only be used for custom chains. It allows you to provide your own ferm rules for this chain. Sets the contents of this custom chain to provided value.
+
+Default value: undef
+
### ferm::ipset
a defined resource that can match for ipsets at the top of a chain. This is a per-chain resource. You cannot mix IPv4 and IPv6 sets.
diff --git a/manifests/chain.pp b/manifests/chain.pp
index ed58126..91cd930 100644
--- a/manifests/chain.pp
+++ b/manifests/chain.pp
@@ -25,7 +25,8 @@ define ferm::chain (
String[1] $chain = $name,
Optional[Ferm::Policies] $policy = undef,
Ferm::Tables $table = 'filter',
- Array[Enum['ip','ip6']] $ip_versions = $ferm::ip_versions,
+ Array[Enum['ip', 'ip6']] $ip_versions = $ferm::ip_versions,
+ Optional[String[1]] $content = undef,
) {
# prevent unmanaged files due to new naming schema
# keep the default "filter" chains in the original location
@@ -43,32 +44,43 @@ define ferm::chain (
'filter' => ['INPUT', 'FORWARD', 'OUTPUT'],
}
- if $policy and ! ($chain in $builtin_chains[$table]) {
+ if $policy and !($chain in $builtin_chains[$table]) {
fail("Can only set a default policy for builtin chains. '${chain}' is not a builtin chain.")
}
# concat resource for the chain
- concat{$filename:
- ensure => 'present',
+ concat { $filename:
+ ensure => 'present',
}
- concat::fragment{"${table}-${chain}-policy":
- target => $filename,
- content => epp(
- "${module_name}/ferm_chain_header.conf.epp", {
- 'policy' => $policy,
- 'disable_conntrack' => $disable_conntrack,
- 'drop_invalid_packets_with_conntrack' => $drop_invalid_packets_with_conntrack,
- }
- ),
- order => '01',
- }
-
- if $log_dropped_packets {
- concat::fragment{"${table}-${chain}-footer":
+ if $content {
+ concat::fragment { "${table}-${chain}-custom-content":
target => $filename,
- content => epp("${module_name}/ferm_chain_footer.conf.epp", { 'chain' => $chain }),
- order => 'zzzzzzzzzzzzzzzzzzzzz',
+ content => epp(
+ "${module_name}/ferm_chain_custom.conf.epp", {
+ 'content' => $content,
+ },
+ ),
+ }
+ } else {
+ concat::fragment { "${table}-${chain}-policy":
+ target => $filename,
+ content => epp(
+ "${module_name}/ferm_chain_header.conf.epp", {
+ 'policy' => $policy,
+ 'disable_conntrack' => $disable_conntrack,
+ 'drop_invalid_packets_with_conntrack' => $drop_invalid_packets_with_conntrack,
+ }
+ ),
+ order => '01',
+ }
+
+ if $log_dropped_packets {
+ concat::fragment { "${table}-${chain}-footer":
+ target => $filename,
+ content => epp("${module_name}/ferm_chain_footer.conf.epp", { 'chain' => $chain }),
+ order => 'zzzzzzzzzzzzzzzzzzzzz',
+ }
}
}
@@ -77,7 +89,7 @@ define ferm::chain (
# This happens if we add ipset matches. We suffix this ordering with `bbb`. This allows us to
# insert ipset matches before other rules by adding `-aaa` or
# insert them at the end by ordering them with `-ccc`.
- concat::fragment{"${table}-${chain}-config-include":
+ concat::fragment { "${table}-${chain}-config-include":
target => $ferm::configfile,
content => epp(
"${module_name}/ferm-table-chain-config-include.epp", {
diff --git a/spec/acceptance/ferm_spec.rb b/spec/acceptance/ferm_spec.rb
index 0dd2399..8c5c454 100644
--- a/spec/acceptance/ferm_spec.rb
+++ b/spec/acceptance/ferm_spec.rb
@@ -26,6 +26,10 @@ iptables_output = case sut_os
'-A HTTP -s 127.0.0.1/32 -p tcp -m comment --comment ["]*allow_http_localhost["]* -m tcp --dport 80 -j ACCEPT'
]
end
+
+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']
+
basic_manifest = %(
class { 'ferm':
manage_service => true,
@@ -124,7 +128,7 @@ describe 'ferm' do
end
end
- context 'with dropping INVALID pakets' do
+ context 'with dropping INVALID packets' do
pp2 = %(
class { 'ferm':
manage_service => true,
@@ -162,4 +166,61 @@ describe 'ferm' do
end
end
end
+
+ context 'with custom chain using ferm DSL as content' do
+ advanced_manifest = %(
+ $my_rules = @(EOT)
+ chain OPENVPN_FORWORD_RULES {
+ proto udp {
+ interface tun0 {
+ outerface enp4s0 {
+ mod conntrack ctstate (NEW) saddr @ipfilter((10.8.0.0/24)) ACCEPT;
+ }
+ }
+ }
+ }
+ | EOT
+
+ ferm::chain{'OPENVPN_FORWORD_RULES':
+ chain => 'OPENVPN_FORWORD_RULES',
+ content => $my_rules,
+ }
+
+ ferm::rule { "OpenVPN - FORWORD all udp traffic from network 10.8.0.0/24 to subchain OPENVPN_FORWORD_RULES":
+ chain => 'FORWARD',
+ action => 'OPENVPN_FORWORD_RULES',
+ saddr => '10.8.0.0/24',
+ proto => 'udp',
+ }
+ )
+ pp = [basic_manifest, advanced_manifest].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 iptables do
+ it do
+ is_expected.to have_rule(iptables_output_custom[0]). \
+ with_table('filter'). \
+ with_chain('FORWARD')
+ end
+ it do
+ is_expected.to have_rule(iptables_output_custom[1]). \
+ with_table('filter'). \
+ with_chain('OPENVPN_FORWORD_RULES')
+ end
+ end
+
+ describe service('ferm') do
+ it { is_expected.to be_running }
+ end
+
+ describe command('iptables-save') do
+ its(:stdout) { is_expected.to match %r{FORWARD.*-j OPENVPN_FORWORD_RULES} }
+ end
+ end
end
diff --git a/spec/defines/chain_spec.rb b/spec/defines/chain_spec.rb
index 1a6bb44..52cc88c 100644
--- a/spec/defines/chain_spec.rb
+++ b/spec/defines/chain_spec.rb
@@ -70,6 +70,34 @@ describe 'ferm::chain', type: :define do
it { is_expected.to compile.and_raise_error(%r{Can only set a default policy for builtin chains}) }
end
+
+ context 'with custom chain FERM-DSL using content parameter' do
+ let(:title) { 'FERM-DSL' }
+ let :params do
+ {
+ content: 'mod rpfilter invert DROP;'
+ }
+ end
+
+ it { is_expected.to compile.with_all_deps }
+ it { is_expected.to contain_concat__fragment('filter-FERM-DSL-config-include') }
+ it do
+ is_expected.to contain_concat__fragment('filter-FERM-DSL-custom-content'). \
+ with_content(%r{mod rpfilter invert DROP;})
+ end
+ it do
+ is_expected.not_to contain_concat__fragment('filter-FERM-DSL-policy')
+ end
+ it do
+ is_expected.not_to contain_concat__fragment('filter-FERM-DSL-footer')
+ end
+ if facts[:os]['name'] == 'Debian'
+ it { is_expected.to contain_concat('/etc/ferm/ferm.d/chains/filter-FERM-DSL.conf') }
+ else
+ it { is_expected.to contain_concat('/etc/ferm.d/chains/filter-FERM-DSL.conf') }
+ end
+ it { is_expected.to contain_ferm__chain('FERM-DSL') }
+ end
end
end
end
diff --git a/templates/ferm_chain_custom.conf.epp b/templates/ferm_chain_custom.conf.epp
new file mode 100644
index 0000000..356311c
--- /dev/null
+++ b/templates/ferm_chain_custom.conf.epp
@@ -0,0 +1,4 @@
+<%- | String[1] $content,
+| -%>
+# THIS FILE IS MANAGED BY PUPPET
+<%= $content %>