Document ferm::rule::simple
[mirror/dsa-puppet.git] / modules / ferm / manifests / rule / simple.pp
1 # A simple ferm rule.
2 #
3 # This rule will send IPv4 and/or IPv6 traffic using either TCP and/or UDP
4 # optionally going to a port, optionally from/to addresses/networks from
5 # one table (INPUT by default) to some target (ACCEPT by default).
6 #
7 # Sample uses:
8 #
9 #     ferm::rule::simple { '01-dsa-bind':
10 #       description => 'Allow nameserver access',
11 #       proto       => ['udp', 'tcp'],
12 #       port        => 'domain',
13 #     }
14 #
15 #  or:
16 #
17 #     ferm::rule::simple { 'dsa-smtp':
18 #       description => 'Allow smtp access from the world',
19 #       port        => '25',
20 #     }
21 #
22 #  or:
23 #
24 #     @@ferm::rule::simple { "submission-from-${::fqdn}":
25 #      tag   => 'smtp::server::submission::to::mail-relay',
26 #      chain => 'submission',
27 #      saddr => $base::public_addresses,
28 #    }
29 #  combined with:
30 #     ferm::rule::simple { 'submission-from-satellites':
31 #       target => 'submission',
32 #       port   => 'submission',
33 #     }
34 #     Ferm::Rule::Simple <<| tag == 'smtp::server::submission::to::mail-relay' |>>
35 #
36 #
37 # @param proto  tcp or udp or both.
38 # @param port   one or more ports or port ranges.
39 # @param saddr  one or more source addresses/networks.
40 # @param daddr  one or more destination addresses/networks.
41 # @param domain netfilter domain: ip (IPv4), ip6 (IPv6), or both.
42 # @param table  netfilter table
43 # @param chain  netfilter chain
44 # @param target netfilter target
45 # @param description a description of the rule
46 # @param prio   Priority/Order of the rule
47 define ferm::rule::simple (
48   String $description = '',
49   Variant[Enum['tcp', 'udp'], Array[Enum['tcp', 'udp']]] $proto = 'tcp',
50   Optional[Variant[Integer, Array[Integer], String, Array[String]]] $port = undef,
51   Optional[Variant[Stdlib::IP::Address, Array[Stdlib::IP::Address]]] $saddr = undef,
52   Optional[Variant[Stdlib::IP::Address, Array[Stdlib::IP::Address]]] $daddr = undef,
53   Variant[Enum['ip', 'ip6'], Array[Enum['ip', 'ip6']]] $domain = ['ip', 'ip6'],
54   String $table = 'filter',
55   String $chain = 'INPUT',
56   String $target = 'ACCEPT',
57   String $prio = '10',
58 ) {
59   include ferm
60
61   $filter_port  = $port  != undef
62   $filter_saddr = $saddr != undef
63   $filter_daddr = $daddr != undef
64
65   $real_domain = Array($domain, true)
66   $real_proto  = Array($proto, true)
67   $real_port   = Array($port, true)
68   $real_saddr  = Array($saddr, true)
69   $real_daddr  = Array($daddr, true)
70
71   file {
72     "/etc/ferm/dsa.d/${prio}_${name}":
73       ensure  => 'present',
74       mode    => '0400',
75       notify  => Exec['ferm reload'],
76       content => inline_template( @(EOF) ),
77                     domain (<%= @real_domain.join(' ') %>) {
78                       table <%= @table %> {
79                         <%-
80                         # netfilter chain names are limited to 28 characters, so if name is too long, we'll have to do something about that
81                         name = @name
82                         if name.size > 20 then
83                           require 'digest'
84                           name = 'dgst-' + Digest::SHA256.hexdigest(name)[0,15]
85                         end
86                         tail = "jump #{@target}"
87                         -%>
88                         <%=
89                           out = []
90                           [ [@filter_daddr, 'daddr', @real_daddr],
91                             [@filter_saddr, 'saddr', @real_saddr],
92                             [@filter_port , 'dport', @real_port ] ].each do |do_filter, filter_name, arr|
93                             next unless do_filter
94                             filter = "#{filter_name} (#{ arr.join(' ') })"
95                             if (arr.size > 2) then
96                               target = "#{name}-#{filter_name}"; prev_tail = tail; tail = "jump #{target}"
97                               out << "chain #{target} { #{filter} #{prev_tail}; }"
98                             else
99                               tail = "#{filter} #{tail}"
100                             end
101                           end
102                           out << "chain #{@chain} proto (#{ @real_proto.join(' ') }) #{tail};"
103                           out.join("\n")
104                         %>
105                       }
106                     }
107                     | EOF
108   }
109 }