370 Configure pf

Use case

Use the role vbotka.freebsd.pf to configure pf.

Tree

shell> tree .
.
├── ansible.cfg
├── host_vars
│   └── iocage_04.yml
├── iocage.ini
└── pb.yml

Synopsis

  • The Ansible controller connects the iocage host iocage_04 at IP 10.1.0.29 configured in /etc/rc.conf

    cloned_interfaces="bridge0"
    create_args_bridge0="addm igb0"
    ifconfig_bridge0="inet 10.1.0.29/24"
    ifconfig_igb0="up -tso -vlanhwtso"
    
  • In the playbook pb.yml at iocage_04 configure:

    • blacklistd, fail2ban, and sshguard

    • nat

    • log all blocked

    • pass from localnet to any

Requirements

  • root privilege in the managed nodes.

Notes

TBD

Note

vbotka.freebsd.pf is the role pf in the collection vbotka.freebsd.
vbotka.freebsd_pf is the role freebsd_pf in the namespace vbotka.
Please make sure the versions are the same before you switch between them.

See also

ansible.cfg

[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false

[connection]
pipelining = true

Inventory iocage.ini

iocage_04 ansible_host=10.1.0.29

[iocage]
iocage_04

[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent

host_vars

host_vars/iocage_04.yml
pf_install: false
pf_blacklistd: true
pf_fail2ban: true
pf_sshguard: true

pf_enable: true
pf_blacklistd_enable: true
pf_fail2ban_enable: true
pf_sshguard_enable: true

pf_log_enable: true
pf_backup_conf: true

# /etc/pf.conf
pf_type: default2
pf_ext_if: bridge0
pf_log_all_blocked: log
pf_pass_icmp_types: [echoreq, unreach]
pf_pass_icmp6_types: [echoreq, unreach]
pf_local_net: 10.1.0.0/24

pf_macros:
  ext_if: "{{ pf_ext_if }}"
  localnet: "{{ pf_local_net }}"
  logall: "{{ pf_log_all_blocked }}"
  icmp_types: "{{ pf_pass_icmp_types }}"
  icmp6_types: "{{ pf_pass_icmp6_types }}"

# pf blocks
pf_options:
  - set skip on lo0
  - set block-policy return
  - set loginterface $ext_if

pf_tables:
  - table <sshabuse> persist

pf_normalization:
  - scrub in on $ext_if all fragment reassemble

pf_translation:
  - nat on $ext_if from $localnet to any -> ($ext_if)

pf_filtering:
  - antispoof for $ext_if
  - "{{ pf_anchors }}"
  - block $logall all
  - pass inet proto icmp icmp-type $icmp_types
  - pass inet6 proto icmp6 icmp6-type $icmp6_types
  - pass from { self, $localnet } to any keep state

# blacklistd
pf_blacklistd_conf_local:
  - {adr: ssh, type: stream, proto: '*', owner: '*', name: '*', nfail: '3', disable: 24h}
  - {adr: ftp, type: stream, proto: '*', owner: '*', name: '*', nfail: '3', disable: 24h}
  - {adr: smtp, type: stream, proto: '*', owner: '*', name: '*', nfail: '3', disable: 24h}
  - {adr: smtps, type: stream, proto: '*', owner: '*', name: '*', nfail: '3', disable: 24h}
  - {adr: submission, type: stream, proto: '*', owner: '*', name: '*', nfail: '3', disable: 24h}
  - {adr: '*', type: '*', proto: '*', owner: '*', name: '*', nfail: '3', disable: '60'}
pf_blacklistd_flags: '-r'
pf_blacklistd_rcconf:
  - {name: blacklistd_flags, value: "{{ pf_blacklistd_flags }}"}

Playbook pb.yml

- name: Test role vbotka.freebsd.pf
  hosts: iocage
  gather_facts: true

  roles:
    - vbotka.freebsd.pf

Playbook output - Install packages

(env) > ansible-playbook pb.yml -i iocage.ini -t pf_packages -e pf_install=true
PLAY [Test role vbotka.freebsd.pf] *********************************************

TASK [Gathering Facts] *********************************************************
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Packages: Install packages.] *************************
ok: [iocage_04]

PLAY RECAP *********************************************************************
iocage_04                  : ok=2    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   

Playbook output - Configure pf

Firewall starting and restarting breaks the ssh connections. See the handlers for details. As a consequence, both handlers starting and reloading don’t work properly and the ssh connection will stale. Therefore, let us first configure the rules

(env) > ansible-playbook pb.yml -i iocage.ini -e pf_enable=false
PLAY [Test role vbotka.freebsd.pf] *********************************************

TASK [Gathering Facts] *********************************************************
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Stat /etc/rc.d/blacklistd] ********
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Blacklistd: Backup /etc/blacklistd.conf.orig] ********
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Blacklistd: Configure /etc/blacklistd.conf] **********
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Stat /usr/local/etc/rc.d/fail2ban] ***
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Fail2ban: Configure /usr/local/etc/fail2ban/fail2ban.local] ***
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Fail2ban: Configure /usr/local/etc/fail2ban/jail.local] ***
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-sshguard: Stat /usr/local/etc/rc.d/sshguard] ***
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Configure sshguard.conf] *****************************
ok: [iocage_04] => (item={'key': 'BACKEND', 'value': '/usr/local/libexec/sshg-fw-pf'})
ok: [iocage_04] => (item={'key': 'WHITELIST_FILE', 'value': '/usr/local/etc/sshguard.whitelist'})

TASK [vbotka.freebsd.pf : Pfconf: Configure and validate rules using template default2-pf.conf.j2] ***
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Enable and start blacklistd.] *****
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Configure blacklistd.] ************
ok: [iocage_04] => (item={'name': 'blacklistd_flags', 'value': '-r'})

TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Enable and start fail2ban.] *********
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Configure fail2ban.] ****************
ok: [iocage_04] => (item={'name': 'fail2ban_flags', 'value': ''})

TASK [vbotka.freebsd.pf : Rcconf-sshguard: Enable and start sshguard.] *********
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-pf: Disable and stop pf.] *********************
changed: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-pflog: Enable and start pflog.] ***************
ok: [iocage_04]

RUNNING HANDLER [vbotka.freebsd.pf : Disable and stop pf] **********************
changed: [iocage_04]

PLAY RECAP *********************************************************************
iocage_04                  : ok=18   changed=2    unreachable=0    failed=0    skipped=39   rescued=0    ignored=0   

Playbook output - Enable pf

(env) > ansible-playbook pb.yml -i iocage.ini -t pf_rcconf_pf
PLAY [Test role vbotka.freebsd.pf] *********************************************

TASK [Gathering Facts] *********************************************************
ok: [iocage_04]

TASK [vbotka.freebsd.pf : Rcconf-pf: Enable and start pf.] *********************
changed: [iocage_04]

RUNNING HANDLER [vbotka.freebsd.pf : Start pf] *********************************
changed: [iocage_04]

PLAY RECAP *********************************************************************
iocage_04                  : ok=3    changed=2    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   

Result

pf status

(env) > ssh admin@10.1.0.29 sudo service pf status
Status: Disabled for 0 days 00:00:04          Debug: Urgent

Interface Stats for bridge0           IPv4             IPv6
  Bytes In                               0                0
  Bytes Out                              0                0
  Packets In
    Passed                          233387              987
    Blocked                            394                0
  Packets Out
    Passed                               0                0
    Blocked                         174948                0

State Table                          Total             Rate
  current entries                      164               
  searches                          426626       106656.5/s
  inserts                             8549         2137.2/s
  removals                            8385         2096.2/s
Counters
  match                              12205         3051.2/s
  bad-offset                             0            0.0/s
  fragment                               0            0.0/s
  short                                  0            0.0/s
  normalize                              0            0.0/s
  memory                                 0            0.0/s
  bad-timestamp                          0            0.0/s
  congestion                             0            0.0/s
  ip-option                            107           26.8/s
  proto-cksum                          872          218.0/s
  state-mismatch                         6            1.5/s
  state-insert                           0            0.0/s
  state-limit                            0            0.0/s
  src-limit                              0            0.0/s
  synproxy                               0            0.0/s
  map-failed                             0            0.0/s
  translate                              0            0.0/s

/etc/pf.conf

(env) > ssh admin@10.1.0.29 cat /etc/pf.conf
# Ansible managed
# template: default2-pf.conf.j2

# MACROS
ext_if = "bridge0"
localnet = "10.1.0.0/24"
logall = "log"
icmp_types = "{ echoreq, unreach }"
icmp6_types = "{ echoreq, unreach }"

# TABLES
table <sshabuse> persist

# OPTIONS
set skip on lo0
set block-policy return
set loginterface $ext_if

# NORMALIZATION
scrub in on $ext_if all fragment reassemble

# TRANSLATION
nat on $ext_if from $localnet to any -> ($ext_if)

# FILTERING
antispoof for $ext_if
anchor "blacklistd/*" in on $ext_if
anchor "f2b/*"
block $logall all
pass inet proto icmp icmp-type $icmp_types
pass inet6 proto icmp6 icmp6-type $icmp6_types
pass from { self, $localnet } to any keep state

# EOF