diff --git a/.rubocop.yml b/.rubocop.yml index 96fd6e5..fa4b05d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,3 +8,5 @@ Layout/LineLength: Max: 88 # Any offenses that should be fixed, e.g. collected via. `rubocop --auto-gen-config` +Metrics/BlockLength: + Max: 39 diff --git a/firewalld/files/zone.xml b/firewalld/files/zone.xml index dabe00a..c730b1c 100644 --- a/firewalld/files/zone.xml +++ b/firewalld/files/zone.xml @@ -4,6 +4,72 @@ Do not edit this file manually, it will be overwritten! Modify the salt pillar for firewalld instead --> +{%- macro rich_rule(rule) -%} + {%- if 'family' in rule %} + + {%- else %} + + {%- endif %} + {%- if 'ipset' in rule %} + + {%- endif %} + {%- if 'source' in rule %} + + {%- endif %} + {%- if 'destination' in rule %} + + {%- endif %} + {%- if 'service' in rule %} + + {%- endif %} + {%- if 'port' in rule %} + + {%- endif %} + {%- if 'protocol' in rule %} + + {%- endif %} + {%- if 'icmp_block' in rule %} + + {%- endif %} + {%- if 'icmp_type' in rule %} + + {%- endif %} + {%- if 'masquerade' in rule %} + {%- if rule.masquerade %}{%- endif %} + {%- endif %} + {%- if 'forward_port' in rule %} + {%- if 'comment' in rule.forward_port %} + + {%- endif %} + + {%- endif %} + {%- if 'source_port' in rule %} + {%- if 'comment' in rule.source_port %} + + {%- endif %} + + {%- endif %} + {%- if 'log' in rule %} + + {%- if 'limit' in rule.log %} + + {%- endif %} + + {%- endif %} + {%- if 'audit' in rule %} + {%- if 'limit' in rule.audit %} {%- endif %} + {%- endif %} + {%- if 'accept' in rule %} + + {%- endif %} + {%- if 'reject' in rule %} + + {%- endif %} + {%- if 'drop' in rule %} + + {%- endif %} + +{%- endmacro %} {% if 'short' in zone %}{{ zone.short }}{% else %}{{ name }}{% endif %} {% if 'description' in zone %}{{ zone.description }}{% endif %} @@ -82,73 +148,39 @@ {%- endfor %} {%- endif %} - {%- if 'rich_rules' in zone %} - {%- for rule in zone.rich_rules %} - {%- if 'family' in rule %} - + {%- if zone.rich_rules is list %} + {%- set rich_rules = zone.rich_rules %} {%- else %} - - {%- endif %} - {%- if 'ipset' in rule %} - + {%- set expanded_ipset_rules = [] %} + {%- for name,rule in zone.rich_rules|dictsort %} + {%- if 'ipsets' in rule %} + {%- for ipset in rule.ipsets %} + {%- set tmp_rule = {} %} + {%- set _dummy = tmp_rule.update(rule) %} + {%- set _dummy = tmp_rule.update({'ipset':{'name':ipset}}) %} + {%- set _dummy = expanded_ipset_rules.append(tmp_rule) %} + {%- endfor %} + {%- else %} + {%- set _dummy = expanded_ipset_rules.append(rule) %} + {%- endif %} + {%- endfor %} + {%- set rich_rules = [] %} + {%- for rule in expanded_ipset_rules %} + {%- if 'services' in rule %} + {%- for service in rule.services %} + {%- set tmp_rule = {} %} + {%- set _dummy = tmp_rule.update(rule) %} + {%- set _dummy = tmp_rule.update({'service':service}) %} + {%- set _dummy = rich_rules.append(tmp_rule) %} + {%- endfor %} + {%- else %} + {%- set _dummy = rich_rules.append(rule) %} + {%- endif %} + {%- endfor %} {%- endif %} - {%- if 'source' in rule %} - - {%- endif %} - {%- if 'destination' in rule %} - - {%- endif %} - {%- if 'service' in rule %} - - {%- endif %} - {%- if 'port' in rule %} - - {%- endif %} - {%- if 'protocol' in rule %} - - {%- endif %} - {%- if 'icmp_block' in rule %} - - {%- endif %} - {%- if 'icmp_type' in rule %} - - {%- endif %} - {%- if 'masquerade' in rule %} - {%- if rule.masquerade %}{%- endif %} - {%- endif %} - {%- if 'forward_port' in rule %} - {%- if 'comment' in rule.forward_port %} - - {%- endif %} - - {%- endif %} - {%- if 'source_port' in rule %} - {%- if 'comment' in rule.source_port %} - - {%- endif %} - - {%- endif %} - {%- if 'log' in rule %} - - {%- if 'limit' in rule.log %} - - {%- endif %} - - {%- endif %} - {%- if 'audit' in rule %} - {%- if 'limit' in rule.audit %} {%- endif %} - {%- endif %} - {%- if 'accept' in rule %} - - {%- endif %} - {%- if 'reject' in rule %} - - {%- endif %} - {%- if 'drop' in rule %} - - {%- endif %} - + {%- for rule in rich_rules %} +{{- rich_rule(rule) }} {%- endfor %} {%- endif %} diff --git a/pillar.example b/pillar.example index bdb1854..3f64319 100644 --- a/pillar.example +++ b/pillar.example @@ -151,6 +151,21 @@ firewalld: port: 4444 protocol: tcp + rich_public: + short: rich_public + description: "Example" + # Rich rules can be specified as a dictionary. All keys from standard rich rules + # can be used. Special keys "ipsets" and "services", if defined, take precedence. + # They will be auto-expanded into separate rich rules per value in the list. + rich_rules: + ssh-csg: + accept: true + ipsets: + - fail2ban-ssh + - other-ipset + services: + - ssh + direct: chain: MYCHAIN: diff --git a/test/integration/default/controls/zones_spec.rb b/test/integration/default/controls/zones_spec.rb new file mode 100644 index 0000000..82382ba --- /dev/null +++ b/test/integration/default/controls/zones_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +control 'zones/public.xml configuration' do + title 'should match desired lines' + + describe file('/etc/firewalld/zones/public.xml') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') do + should include <<~ZONE_XML + + Public + For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted. + + + + + + + + + + + + + + + + + + + + + + + + + + ZONE_XML + end + end +end + +control 'zones/rich_public.xml configuration' do + title 'should match desired lines' + + describe file('/etc/firewalld/zones/rich_public.xml') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') do + should include <<~ZONE_XML + + rich_public + Example + + + + + + + + + + + + ZONE_XML + end + end +end