bimdata.ferm
Ansible Role Ferm
=========
This role sets up and configures Ferm.
Requirements
- This role works with Ansible version 2.9 or higher.
Role Variables
You can get more details about these options in the Ferm documentation.
Variables for Installation:
Variable Name | Default Value | Description |
---|---|---|
ferm_pkg_name | ferm | Name of the Ferm package in APT. |
ferm_svc_name | ferm | Name of the Ferm service to start or stop. |
Variables for General Configuration:
Variable Name | Default Value | Description |
---|---|---|
ferm_main_conf_file | /etc/ferm/ferm.conf | Path to the main Ferm configuration file. |
ferm_rules_path | /etc/ferm/ferm.d | Path to the directory for Ferm rules. |
The default rules are stored in the main configuration file, which loads all rules defined in the configuration directory. You can also define additional rules that are not managed by this role if ferm_delete_unknown_rules
is set to false
.
Variables for Rules Configuration:
Variable Name | Default Value | Description |
---|---|---|
ferm_delete_unknown_rulefiles | true | Remove the rules in ferm_rules_path not managed by this role. |
ferm_default_domains | ['ip', 'ip6'] | Default domain used when a rule does not specify one. |
ferm_default_table | filter | Default table used when a rule does not specify one. |
Variables for Rule Definitions:
Variable Name | Default Value | Description |
---|---|---|
ferm_input_policy | DROP | Default input policy for Ferm. |
ferm_output_policy | ACCEPT | Default output policy for Ferm. |
ferm_forward_policy | DROP | Default forward policy for Ferm. |
_ferm_rules | "{{ lookup('template', 'get_vars.j2', template_vars=dict(vartype='rule')) }}" | List of rules defined for Ferm. |
_ferm_vars | "{{ lookup('template', 'get_vars.j2', template_vars=dict(vartype='var')) }}" | List of variables defined for Ferm. |
_ferm_functions | "{{ lookup('template', 'get_vars.j2', template_vars=dict(vartype='function')) }}" | List of functions defined for Ferm. |
_ferm_hooks | "{{ lookup('template', 'get_vars.j2', template_vars=dict(vartype='hook')) }}" | List of hooks defined for Ferm. |
Do not change variables starting with an '_'. They use templates to build lists from other variables.
_ferm_rules
will gather variables whose names match this pattern:^ferm_.+_rule(s)?$
_ferm_vars
will gather variables whose names match this pattern:^ferm_.+_var(s)?$
_ferm_functions
will gather variables whose names match this pattern:^ferm_.+_function(s)?$
_ferm_hooks
will gather variables whose names match this pattern:^ferm_.+_hook(s)?$
Each variable that matches these patterns must be:
- a dictionary that defines one rule/variable/function/hook or
- a list of dictionaries that define one or more rules/variables/functions/hooks.
This allows you to define variables in different group_vars
and merge them for hosts in multiple groups without rewriting the full list.
Default Ruleset Variables:
- To configure the default ruleset for the INPUT table:
ferm_default_inputs: - "policy {{ ferm_input_policy }};" - interface lo ACCEPT; - "mod conntrack ctstate (RELATED ESTABLISHED) ACCEPT;"
- To configure the default ruleset for the OUTPUT table:
ferm_default_outputs: - "policy {{ ferm_output_policy }};" - interface lo ACCEPT; - "mod conntrack ctstate (RELATED ESTABLISHED) ACCEPT;"
- To configure the default ruleset for the FORWARD table:
ferm_default_forwards: []
Note: Debian 11 uses iptables-nft
by default, but Ferm does not support it. Debian 11 forces the use of iptables-legacy
.
Variable Name | Default Value | Description |
---|---|---|
ferm_iptables_path | /usr/sbin/iptables-legacy | Path to iptables-legacy . |
ferm_ip6tables_path | /usr/sbin/ip6tables-legacy | Path to ip6tables-legacy . |
ferm_arptables_path | /usr/sbin/arptables-legacy | Path to arptables-legacy . |
ferm_ebtables_path | /usr/sbin/ebtables-legacy | Path to ebtables-legacy . |
These variables are only relevant for Debian hosts running version 10 or higher. They will configure the system with the alternative
system to set the value of each legacy command.
Variable Examples
You can define a Ferm variable like this:
ferm_webports_var:
name: web_ports
content:
- 80
- 443
ferm_hosts_vars:
- name: web_front_addr
content:
- 172.29.10.100
- 2a01:baaf::100
Hook Examples
You can define a Ferm hook like this:
ferm_fail2ban_hooks:
- comment: Fail2ban hooks
content: post "type fail2ban-server > /dev/null && (fail2ban-client ping > /dev/null && fail2ban-client reload > /dev/null || true) || true";
- content: flush "type fail2ban-server > /dev/null && (fail2ban-client ping > /dev/null && fail2ban-client reload > /dev/null || true) || true";
Rule Definitions
You can define a rule in two ways:
ferm_web_rules:
- name: "web_server"
content:
- domains: ['ip'] # Can be omitted; ferm_default_domains will be used.
chains: ['INPUT'] # Can be omitted; ferm_default_table will be used.
rules:
- proto tcp dport ($web_ports) mod comment comment "web server" ACCEPT
Or using raw rules:
ferm_web_rules:
- name: "web_server"
raw_content: |
domain (ip) table filter {
chain (INPUT) {
proto tcp dport ($web_ports) mod comment comment "web server" ACCEPT;
}
}
Function Definitions
You can define a Ferm function like this:
ferm_dnat_function:
comment: "Easy DNAT (DNAT+filter rules)"
content: |
@def &EASY_DNAT($wan_ip, $proto, $port, $dest) = {
domain ip table nat chain PREROUTING daddr $wan_ip proto $proto dport $port DNAT to @ipfilter($dest);
domain (ip ip6) table filter chain FORWARD outerface $dmz_iface daddr $dest proto $proto dport $port ACCEPT;
}
Then create a rule that uses it:
ferm_dnat_rules:
- name: "80-dnat-rules"
raw_content: |
# HTTP(S) web_front
&EASY_DNAT($main_public_ip, tcp, (80 443), $web_front_addr);
Docker Example
Docker may want to manage its own iptables rules. Here’s how you can handle it:
# No rules can be defined in FORWARD before the Docker rules
ferm_default_forwards: []
# Keep Docker rules
ferm_docker_preserve_rules:
- name: 99-docker-users.ferm
content:
- domains: ['ip']
chains: ['DOCKER-USER']
rules:
- "RETURN;"
- name: 00-docker-preserve.ferm
content:
- domains: ['ip']
chains:
- DOCKER
- DOCKER-INGRESS
- DOCKER-ISOLATION-STAGE-1
- DOCKER-ISOLATION-STAGE-2
- FORWARD
rules:
- "@preserve;"
- domains: ['ip']
table: nat
chains:
- DOCKER
- DOCKER-INGRESS
- PREROUTING
- OUTPUT
- POSTROUTING
rules:
- "@preserve;"
@preserve is a specific command used by Ferm to save previous rules.
Dependencies
None
Example Playbook
In group_vars/all.yml
:
ferm_webports_var:
name: web_ports
content:
- 80
- 443
In group_vars/web.yml
:
ferm_web_rules:
- name: "web_server"
content:
- chains: ['INPUT']
rules:
- proto tcp dport ($web_ports) mod comment comment "web server" ACCEPT
In group_vars/router.yml
:
ferm_interface_vars:
- name: wan_iface
content: ['eth0']
- name: dmz_iface
content: ['eth1']
- name: lan_iface
content:
- eth2
- eth3
ferm_ips_vars:
- name: main_public_ip
content: ['1.2.3.4']
- name: web_front_addr
content:
- 10.0.0.100
- 2a01:baaf::100
ferm_dnat_function:
comment: "Easy DNAT (DNAT+filter rules)"
content: |
@def &EASY_DNAT($wan_ip, $proto, $port, $dest) = {
domain ip table nat chain PREROUTING daddr $wan_ip proto $proto dport $port DNAT to @ipfilter($dest);
domain (ip ip6) table filter chain FORWARD outerface $dmz_iface daddr $dest proto $proto dport $port ACCEPT;
}
ferm_dnat_rules:
- name: "80-dnat-rules"
raw_content: |
# HTTP(S) web_front
&EASY_DNAT($main_public_ip, tcp, $web_ports, $web_front_addr);
In playbook.yml
:
- hosts: all
gather_facts: True
become: yes
roles:
- bimdata.ferm
License
BSD
Author Information
ansible-galaxy install bimdata.ferm