Merge pull request #40 from Sxderp/pr-add-dictionary-rich-rules2

Allow rich_rules to be specified as a dictionary
This commit is contained in:
Imran Iqbal 2020-04-02 13:19:52 +01:00 committed by GitHub
commit 5c135df025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 186 additions and 64 deletions

View File

@ -8,3 +8,5 @@ Layout/LineLength:
Max: 88 Max: 88
# Any offenses that should be fixed, e.g. collected via. `rubocop --auto-gen-config` # Any offenses that should be fixed, e.g. collected via. `rubocop --auto-gen-config`
Metrics/BlockLength:
Max: 39

View File

@ -4,6 +4,72 @@
Do not edit this file manually, it will be overwritten! Do not edit this file manually, it will be overwritten!
Modify the salt pillar for firewalld instead Modify the salt pillar for firewalld instead
--> -->
{%- macro rich_rule(rule) -%}
{%- if 'family' in rule %}
<rule family="{{ rule.family }}">
{%- else %}
<rule>
{%- endif %}
{%- if 'ipset' in rule %}
<source ipset="{{ rule.ipset.name }}" />
{%- endif %}
{%- if 'source' in rule %}
<source address="{{ rule.source.address }}" {%- if 'invert' in rule.source %}invert="{{ rule.source.invert }}"{%- endif %} />
{%- endif %}
{%- if 'destination' in rule %}
<destination address="{{ rule.destination.address }}" {%- if 'invert' in rule.destination %}invert="{{ rule.destination.invert }}"{%- endif %} />
{%- endif %}
{%- if 'service' in rule %}
<service name="{{ rule.service }}" />
{%- endif %}
{%- if 'port' in rule %}
<port port="{{ rule.port.portid }}" protocol="{{ rule.port.protocol }}" />
{%- endif %}
{%- if 'protocol' in rule %}
<protocol value="{{ rule.protocol }}" />
{%- endif %}
{%- if 'icmp_block' in rule %}
<icmp-block name="{{ rule.icmp_block }}" />
{%- endif %}
{%- if 'icmp_type' in rule %}
<icmp-type name="{{ rule.icmp_type }}" />
{%- endif %}
{%- if 'masquerade' in rule %}
{%- if rule.masquerade %}<masquerade/>{%- endif %}
{%- endif %}
{%- if 'forward_port' in rule %}
{%- if 'comment' in rule.forward_port %}
<!-- {{ rule.forward_port.comment }} -->
{%- endif %}
<forward-port port="{{ rule.forward_port.portid }}" protocol="{{ rule.forward_port.protocol }}"{%- if 'to_port' in rule.forward_port %} to-port="{{ rule.forward_port.to_port }}"{%- endif %}{%- if 'to_addr' in rule.forward_port %} to-addr="{{ rule.forward_port.to_addr }}"{%- endif %} />
{%- endif %}
{%- if 'source_port' in rule %}
{%- if 'comment' in rule.source_port %}
<!-- {{ rule.source_port.comment }} -->
{%- endif %}
<source-port port="{{ rule.source_port.portid }}" protocol="{{ rule.source_port.protocol }}"{%- if 'to_port' in rule.source_port %} to-port="{{ rule.source_port.to_port }}"{%- endif %}{%- if 'to_addr' in rule.source_port %} to-addr="{{ rule.source_port.to_addr }}"{%- endif %} />
{%- endif %}
{%- if 'log' in rule %}
<log{%- if 'prefix' in rule.log %} prefix="{{ rule.log.prefix }}"{%- endif %}{%- if 'level' in rule.log %} level="{{ rule.log.level }}"{%- endif %}>
{%- if 'limit' in rule.log %}
<limit value="{{ rule.log.limit }}"/>
{%- endif %}
</log>
{%- endif %}
{%- if 'audit' in rule %}
<audit>{%- if 'limit' in rule.audit %} <limit value="{{ rule.audit.limit }}"/>{%- endif %}</audit>
{%- endif %}
{%- if 'accept' in rule %}
<accept/>
{%- endif %}
{%- if 'reject' in rule %}
<reject{%- if 'type' in rule.reject %} type="{{ rule.reject.type }}"{%- endif %} />
{%- endif %}
{%- if 'drop' in rule %}
<drop/>
{%- endif %}
</rule>
{%- endmacro %}
<zone{%- if 'target' in zone %} target="{{ zone.target }}"{%- endif %}> <zone{%- if 'target' in zone %} target="{{ zone.target }}"{%- endif %}>
{% if 'short' in zone %}<short>{{ zone.short }}</short>{% else %}<short>{{ name }}</short>{% endif %} {% if 'short' in zone %}<short>{{ zone.short }}</short>{% else %}<short>{{ name }}</short>{% endif %}
{% if 'description' in zone %}<description>{{ zone.description }}</description>{% endif %} {% if 'description' in zone %}<description>{{ zone.description }}</description>{% endif %}
@ -82,73 +148,39 @@
<source-port port="{{ v.port }}" protocol="{{ v.protocol }}" /> <source-port port="{{ v.port }}" protocol="{{ v.protocol }}" />
{%- endfor %} {%- endfor %}
{%- endif %} {%- endif %}
{%- if 'rich_rules' in zone %} {%- if 'rich_rules' in zone %}
{%- for rule in zone.rich_rules %} {%- if zone.rich_rules is list %}
{%- if 'family' in rule %} {%- set rich_rules = zone.rich_rules %}
<rule family="{{ rule.family }}">
{%- else %} {%- else %}
<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 %} {%- endif %}
{%- if 'ipset' in rule %} {%- endfor %}
<source ipset="{{ rule.ipset.name }}" /> {%- 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 %} {%- endif %}
{%- if 'source' in rule %} {%- endfor %}
<source address="{{ rule.source.address }}" {%- if 'invert' in rule.source %}invert="{{ rule.source.invert }}"{%- endif %} />
{%- endif %} {%- endif %}
{%- if 'destination' in rule %} {%- for rule in rich_rules %}
<destination address="{{ rule.destination.address }}" {%- if 'invert' in rule.destination %}invert="{{ rule.destination.invert }}"{%- endif %} /> {{- rich_rule(rule) }}
{%- endif %}
{%- if 'service' in rule %}
<service name="{{ rule.service }}" />
{%- endif %}
{%- if 'port' in rule %}
<port port="{{ rule.port.portid }}" protocol="{{ rule.port.protocol }}" />
{%- endif %}
{%- if 'protocol' in rule %}
<protocol value="{{ rule.protocol }}" />
{%- endif %}
{%- if 'icmp_block' in rule %}
<icmp-block name="{{ rule.icmp_block }}" />
{%- endif %}
{%- if 'icmp_type' in rule %}
<icmp-type name="{{ rule.icmp_type }}" />
{%- endif %}
{%- if 'masquerade' in rule %}
{%- if rule.masquerade %}<masquerade/>{%- endif %}
{%- endif %}
{%- if 'forward_port' in rule %}
{%- if 'comment' in rule.forward_port %}
<!-- {{ rule.forward_port.comment }} -->
{%- endif %}
<forward-port port="{{ rule.forward_port.portid }}" protocol="{{ rule.forward_port.protocol }}"{%- if 'to_port' in rule.forward_port %} to-port="{{ rule.forward_port.to_port }}"{%- endif %}{%- if 'to_addr' in rule.forward_port %} to-addr="{{ rule.forward_port.to_addr }}"{%- endif %} />
{%- endif %}
{%- if 'source_port' in rule %}
{%- if 'comment' in rule.source_port %}
<!-- {{ rule.source_port.comment }} -->
{%- endif %}
<source-port port="{{ rule.source_port.portid }}" protocol="{{ rule.source_port.protocol }}"{%- if 'to_port' in rule.source_port %} to-port="{{ rule.source_port.to_port }}"{%- endif %}{%- if 'to_addr' in rule.source_port %} to-addr="{{ rule.source_port.to_addr }}"{%- endif %} />
{%- endif %}
{%- if 'log' in rule %}
<log{%- if 'prefix' in rule.log %} prefix="{{ rule.log.prefix }}"{%- endif %}{%- if 'level' in rule.log %} level="{{ rule.log.level }}"{%- endif %}>
{%- if 'limit' in rule.log %}
<limit value="{{ rule.log.limit }}"/>
{%- endif %}
</log>
{%- endif %}
{%- if 'audit' in rule %}
<audit>{%- if 'limit' in rule.audit %} <limit value="{{ rule.audit.limit }}"/>{%- endif %}</audit>
{%- endif %}
{%- if 'accept' in rule %}
<accept/>
{%- endif %}
{%- if 'reject' in rule %}
<reject{%- if 'type' in rule.reject %} type="{{ rule.reject.type }}"{%- endif %} />
{%- endif %}
{%- if 'drop' in rule %}
<drop/>
{%- endif %}
</rule>
{%- endfor %} {%- endfor %}
{%- endif %} {%- endif %}
</zone> </zone>

View File

@ -151,6 +151,21 @@ firewalld:
port: 4444 port: 4444
protocol: tcp 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: direct:
chain: chain:
MYCHAIN: MYCHAIN:

View File

@ -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
<zone>
<short>Public</short>
<description>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.</description>
<service name="zabbixcustom" />
<service name="http" />
<service name="https" />
<service name="ssh" />
<service name="salt-minion" />
<!-- zabbix-agent -->
<port port="10050" protocol="tcp" />
<!-- bacula-client -->
<port port="9102" protocol="tcp" />
<!-- vsftpd -->
<port port="21" protocol="tcp" />
<protocol value="igmp" />
<!-- something -->
<source-port port="2222" protocol="tcp" />
<!-- something_else -->
<source-port port="4444" protocol="tcp" />
<rule family="ipv4">
<source address="8.8.8.8/24" />
<accept/>
</rule>
<rule family="ipv4">
<source ipset="fail2ban-ssh" />
<reject type="icmp-port-unreachable" />
</rule>
</zone>
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
<zone>
<short>rich_public</short>
<description>Example</description>
<rule>
<source ipset="fail2ban-ssh" />
<service name="ssh" />
<accept/>
</rule>
<rule>
<source ipset="other-ipset" />
<service name="ssh" />
<accept/>
</rule>
</zone>
ZONE_XML
end
end
end