debops.ferm default variables
Sections
ferm configuration
- ferm__enabled
Enable or disable iptables management by checking if cap_net_admin
POSIX capability is set on the host.
ferm__enabled: '{{ True
if (ansible_system_capabilities is undefined or
(((ansible_system_capabilities_enforced | d()) | bool and
"cap_net_admin" in ansible_system_capabilities) or
not (ansible_system_capabilities_enforced | d(True)) | bool))
else False }}'
- ferm__flush
Should ferm-rules be flushed when ferm is disabled? The default is true,
but you may need set both ferm__enabled
and this to False
if you are
running in some container and are not allowed to change iptables.
ferm__flush: '{{ ferm__enabled | bool }}'
- ferm__iptables_backend_enabled
Enable or disable configuration of the iptables backend symlink using the "alternatives" system, supported on Debian 10 and later.
ferm__iptables_backend_enabled: '{{ False
if ansible_distribution_release in
["stretch", "trusty", "xenial",
"bionic", "focal"]
else True }}'
- ferm__iptables_backend_type
Select which iptables backend should be used on the host. Known backends:
legacy
- old arptables, ebtables, iptables, ip6tablesnft
- new, nftables-based firewall
Ferm does not support nftables backend, therefore the legacy variant is enabled by default.
ferm__iptables_backend_type: 'legacy'
- ferm__base_packages
List of base APT packages to install.
ferm__base_packages: [ 'ferm', 'patch', 'iptables', 'arptables', 'ebtables' ]
- ferm__packages
List of additional APT packages to install.
ferm__packages: []
- ferm__domains
List of iptables domains enabled in main ferm firewall. Currently supported domains:
ip
Enables IPv4 support (iptables).
ip6
Enables IPv6 support (ip6tables).
ferm__domains: '{{ lookup("flattened",
((["ip"] if (ansible_all_ipv4_addresses | d()) else [])
+ (["ip6"] if (ansible_all_ipv6_addresses | d()) else [])),
wantlist=True) }}'
- ferm__ansible_controllers
Optional list of CIDR hosts which are not included in ssh port recent filter and won't be blocked by the firewall in case of too many connections. Entries are saved in the local facts on remote hosts. Remember to specify IP address from the remote host point of view. Format: "IP address/netmask", for example: '192.168.1.1/32'.
Note
If you are using debops.tcpwrappers too (or the DebOps playbook), mind setting its own Ansible Controllers variable as well. An easier way would be to use the debops.sshd role to configure ssh service.
ferm__ansible_controllers: []
- ferm__ansible_controllers_ports
List of ports which are opened for access from Ansible Controllers.
ferm__ansible_controllers_ports: [ 'ssh' ]
- ferm__ansible_controllers_interfaces
List of interfaces for the default Ansible Controllers rule. An empty list means all interfaces.
ferm__ansible_controllers_interfaces: []
- ferm__fast_mode
Use iptables-restore for fast firewall initialization?
ferm__fast_mode: False
- ferm__use_cache
Use iptables-restore for fast firewall initialization?
ferm__use_cache: False
- ferm__extra_options
Additional parameters for ferm (like --def '=bar')
ferm__extra_options: ""
- ferm__default_policy_input
Default iptables policy for INPUT
chain.
ferm__default_policy_input: 'DROP'
- ferm__default_policy_output
Default iptables policy for OUTPUT
chain.
ferm__default_policy_output: 'ACCEPT'
- ferm__default_policy_forward
Default iptables policy for FORWARD
chain.
ferm__default_policy_forward: 'DROP'
Rate limit filter configuration
- ferm__filter_icmp
Manage filtering of ICMP packets using the hashlimit
module.
ferm__filter_icmp: True
- ferm__filter_icmp_limit
Rate limit when filtering ICMP packets.
ferm__filter_icmp_limit: '10/second'
- ferm__filter_icmp_burst
Burst limit when filtering ICMP packets.
ferm__filter_icmp_burst: '10'
- ferm__filter_icmp_expire
Expiration time when filtering ICMP packets in seconds. Defaults to 1 hour.
ferm__filter_icmp_expire: '{{ (60 * 60) }}'
- ferm__filter_syn
Manage filtering of TCP SYN segments using the hashlimit
module.
ferm__filter_syn: True
- ferm__filter_syn_limit
Rate limit when filtering TCP SYN segments.
ferm__filter_syn_limit: '40/second'
- ferm__filter_syn_burst
Burst limit when filtering TCP SYN segments.
ferm__filter_syn_burst: '40'
- ferm__filter_syn_expire
Expiration time when filtering TCP SYN segments in seconds. Defaults to 1 hour.
ferm__filter_syn_expire: '{{ (60 * 60) }}'
- ferm__filter_recent
Enable recent filter in respective rules. You might need to disable it on
certain hosts, like OpenVZ containers that don't have the recent
module
available.
ferm__filter_recent: True
- ferm__filter_recent_name
Name of recent list to block early.
ferm__filter_recent_name: 'badguys'
- ferm__filter_recent_time
Length of time in seconds to block recent offenders; if they try connecting before the time is up, timer is reset.
ferm__filter_recent_time: '{{ (60 * 60 * 2) }}'
- ferm__mark_portscan
Mark packets on invalid ports as bad guys (block port scanning). For more information check Block Port Scans.
ferm__mark_portscan: False
Logging configuration
- ferm__log
Enable/disable custom &log()
ferm function used in different firewall
rules.
ferm__log: True
- ferm__log_type
Select how firewall performs logging. By default, it uses normal syslog calls, there are other ways to log packets listed below.
ferm__log_type: 'LOG'
- ferm__log_map
Dictionary map with actual firewall rules mapped to different log types.
ferm__log_map:
'LOG': 'LOG log-ip-options log-prefix "$msg"'
'ULOG': 'ULOG ulog-nlgroup {{ ferm__log_group }} ulog-prefix "$msg"'
'NFLOG': 'NFLOG nflog-group {{ ferm__log_group }} nflog-prefix "$msg"'
- ferm__log_target
Firewall log target used in the &log()
ferm function.
ferm__log_target: '{{ ferm__log_map[ferm__log_type] }}'
- ferm__log_limit
Limit the amount of packets logged by the firewall.
ferm__log_limit: '2/min'
- ferm__log_burst
Set the burst limit for the logged packets.
ferm__log_burst: '5'
- ferm__log_group
ULOG/NFLOG group used by the firewall logs.
ferm__log_group: '32'
Firewall rules configuration
The variables below define what rules should be present in the firewall. Each
variable is a YAML dictionary with nested dictionaries. They are combined in
the ferm__combined_rules
variable. See ferm__rules for
more details.
- ferm__include_legacy
Include legacy firewall rules. This variable should allow for easier transition to the new firewall rules in the future.
ferm__include_legacy: True
- ferm__mdns_state
Enable or disable the firewall rule to allow Multicast DNS packets. Multicast
DNS is used by systemd-resolved service to resolve the .local
domain, also used by Avahi/Bonjour services.
ferm__mdns_state: 'present'
- ferm__mdns_allow
List of IP addresses or CIDR subneds which are allowed to send Multicast DNS packets to the host. If the list is empty, any host will be accepted.
ferm__mdns_allow: []
- ferm__dependent_rules
YAML list which contains ferm rules to manage defined by other Ansible roles using dependent variables.
ferm__dependent_rules: []
- ferm__fix_dependent_rules
For now, some rules defined by other Ansible roles are incomplete. This template makes sure that all required information is added if missing. This variable will be removed at some point in the future, therefore you should not rely on it.
ferm__fix_dependent_rules: '{{ lookup("template",
"lookup/ferm__fix_dependent_rules.j2",
convert_data=False) | from_yaml }}'
- ferm__rules
YAML list which contains ferm rules which should be defined on all hosts in the Ansible inventory.
ferm__rules: []
- ferm__group_rules
YAML list which contains ferm rules which should be defined on a group of hosts in the Ansible inventory.
ferm__group_rules: []
- ferm__host_rules
YAML list which contains ferm rules which should be defined on specific hosts in the Ansible inventory.
ferm__host_rules: []
- ferm__combined_rules
YAML list which defines the order in which firewall rules are defined and affect each other. This list is then passed to the parser template to generate final dictionary with rules for ferm.
ferm__combined_rules: '{{ ferm__default_rules
+ ferm__fix_dependent_rules
+ ferm__rules
+ ferm__group_rules
+ ferm__host_rules }}'
- ferm__parsed_rules
YAML dictionary which contains all of the defined ferm rules combined together. This variable is used in the Ansible tasks that manage the rules on remote hosts.
ferm__parsed_rules: '{{ lookup("template",
"lookup/ferm__parsed_rules.j2",
convert_data=False) | from_yaml }}'
- ferm_input_list
This is a legacy variable and shouldn't be used! List of iptables INPUT rules to manage. See ferm_input_list for more details.
ferm_input_list: []
- ferm_input_group_list
This is a legacy variable and shouldn't be used! List of iptables INPUT rules to manage for a host group. See ferm_input_list for more details.
ferm_input_group_list: []
- ferm_input_host_list
This is a legacy variable and shouldn't be used! List of iptables INPUT rules to manage for an individual host. See ferm_input_list for more details.
ferm_input_host_list: []
- ferm_input_dependent_list
This is a legacy variable and shouldn't be used! List of iptables INPUT rules to manage in dependency to other rules. See ferm_input_list for more details.
ferm_input_dependent_list: []
- ferm__default_weight_map
Dictionary with mapping between "rule classes" and their desired weight.
ferm__default_weight_map:
'pre-hook': '00'
'function': '00'
'custom': '00'
'loopback': '01'
'default_policy': '05'
'policy': '05'
'ansible-controller': '05'
'any-whitelist': '10'
'filter-icmp': '15'
'connection-tracking': '20'
'filter-syn': '25'
'any-blacklist': '30'
'sshd-chain': '40'
'any-forward': '60'
'default': '100'
'accept': '100'
'any-service': '100'
'reject': '900'
'any-reject': '900'
'post-hook': '950'
- ferm__weight_map
Dictionary with additional mapping between "rule classes" and their desired weight. This variable can be used to override weight for specific weight classes.
ferm__weight_map: {}
- ferm__combined_weight_map
YAML dictionary with the combined default and custom weight maps, used by the Ansible tasks.
ferm__combined_weight_map: '{{ ferm__default_weight_map
| combine(ferm__weight_map) }}'
- ferm__default_rules
YAML dictionary with default firewall rules defined on each host.
ferm__default_rules:
- name: 'policy_filter_input'
type: 'default_policy'
chain: 'INPUT'
policy: '{{ ferm__default_policy_input }}'
- name: 'policy_filter_forward'
type: 'default_policy'
chain: 'FORWARD'
policy: '{{ ferm__default_policy_forward }}'
- name: 'policy_filter_output'
type: 'default_policy'
chain: 'OUTPUT'
policy: '{{ ferm__default_policy_output }}'
- name: 'firewall_hooks'
type: 'custom'
comment: 'Run custom hooks at various firewall stages'
rules: |
@hook pre "run-parts /etc/ferm/hooks/pre.d";
@hook post "run-parts /etc/ferm/hooks/post.d";
@hook flush "run-parts /etc/ferm/hooks/flush.d";
- name: 'firewall_variables'
type: 'custom'
comment: 'Define custom variables available in the firewall'
rules: |
@def $domains = ({{ ferm__domains | unique | join(" ") }});
@def $ipv4_enabled = {{ "1" if "ip" in ferm__domains else "0" }};
@def $ipv6_enabled = {{ "1" if "ip6" in ferm__domains else "0" }};
- name: 'firewall_log'
type: 'custom'
comment: 'Custom log function used by other rules'
rules: |
@def &log($msg) = {
mod limit limit {{ ferm__log_limit }}
limit-burst {{ ferm__log_burst }}
{{ ferm__log_target }};
}
rule_state: '{{ "present" if (ferm__log | bool) else "absent" }}'
- name: 'accept_loopback'
type: 'accept'
weight_class: 'loopback'
interface: 'lo'
- name: 'accept_ansible_controller'
type: 'ansible_controller'
weight_class: 'ansible-controller'
comment: 'Accept SSH connections from Ansible Controllers'
dport: '{{ ferm__ansible_controllers_ports }}'
interface: '{{ ferm__ansible_controllers_interfaces }}'
multiport: True
accept_any: False
- name: 'filter_icmp_flood'
type: 'hashlimit'
weight_class: 'filter-icmp'
protocol: 'icmp'
rule_state: '{{ "present" if (ferm__filter_icmp | bool) else "absent" }}'
hashlimit: '{{ ferm__filter_icmp_limit }}'
hashlimit_burst: '{{ ferm__filter_icmp_burst }}'
hashlimit_expire: '{{ ferm__filter_icmp_expire }}'
hashlimit_target: 'ACCEPT'
target: 'DROP'
- name: 'connection_tracking'
type: 'connection_tracking'
weight_class: 'connection-tracking'
chain: [ 'INPUT', 'OUTPUT', 'FORWARD' ]
- name: 'filter_syn_flood'
type: 'hashlimit'
weight_class: 'filter-syn'
protocol: 'tcp'
protocol_syn: True
rule_state: '{{ "present" if (ferm__filter_syn | bool) else "absent" }}'
hashlimit: '{{ ferm__filter_syn_limit }}'
hashlimit_burst: '{{ ferm__filter_syn_burst }}'
hashlimit_expire: '{{ ferm__filter_syn_expire }}'
hashlimit_target: 'RETURN'
target: 'DROP'
- name: 'block_recent_badguys'
type: 'recent'
weight_class: 'any-blacklist'
comment: 'Reject packets marked as "badguys"'
rule_state: '{{ "present" if (ferm__filter_recent | bool) else "absent" }}'
recent_name: '{{ ferm__filter_recent_name }}'
recent_update: True
recent_seconds: '{{ ferm__filter_recent_time }}'
recent_target: 'REJECT'
- name: 'clean_recent_badguys'
type: 'recent'
weight_class: 'any-blacklist'
comment: 'Reject packets marked as "badguys"'
rule_state: '{{ "present" if (ferm__filter_recent | bool) else "absent" }}'
recent_name: '{{ ferm__filter_recent_name }}'
recent_remove: True
recent_log: False
- name: 'accept_dhcpv6_client_solicit'
type: 'accept'
weight_class: 'any-service'
comment: 'Initial DHCPv6 Solicit message is sent to multicast'
domain: [ 'ip6' ]
saddr: [ 'fe80::/10' ]
daddr: [ 'ff02::1:2/128' ]
protocol: [ 'udp' ]
sport: [ 'dhcpv6-client' ]
dport: [ 'dhcpv6-server' ]
rule_state: '{{ "present" if ("ip6" in ferm__domains) else "absent" }}'
- name: 'accept_dhcpv6_client'
type: 'accept'
weight_class: 'any-service'
comment: 'DHCPv6 responses seem to be neither RELATED nor ESTABLISHED.'
domain: [ 'ip6' ]
saddr: [ 'fe80::/10' ]
daddr: [ 'fe80::/10' ]
protocol: [ 'udp' ]
sport: [ 'dhcpv6-server' ]
dport: [ 'dhcpv6-client' ]
rule_state: '{{ "present" if ("ip6" in ferm__domains) else "absent" }}'
# Multicast DNS is used by systemd-resolved for '.local' name resolution.
- name: 'accept_mdns'
type: 'accept'
dport: 'mdns'
comment: 'Accept Multicast DNS packets from other hosts'
saddr: '{{ ferm__mdns_allow }}'
daddr: [ '224.0.0.251', 'ff02::fb' ]
accept_any: True
protocol: 'udp'
rule_state: '{{ ferm__mdns_state }}'
# Avahi is usually installed by default on workstations and laptops where
# it is useful. To manage Avahi on servers, you should enable the
# 'debops.avahi' Ansible role which will set up the same firewall rule.
- name: 'avahi'
type: 'accept'
dport: 'mdns'
saddr: '{{ avahi__allow | d([]) }}'
protocol: 'udp'
accept_any: True
rule_state: '{{ "present"
if ((ansible_local.nsswitch.conf | d() and
("mdns4_minimal" in q("flattened",
ansible_local.nsswitch.conf.hosts | d([])) or
"mdns_minimal" in q("flattened",
ansible_local.nsswitch.conf.hosts | d([])))) and
(ansible_local | d(True) and ansible_local.avahi | d(True) and
((ansible_local["avahi"] | d({})).enabled | d(True)) | bool))
else "absent" }}'
- name: 'jump_to_legacy_input_rules'
type: 'accept'
weight: '-10'
weight_class: 'reject'
comment: 'Jump to legacy firewall rules'
target: 'debops-legacy-input-rules'
rule_state: '{{ "present" if (ferm__include_legacy | bool) else "absent" }}'
- name: 'include_legacy_input_rules'
type: 'include'
weight_class: 'post-hook'
chain: 'debops-legacy-input-rules'
comment: 'Include legacy firewall rules'
include: '/etc/ferm/filter-input.d/'
rule_state: '{{ "present" if (ferm__include_legacy | bool) else "absent" }}'
- name: 'block_portscans'
type: 'recent'
weight: '85'
comment: 'Mark potential port scanners as bad guys'
recent_set_name: '{{ ferm__filter_recent_name }}'
rule_state: '{{ "present" if (ferm__mark_portscan | bool) else "absent" }}'
- name: 'reject_all'
type: 'reject'
- name: 'fail2ban-hook'
type: 'fail2ban'
comment: 'Reload fail2ban rules'
rule_state: '{{ "present" if (ferm__fail2ban | bool) else "absent" }}'
rules: |
@hook post "type fail2ban-server > /dev/null && (fail2ban-client ping > /dev/null && fail2ban-client reload > /dev/null || true) || true";
@hook flush "type fail2ban-server > /dev/null && (fail2ban-client ping > /dev/null && fail2ban-client reload > /dev/null || true) || true";
weight_class: 'post-hook'
# Remove obsolete forwarding rules
- name: 'forward_external_in'
rule_state: 'absent'
weight: '1'
weight_class: 'any-forward'
type: 'accept'
chain: 'FORWARD'
# Remove obsolete forwarding rules
- name: 'forward_external_out'
rule_state: 'absent'
weight: '2'
weight_class: 'any-forward'
type: 'accept'
chain: 'FORWARD'
# Remove obsolete forwarding rules
- name: 'forward_internal'
rule_state: 'absent'
weight: '3'
weight_class: 'any-forward'
type: 'accept'
chain: 'FORWARD'
- name: 'fix_bootpc_checksum'
type: 'custom'
rules: |
# Add checksums to BOOTP packets from virtual machines and containers.
# https://www.redhat.com/archives/libvir-list/2010-August/msg00035.html
@hook post "iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill";
rule_state: 'ignore'
- ferm__custom_files
Copy or install custom files needed by the firewall, usually scripts. The
syntax is the same as used by the copy
Ansible module.
ferm__custom_files: []
- ferm__group_custom_files
Copy or install custom files needed by the firewall host group configuration.
ferm__group_custom_files: []
- ferm__host_custom_files
Copy or install custom files needed by the firewall individual host configuration.
ferm__host_custom_files: []
- ferm__fail2ban
Enable or disable fail2ban integration. ferm will send fail2ban a reload command after its own configuration is reloaded. If fail2ban is not present or turned off, nothing will happen.
ferm__fail2ban: True