DEBOPS.FERM(5)

NAME
debops.ferm - Manage iptables firewall using ferm

SYNOPSIS

debops run service/ferm [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

debops run site --tags role::ferm [playbook] ... [--limit group,host,...] [--diff] [--check] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

debops run site --skip-tags skip::ferm [playbook] ... [--limit group,host,...] [--diff] [--check] [--tags-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

ferm <http://ferm.foo-projects.org/> is a wrapper around the iptables and the ip6tables commands which lets you manage host firewalls in an easy and Ansible-friendly way. This role can be used to setup firewall rules directly from the inventory, or it can be used as a dependency by other roles to setup firewall rules for other services.

GETTING STARTED

  Example inventory

The debops.ferm role is part of the default DebOps playbook an run on all hosts which are part of the [debops_all_hosts] group. To use this role with DebOps it's therefore enough to add your host to the mentioned host group (which most likely it is already):

[debops_all_hosts]
hostname

  Example playbook

Here's an example playbook which uses the debops.ferm role:

---
- name: Manage firewall using ferm
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_all_hosts', 'debops_service_ferm' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  roles:
    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]

  Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::ferm
    Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.

role::ferm:custom_files
    Copy custom ferm configuration files to remote hosts.

role::ferm:rules
    Run tasks to add or remove ferm rules and configure IP packet forwarding.

DEFAULT VARIABLE DETAILS

Some of debops.ferm default variables have more extensive configuration than simple strings or lists, here you can find documentation and examples for them.

  ferm__rules

The ferm__*_rules variables are YAML lists which define what firewall rules are configured on a host. The rules are combined together in the ferm__combined_rules variable which defines the order of the rule variables and therefore how they will affect each other.

Each entry in the ferm__*_rules lists is a YAML dictionary. The entry needs to have the name parameter that specifies the rule name, otherwise it will be skipped.

The result is stored as ferm__parsed_rules variable. This order allows modification of the default rules as well as rules defined by other Ansible roles using Ansible inventory variables.

The rules are stored in the /etc/ferm/rules.d/ directory and the filename format is:

/etc/ferm/rules.d/<weight>_rule_<name>.conf

The rule "weight" is determined by a given rule type which can be overridden if needed, see the type, weight and weight_class parameters for more details.

Each rule defined in a dictionary uses specific parameters. The parameters described here are general ones, mostly usable on the main "level" and are related to management of rule files. The parameters related to specific ferm rules are described in Firewall Rule Definitions documentation.

name
    Name of the firewall rule to configure. An example rule definition:

    ferm__rules:
      - name: 'accept_all_connections'
        type: 'accept'
        accept_any: True

rules
    Either a string or a YAML text block that contains raw ferm configuration options, or a list of YAML dictionaries which specify firewall rules. If this parameter is not specified, role will try and generate rules automatically based on other parameters specified on the "first level" of a given rule definition. Most of the other parameters can be specified on the "second level" rules and will apply to a given rule in the list.

    Example custom rule definition that restarts nginx after firewall is modified:

    ferm__rules:
      - name: 'restart_nginx':
        type: 'post-hook'
        rules: '@hook post "type nginx > /dev/null && systemctl restart nginx || true";'

    Example list of rule definitions which will open access to different service ports; rules will be present in the same file:

    ferm__rules:
      - name: 'allow_http_https'
        rules:
          - dport: 'http'
            accept_any: True
          - dport: 'https'
            accept_any: True

rule_state
    Optional. Specify the state of the firewall rule file, or one of the rules included in that file. Supported states:

•   present: default. The rule file will be created if it doesn't exist, a rule will be present in the file.

•   absent: The rule file will be removed, a rule in the file will not be generated.

•   ignore: the role will not change the current state of the configuration file. This value does not have an effect on the rules inside the file.

comment
    Optional. Add a comment in the rule configuration file, either as a string or as a YAML text block.

template
    Optional. Name of the template to use to generate the firewall rule file. Currently only one template is available, rule so this option is not useful yet.

type
    Optional. Specify the rule type as a name, for example accept or reject. Different rule types can use different rule parameters, the rule type also affects the "weight" used to order the configuration files. Weight of the different rules is specified in the ferm__default_weight_map variable and can be overridden using the ferm__weight_map variable.

    List of known rule types can be found in the Firewall Rule Definitions documentation.

weight_class
    Optional. Override the rule type with another type, to change the sort order of the configuration files. This parameter does not affect the ferm configuration template, only the resulting filename.

weight
    Optional. Additional positive or negative number (for example 2 or -2) which will be added to the rule weight affecting the file sorting order.

  ferm_input_list

This is a set of legacy debops.ferm variables, kept to allow older roles to be usable with new variables. You should use the ferm__*_rules variables instead in new configuration, the legacy variables will be removed at some point.

List of ferm INPUT rules that should be present or absent in the firewall rule set. The same format is also used for ferm_input_group_list, ferm_input_host_list and ferm_input_dependent_list. Each rule is defined as a YAML dict with the following keys:

type
    Name of template file to use, required. Format: <type>.conf.j2

dport
    List of destination ports to manage, required.

name
    Optional. Custom name used in the generated rule filename

weight
    Optional. Helps with file sorting in rule directory

filename
    Optional. Custom filename instead of a generated one

rule_state
    Optional. State of the rule. Defaults to present. Possible values: present or absent

    Depending on the chosen type, many additional variables are supported. Please check the template files located in the templates/etc/ferm/ferm.d directory.

FIREWALL RULE DEFINITIONS

Firewall configuration in debops.ferm is done through a flexible definition of rules. There are a number of variables which are used to reference a set of default rules and can be extended by user defined rules. Here a description of the involved configurations should be given so that everyone can customize the ruleset according to individual requirements.

  Default rules

By default debops.ferm configures a number of rules as soon as a host is part of the [debops_all_hosts] Ansible host group. The rules created by default are defined in defaults/main.yml and activated by being listed in ferm__default_rules. They consist of basic rules for setting the iptables default policies, restricting extensive connection attempts, logging and more.

In case a firewall is not required or preferred this behaviour can be disabled by setting ferm__enabled to False in the inventory.

  Custom rules

A custom rule can be enabled by adding a rule definition to one of the predefined rule lists (ferm__rules, ferm__group_rules, ferm__host_rules or ferm__dependent_rules) in the Ansible inventory. Each rule has to be defined as a YAML dict using some of the following keys:

domain
    Optional. iptables domain used for the firewall rule. Possible values: ip, ip6. Defaults to ferm__domains.

table
    Optional. iptables table to which the rule is added or from which it is removed. Defaults to filter.

chain
    Optional. iptables chain to which the rule is added or from which it is removed. Defaults to INPUT.

by_role
    Optional. Name of the Ansible role in the format ROLE_OWNER.ROLE_NAME which is responsible for the rule. This will be included as a comment in the generated rule file.

    Depending on the chosen type, many additional variables are supported. Please check the individual rule type description below.

  Rule types

There exist a number of predefined rule types for generating firewall rules through ferm. Following a list of the available rule types which can be used to create custom rules.

  The 'accept' type

This rule type can be used to create rules that match interfaces, ports, remote IP addresses/subnets and can accept the packets, reject, or redirect to a different chain. The following type-specific YAML keys are supported:

accept_any
    Optional. Match all source addresses by default. Possible values: True or False. Defaults to True. If this option is set to False and item.target is set to REJECT all traffic is blocked by default. As soon as item.saddr is not empty, this configuration doesn't matter anymore.

daddr
    Optional. List of destination IP addresses or networks to which the rule is applied.

dport
    Optional. List of destination ports to which the rule is applied.

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

interface
    Optional. List of network interfaces for incoming packets to which the rule is applied.

interface_present
    Optional. Same as item.interface but first check if specified network interfaces exists before adding the firewall rules.

multiport
    Optional. Use iptables multiport extension. Possible values: True or False. Defaults to False.

outerface
    Optional. List of network interfaces for outgoing packets to which the rule is applied.

outerface_present
    Optional. Same as item.outerface but first check if specified network interface exists before adding the firewall rule.

protocol
    Optional. Network protocol to which the rule is applied.

protocol_syn
    Optional. Match TCP packet with only the SYN flag set. Possible values True or False. If set to False it will match all other packets except the ones with only the SYN flag set. Defaults to unset.

realgoto
    Optional. After packet match jump to custom chain. See ferm realgoto <http://ferm.foo-projects.org/download/2.1/ferm.html#realgoto_custom_chain_name> for more details.

reject_with
    Optional. Define reject message being sent when the rule item.target is set to REJECT. Defaults to icmp-admin-prohibited.

saddr
    Optional. List of source IP addresses or networks to which this rule is applied.

sport
    Optional. List of source ports to which the rule is applied.

state
    Optional. Connection state which should be matched. Possible values: INVALID, ESTABLISHED, NEW, RELATED, UNTRACKED or comma-separated combination thereof.

subchain
    Optional. Subchain name. If more than 3 addresses are listed in target.saddr move resulting iptables rules into a separate subchain with the given name. See ferm subchain <http://ferm.foo-projects.org/download/2.1/ferm.html#_subchain> for more details.

target
    Optional. iptables jump target. Possible values: ACCEPT, DROP, REJECT, RETURN, NOP or a custom target. Defaults to ACCEPT.

  The 'ansible_controller' type

Similar to the accept type but defaults to the SSH target port and sets the source address to the host running Ansible if not overwritten through the item.ansible_controllers key. The following type-specific YAML keys are supported:

ansible_controllers
    Optional. List of source IP address which are added to item.saddr. Overwrites auto-detection of the Ansible controller address.

daddr
    Optional. List of destination IP addresses or networks to which the rule is applied.

dport
    Optional. List of destination ports to which the rule is applied. Defaults to ssh.

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

interface
    Optional. List of network interfaces for incoming packets to which the rule is applied.

multiport
    Optional. Use iptables multiport <http://ipset.netfilter.org/iptables-extensions.man.html#lbBM> extension. Possible values: True or False. Defaults to False.

outerface
    Optional. List of network interfaces for outgoing packets to which the rule is applied.

protocol
    Optional. Network protocol to which the rule is applied. Defaults to tcp.

protocol_syn
    Optional. Match TCP packet with only the SYN flag set. Possible values True or False. If set to False it will match all other packets except the ones with only the SYN flag set. Defaults to unset.

realgoto
    Optional. After packet match jump to custom chain. See ferm realgoto <http://ferm.foo-projects.org/download/2.1/ferm.html#realgoto_custom_chain_name> for more details.

reject_with
    Optional. Define reject message being sent when the rule item.target is set to REJECT. Defaults to icmp-admin-prohibited.

saddr
    Optional. List of source IP addresses or networks to which this rule is applied.

sport
    Optional. List of source ports to which the rule is applied.

state
    Optional. Connection state which should be matched. Possible values: INVALID, ESTABLISHED, NEW, RELATED, UNTRACKED or comma-separated combination thereof.

subchain
    Optional. Subchain name. If more than 3 addresses are listed in target.saddr move resulting iptables rules into a separate subchain with the given name. See ferm subchain <http://ferm.foo-projects.org/download/2.1/ferm.html#_subchain> for more details.

target
    Optional. iptables jump target. Possible values: ACCEPT, DROP, REJECT, RETURN, NOP or a custom target. Defaults to ACCEPT.

  The 'connection_tracking' type

This type is used to enable connection tracking using the iptables conntrack <http://ipset.netfilter.org/iptables-extensions.man.html#lbAO> or iptables state <http://ipset.netfilter.org/iptables-extensions.man.html#lbCC> extension. The following type-specific YAML keys are supported:

tracking_active_target
    Optional. iptables jump target for valid connections. Defaults to ACCEPT.

tracking_invalid_target
    Optional. iptables jump target for invalid connections. Defaults to DROP.

tracking_module
    Optional. iptables module used for connection tracking. Possible values: state or conntrack. Defaults to conntrack.

interface
    Optional. List of network interfaces for incoming packets to which the rule is applied.

outerface
    Optional. List of network interfaces for outgoing packets to which the rule is applied.

interface_not
    Optional. List of network interfaces for incoming packets which are excluded from the rule.

outerface_not
    Optional. List of network interfaces for outgoing packets which are excluded from the rule.

  The 'custom' type

The type used to define custom ferm rules. The following additional YAML keys are supported:

rules
    ferm rule definition, required.

by_role
    Optional. Add comment to generated ferm rule definition file that rule is defined in the given Ansible role.

    This template is used among others in a debops.libvirtd custom ferm rule.

  The 'default_policy' type

This type is used to define iptables default policies. The following type-specific YAML keys are supported:

policy
    iptables chain policy, required.

  The 'dmz' type

This type can be used to enable connection forwarding to another host. If item.port is not specified, all traffic is forwarded. The following type-specific YAML keys are supported:

multiport
    Optional. Use iptables multiport <http://ipset.netfilter.org/iptables-extensions.man.html#lbBM> extension. Possible values: True or False. Defaults to False.

interface
    Optional. List of public network interfaces which accept connections. At least one of interface or public_ip is required.

public_ip
    Optional. IPv4 address on the public network which accepts connections. At least one of interface or public_ip is required. Only 1 IP address should be used at a time.

private_ip
    IPv4 address of the host on the internal network, required. Only 1 IP address should be used at a time.

protocol(s)
    Optional. List of protocols to forward. Defaults to tcp.

port(s)
    Optional. List of ports to forward.

dport
    Optional. Destination port to forward to. Only needs to be specified if internal destination port is different from the original destination port.

snat_ip
    Optional. IP address for source address translation. If set the source IP is rewritten to this address. This is typically the IP address of the firewall host on the internal network. This is useful if traffic from the private_ip would otherwise not be routed back to the firewall host.

  The 'hashlimit' type

This type is used to define rate limit rules using the iptables hashlimit <http://ipset.netfilter.org/iptables-extensions.man.html#lbAY> extension. The following type-specific YAML keys are supported:

daddr
    Optional. List of destination IP addresses or networks to which the rule is applied.

dport
    Optional. List of destination ports to which the rule is applied.

hashlimit_burst
    Optional. Number of packets to match within the expiration time. Defaults to 5.

hashlimit_expire
    Optional. Expiration time of hash entries in seconds. Defaults to 1.8.

hashlimit_target
    Optional. Jump target used when packet matches the hashlimit rule which means that the rate limit is not reached yet. Defaults to RETURN.

hashlimit_mode
    Optional. Options to take into consideration when associating packet streams. Possible values: srcip, srcport, dstip, dstport or a comma-separated list thereof. Defaults to srcip.

interface
    Optional. List of network interfaces for incoming packets to which the rule is applied.

interface_present
    Optional. Same as item.interface but first check if specified network interfaces exists before adding the firewall rules.

outerface
    Optional. List of network interfaces for outgoing packets to which the rule is applied.

outerface_present
    Optional. Same as item.outerface but first check if specified network interface exists before adding the firewall rule.

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

log Optional. Write rate limit hits to syslog. Possible values: True and False. Defaults to True.

protocol
    Optional. Network protocol to which the rule is applied.

protocol_syn
    Optional. Match TCP packet with only the SYN flag set. Possible values True or False. If set to False it will match all other packets except the ones with only the SYN flag set. Defaults to unset.

reject_with
    Optional. Define reject message being sent when the rule item.target is set to REJECT. Defaults to icmp-admin-prohibited.

state
    Optional. Connection state which should be matched. Possible values: INVALID, ESTABLISHED, NEW, RELATED, UNTRACKED or comma-separated combination thereof.

subchain
    Optional. Subchain name. Move resulting iptables rules into a separate subchain with the given name. See ferm subchain <http://ferm.foo-projects.org/download/2.1/ferm.html#_subchain> for more details.

target
    Optional. iptables jump target in case the rate limit is reached. Defaults to REJECT.

  The 'include' type

This type can be used to include custom ferm configuration files. The following type-specific YAML keys are supported:

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

  The 'log' type

This type can be used to specify logging rules using the iptables log <http://ipset.netfilter.org/iptables-extensions.man.html#lbDD> extension. The following type-specific YAML keys are supported:

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

log_burst
    Optional. Burst limit of packets being logged. Defaults to ferm__log_burst.

log_ip_options
    Optional. Log IP options of packet. Possible values: True or False. Defaults to True.

log_level
    Optional. Log level for firewall messages. Possible values are: emerg, alert, crit, error, warning, notice, info or debug. Defaults to warning.

log_limit
    Optional. Rate limit of packets being logged. Defaults to ferm__log_limit.

log_prefix
    Optional. Prefix (up to 29 characters) for firewall log messages. Defaults to iptables-log:

log_target
    Optional. Select how iptables performs logging. Possible values: LOG, ULOG, NFLOG. Defaults to LOG.

log_tcp_options
    Optional. Log TCP options of packet. Possible values: True or False. Defaults to False.

log_tcp_sequence
    Optional. Log TCP sequence of packet. Possible values: True or False. Defaults to False.

realgoto
    Optional. After packet match jump to custom chain. See ferm realgoto <http://ferm.foo-projects.org/download/2.1/ferm.html#realgoto_custom_chain_name> for more details.

reject_with
    Optional. Define reject message being sent when the rule item.target is set to REJECT. Defaults to icmp-admin-prohibited.

target
    Optional. iptables jump target for logged packets.

  The 'recent' type

This type can be used to track connections and respond accordingly by using the iptables recent <http://ipset.netfilter.org/iptables-extensions.man.html#lbBW> extension. The following type-specific YAML keys are supported:

dport
    Optional. List of destination ports to which the rule is applied.

include
    Optional. Custom ferm configuration file to include. See ferm include <http://ferm.foo-projects.org/download/2.1/ferm.html#includes> for more details.

multiport
    Optional. Use iptables multiport <http://ipset.netfilter.org/iptables-extensions.man.html#lbBM> extension. Possible values: True or False. Defaults to False.

protocol
    Optional. Network protocol to which the rule is applied.

protocol_syn
    Optional. Match TCP packet with only the SYN flag set. Possible values True or False. If set to False it will match all other packets except the ones with only the SYN flag set. Defaults to unset.

recent_hitcount
    Optional. Must be used in combination with item.recent_update. Match if address is in the list and at least the given number of packets were received so far.

recent_log
    Optional. Log packets matching the rule. Possible values: True or False. Defaults to ferm__log. If this is set to True ferm__log must be enabled too for the packet to be logged.

recent_name
    Optional. Name of the list. Defaults to DEFAULT.

recent_remove
    Optional. Remove address from the list. Possible values: True or False. Defaults to False. Mutually exclusive with item.recent_update.

recent_seconds
    Optional. Must be used in combination with item.recent_update. Match if address is in the list and was last seen within the given number of seconds.

recent_set_name
    Optional. Add the source address of a matching packet to the given list. This must correspond with item.recent_name of a second rule which would potentially act on the packet, e. g. reject it.

recent_target
    Optional. iptables jump target when packet has hit the recent list. Possible values: ACCEPT, DROP, REJECT, RETURN, NOP or a custom target. Defaults to NOP.

recent_update
    Optional. Update "last-seen" timestamp. Possible values: True or False. Defaults to False. Mutually exclusive with item.recent_remove.

reject_with
    Optional. Define reject message being sent when the rule item.target is set to REJECT. Defaults to icmp-admin-prohibited.

state
    Optional. Connection state which should be matched. Possible values: INVALID, ESTABLISHED, NEW, RELATED, UNTRACKED or comma-separated combination thereof.

subchain
    Optional. Subchain name. Move resulting iptables rules into a separate subchain with the name given. See ferm subchain <http://ferm.foo-projects.org/download/2.1/ferm.html#_subchain> for more details.

    When using the recent type make sure to always define two rules:

•   One for matching the packet against the address list using the item.recent_update feature. If this filter matches you likely want to set the item.recent_target to DROP or REJECT.

•   To clear the source address from the list again in case the connection restrictions are not met, add a second role using item.recent_remove.

  The 'reject' type

This type is used to reject all traffic. It can be added for example as a final rule in a custom chain.

  Legacy rules

Legacy rules are the (old) deprecated way to configure firewall rules using a simpler less flexible syntax than described above. As support for these is likely going to be removed in the future, they shouldn't be used anymore.

Support for legacy rules is still enabled by default. However, they are stored in a separate iptables INPUT chain called debops-legacy-input-rules. In case you haven't defined any legacy rules and none of the DebOps roles you are using are still depending on it, disable support completely by setting ferm__include_legacy to False which will avoid the additional chain from being created.

If you're not sure if you still have legacy rules defined, look for variable names with only on '_' after the ferm prefix (e. g. ferm_input_list and ferm_input_dependent_list).

GUIDES AND EXAMPLES

  Configuring an Internet Gateway

An Internet gateway is a host which is managing the access of a private (internal) network to the (external) Internet. When running Linux as a gateway host the correct setup of the required iptables rules is crucial. While there exist dedicated Linux distributions for this task such as OpenWRT or IPFire, it's also possible to use a regular Debian GNU/Linux system and configure it through DebOps. Here a short overview about the basic steps for a simple gateway configuration is given.

The gateway host should have at least two network interfaces connected to the respective networks. In this guide the interface named eth0 will be used as external untrusted interface and eth1 will be used as internal trusted interface.

To follow this guide you should be familiar with DebOps and the way to configure related Ansible variables. If you're not, you may first want to read the Getting Started guide.

  Packet Forwarding

The configuration of packet forwarding is done on a per-interface basis. You can use the debops.ferm and debops.ifupdown Ansible roles to configure the respective firewall rules and kernel parameters, or use the debops.ifupdown role to configure network interfaces, which will include packet forwarding rules when necessary, for example for all bridge interfaces.

In case every connection traversing the network boundaries should be explicitly defined, set an empty rule list here:

ferm__rules_forward: []

On the other hand it might be useful to start with a less restrictive forwarding rule list which allows all outgoing traffic:

ferm__rules_forward:
  - chain: 'FORWARD'
    type: 'accept'
    outerface_present: '{{ ferm__external_interfaces }}'
    weight: '10'
    role: 'forward'
    role_weight: '20'
    name: 'external_out'
    comment: 'Forward outgoing traffic to other hosts'
    rule_state: '{{ "present" if (
                      (ferm__forward | d(ferm_forward) | bool) or
                      (ansible_local | d() and ansible_local.ferm | d() and
                       ansible_local.ferm.forward | bool))
                     else "absent" }}'

Once a packet was accepted by the firewall all related packets belonging to the same connection are accepted too. This is defined in the connection_tracking rule which is loaded as part of the ferm__default_rules rule list.

  Port Forwarding

If the forward rules above are properly implemented, all external access to a host connected to the internal network is blocked. Still it might be necessary to allow external access to a specific internally hosted service such as a Web server. This can be done by forwarding a port or port range from the gateway's external interface to an internal host. Technically this is called DNAT (Destination Network Address Translation), where the original destination address of a network packet is rewritten to the internal host address.

•   To forward the HTTP port from the gateway to the internal host, a rule such as the following is required:

    ferm__host_rules:
      - type: 'dmz'
        name: 'http-forward'
        domain: [ 'ip' ]
        public_ip: '{{ ansible_eth0.ipv4.address }}'
        private_ip: '{{ lookup("dig", "web.internal.example.com") }}'
        protocol: 'tcp'
        ports: [ 80 ]

  Note

The 'dmz' type rule template won't modify the source address of a forwarded packet by default. This means that the original source address can still be identified at the internal receiver, however the route leading back to the source address must traverse the gateway again in order to successfully initiate connection tracking.

The optional snat_ip parameter can be used to configure source address translation (SNAT).

  INPUT Rules for Services running on the Gateway Host

As an Internet gateway is usually a device which is running 24/7 and being a core part of the network infrastructure, people might want to run additional services on this host. In case these services are also managed by DebOps the respective Ansible roles will ensure that the required firewall rules are added to the ferm__dependent_rules rule list. By default access from all networks is allowed which is not always desired. Below it will be shown how this can be restricted to the internal network attached to eth1.

Example: dnsmasq

The debops.dnsmasq <https://github.com/debops/ansible-dnsmasq> role is providing DNS and DHCP services. Obviously access to these services should only be allowed from the internal network.

•   Define the upstream (external) interface where access should be blocked:

    dnsmasq_upstream_interfaces: [ 'eth0' ]

•   Define the internal interface where the DNS and DHCP services will be provided. This setting would automatically define the necessary iptables INPUT rules for those services to be accessible from the internal network:

    dnsmasq_interfaces:
      - interface: 'eth1'
        name: 'gateway'
        dhcp_range_start: '10'
        dhcp_range_end: '-10'
        dhcp_lease: '24h'

    Refer to the debops.dnsmasq <https://github.com/debops/ansible-dnsmasq> role for details.

    Example: nginx

    Most other DebOps roles which manage applications are able to restrict access through the firewall based on source IP addresses and network ranges. This is typically done by defining a corresponding service_allow variable. In case of debops.nginx <https://github.com/debops/ansible-nginx> this configuration would look as following:

    nginx_allow: [ '{{ ansible_eth1.ipv4.network }}/{{ ("0.0.0.0/" + ansible_eth1.ipv4.netmask) | ansible.utils.ipaddr("prefix") }}' ]

    This will restrict access to the HTTP service running on the gateway host to the internal IPv4 network which is automatically defined using the ansible_eth1 host fact.

  Restrict Outgoing Traffic

Many iptables setups are rather lax when it's about restricting outgoing traffic. By default DebOps will set the iptables OUTPUT policy to ACCEPT which will permit every outgoing connection attempt. However, it is always a good idea to also limit the connections which can be made from within a host, especially if the host is directly connected to the Internet.

Unfortunately debops.ferm doesn't provide any predefined rule lists to restrict outgoing traffic, therefore they need to be custom defined entirely. On the other hand this will be a good example for defining rule lists also for any other purpose.

•   First create an Ansible list with an individually chosen name which will hold the custom output rules. For every outgoing connection which should be allowed to the internal or external network a rule needs to be added. Every template described in the Rule types chapter can be used for the custom rules. The definition below is just a minimal example to show the procedure:

    ferm__custom_rules_filter_output:
      - type: 'accept'
        chain: 'OUTPUT'
        weight: '00'
        weight_class: 'loopback'
        comment: 'Allow connections to loopback'
        name: 'loopback_out'
        outerface: 'lo'
        target: 'ACCEPT'
      - type: 'accept'
        chain: 'OUTPUT'
        weight: '50'
        weight_class: 'any-service'
        comment: 'Allow connections to internal network'
        name: 'internal_out'
        outerface: 'eth1'
        target: 'ACCEPT'
      - type: 'accept'
        chain: 'OUTPUT'
        weight: '03'
        weight_class: 'filter-icmp'
        comment: 'Allow outgoing ICMP requests'
        name: 'icmp_out'
        protocol: 'icmp'
        outerface: 'eth0'
        target: 'ACCEPT'
      - type: 'accept'
        chain: 'OUTPUT'
        weight: '32'
        comment: 'Allow outgoing DNS traffic'
        name: 'dns_out'
        protocol: 'udp'
        dport: 53
        outerface: 'eth0'
        target: 'ACCEPT'
      - type: 'reject'
        chain: 'OUTPUT'
        weight_class: 'any-reject'
        name: 'reject_out'
        comment: 'Reject remaining outgoing traffic'

    The last rule is using The 'reject' type which will reject every packet not explicitly allowed. This will make it easier to figure out missing rules than if the packets would simply be dropped.

•   Reference the custom rule list in one of the main rule list variables ferm__rules, ferm__group_rules or ferm__host_rules. E.g.:

    ferm__host_rules: '{{ ferm__custom_rules_filter_output }}'

    If there are multiple custom rule lists, they can be concatenated with +.

•   Finally set the iptables OUTPUT policy to DROP:

    ferm__default_policy_output: 'DROP'

  Block Port Scans

To block port scans there is a predefined rule block_portscans which is not enabled by default. It will remember source addresses which try to reach closed ports and completely blocks access from those addresses for a while. This behaviour can be enabled by setting ferm__mark_portscan:

ferm__mark_portscan: True

To make sure management access to the gateway is not suddenly blocked by the mentioned rule list, trusted addresses must be whitelisted. For example when trying out DebOps in a Vagrant environment the host running vagrant` should be added to the ferm__ansible_controllers variable. Otherwise vagrant ssh might suddenly be blocked by the portscan rule in case a machine port was mistakenly accessed where no service was running:

ferm__ansible_controllers: [ '192.168.121.1' ]

The host running DebOps doesn't explicitly need to be added here as it is automatically being whitelisted.

AUTHOR
Maciej Delmanowski, Robin Schneider, Reto Gantenbein

COPYRIGHT
2014-2024, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others