440 Configure DHCP¶
Use case¶
Use the role vbotka.freebsd.dhcp to configure DHCP. Use the role vbotka.freebsd.pf to configure pf.
Tree¶
shell> tree .
.
├── ansible.cfg
├── host_vars
│ └── iocage_05
│ ├── dhcp.yml
│ └── pf.yml
├── iocage.ini
├── pb-dhcp.yml
└── pb-pf.yml
Synopsis¶
The Ansible controller connects the iocage host
iocage_05at the wlan interface configured in/etc/rc.confgateway_enable="YES" defaultrouter="10.10.0.1" cloned_interfaces="bridge0" ifconfig_bridge0="inet 10.1.0.1/24" wlans_iwm0="wlan0" create_args_wlan0="country US" ifconfig_wlan0="WPA SYNCDHCP"
In the playbook
pb-dhcp.ymlatiocage_05configure:subnet 10.1.0.0/24
range 100-200
dhcpd_ifaces=”bridge0”
In the playbook
pb-pf.ymlatiocage_05configure:blacklistd, fail2ban, and sshguard
nat
log all blocked
allow SSH from the external network
pass from localnet and jails’ vnet to any
Requirements¶
root privilege in the managed nodes.
Notes¶
TBD
Note
See also
FreeBSD Handbook Installing and Configuring a DHCP Server
FreeBSD Handbook Firewalls
FreeBSD Forum pf and bridge
Dell XPS 13 9365 15.0-RELEASE dmesg used as
iocage_05
ansible.cfg¶
[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
[connection]
pipelining = true
Inventory iocage.ini¶
iocage_05 ansible_host=handy
[iocage]
iocage_05
[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent
host_vars¶
---
bsd_dhcpd_install: false
bsd_dhcpd_enable: true
bsd_dhcpd_debug: false
bsd_dhcpd_sanity: true
bsd_dhcpd_sanity_fatal: true
bsd_dhcpd_backup_conf: true
# rc.conf
bsd_dhcpd_rcconf:
- name: dhcpd_ifaces
value: bridge0
# Template
bsd_dhcpd_template: dhcpd.conf-minimal.j2
# Gobal
bsd_dhcpd_domain_name: g3.example.com
bsd_dhcpd_domain_name_servers: [8.8.8.8, 8.8.4.4]
bsd_dhcpd_default_lease_time: 600
bsd_dhcpd_max_lease_time: 7200
# Primary server
bsd_dhcpd_authoritative: true
# Subnet
bsd_dhcpd_subnet: 10.1.0
bsd_dhcpd_netmask: 255.255.255.0
bsd_dhcpd_subnet_from: 100
bsd_dhcpd_subnet_to: 200
bsd_dhcpd_routers: [10.1.0.1]
bsd_dhcpd_subnet_broadcast: 255
# EOF
---
pf_install: false
pf_enable: true
pf_blacklistd: true
pf_fail2ban: true
pf_relayd: false
pf_sshguard: true
pf_blacklistd_enable: true
pf_fail2ban_enable: true
pf_sshguard_enable: true
pf_debug: false
pf_backup_conf: true
pfconf_only: false
pfconf_validate: true
# /etc/pf.conf
pf_type: default2
pf_log_enable: true
pf_ext_if: wlan0
pf_int_if: bridge0
pf_log_all_blocked: log
pf_pass_icmp_types: [echoreq, unreach]
pf_pass_icmp6_types: [echoreq, unreach]
pf_local_net: 10.10.1.0/24
pf_local_vnet: 10.1.0.0/24
pf_tcp_services: [ssh]
pf_macros:
ext_if: "{{ pf_ext_if }}"
int_if: "{{ pf_int_if }}"
localnet: "{{ pf_local_net }}"
localvnet: "{{ pf_local_vnet }}"
logall: "{{ pf_log_all_blocked }}"
icmp_types: "{{ pf_pass_icmp_types }}"
icmp6_types: "{{ pf_pass_icmp6_types }}"
tcp_services: "{{ pf_tcp_services }}"
# 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:
- "{{ pf_rules_rdr }}"
- nat on $ext_if from $localnet to any -> ($ext_if)
- nat on $ext_if from $localvnet to any -> ($ext_if)
pf_filtering:
- antispoof for $ext_if
- "{{ pf_anchors }}"
- block $logall all
- pass in on $ext_if proto tcp to any port $tcp_services flags S/SA keep state
- pass inet proto icmp icmp-type $icmp_types
- pass inet6 proto icmp6 icmp6-type $icmp6_types
- pass from { self, $localnet, $localvnet } to any keep state
# blacklistd
pf_blacklistd_conf_remote: []
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 }}"}
# EOF
Playbook pb-dhcp.yml¶
- name: Test role vbotka.freebsd.dhcp
hosts: iocage
gather_facts: true
roles:
- vbotka.freebsd.dhcp
Playbook output - Install packages¶
(env) > ansible-playbook pb-dhcp.yml -i iocage.ini -t bsd_dhcpd_packages -e bsd_dhcpd_install=true
PLAY [Test role vbotka.freebsd.dhcp] *******************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_05]
TASK [vbotka.freebsd.dhcp : Packages: Install dhcp packages.] ******************
ok: [iocage_05] => (item=net/isc-dhcp44-server)
PLAY RECAP *********************************************************************
iocage_05 : ok=2 changed=0 unreachable=0 failed=0 skipped=5 rescued=0 ignored=0
Playbook output - Configure DHCP¶
(env) > ansible-playbook pb-dhcp.yml -i iocage.ini
PLAY [Test role vbotka.freebsd.dhcp] *******************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_05]
TASK [vbotka.freebsd.dhcp : Sanity: Collect installed packages.] ***************
ok: [iocage_05]
TASK [vbotka.freebsd.dhcp : Sanity: Set my_missing_packages] *******************
ok: [iocage_05]
TASK [vbotka.freebsd.dhcp : Rcconf: Enable and start dhcpd] ********************
ok: [iocage_05]
TASK [vbotka.freebsd.dhcp : Rcconf: Configure dhcpd.] **************************
ok: [iocage_05] => (item={'name': 'dhcpd_ifaces', 'value': 'bridge0'})
TASK [vbotka.freebsd.dhcp : Conf: Configure /usr/local/etc/dhcpd.conf from dhcpd.conf-minimal.j2] ***
ok: [iocage_05]
PLAY RECAP *********************************************************************
iocage_05 : ok=6 changed=0 unreachable=0 failed=0 skipped=6 rescued=0 ignored=0
Playbook pb-pf.yml¶
- name: Test role vbotka.freebsd.pf
hosts: iocage
gather_facts: true
roles:
- vbotka.freebsd.pf
Playbook output - Install packages¶
(env) > ansible-playbook pb-pf.yml -i iocage.ini -t pf_packages -e pf_install=true
PLAY [Test role vbotka.freebsd.pf] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Packages: Install packages.] *************************
ok: [iocage_05]
PLAY RECAP *********************************************************************
iocage_05 : 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-pf.yml -i iocage.ini -e pf_enable=false
PLAY [Test role vbotka.freebsd.pf] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Stat /etc/rc.d/blacklistd] ********
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Blacklistd: Backup /etc/blacklistd.conf.orig] ********
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Blacklistd: Configure /etc/blacklistd.conf] **********
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Stat /usr/local/etc/rc.d/fail2ban] ***
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Fail2ban: Configure /usr/local/etc/fail2ban/fail2ban.local] ***
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Fail2ban: Configure /usr/local/etc/fail2ban/jail.local] ***
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-sshguard: Stat /usr/local/etc/rc.d/sshguard] ***
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Configure sshguard.conf] *****************************
ok: [iocage_05] => (item={'key': 'BACKEND', 'value': '/usr/local/libexec/sshg-fw-pf'})
ok: [iocage_05] => (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_05]
TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Enable and start blacklistd.] *****
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-blacklistd: Configure blacklistd.] ************
ok: [iocage_05] => (item={'name': 'blacklistd_flags', 'value': '-r'})
TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Enable and start fail2ban.] *********
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-fail2ban: Configure fail2ban.] ****************
ok: [iocage_05] => (item={'name': 'fail2ban_flags', 'value': ''})
TASK [vbotka.freebsd.pf : Rcconf-sshguard: Enable and start sshguard.] *********
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-pf: Disable and stop pf.] *********************
changed: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-pflog: Enable and start pflog.] ***************
ok: [iocage_05]
RUNNING HANDLER [vbotka.freebsd.pf : Disable and stop pf] **********************
changed: [iocage_05]
PLAY RECAP *********************************************************************
iocage_05 : ok=18 changed=2 unreachable=0 failed=0 skipped=39 rescued=0 ignored=0
Playbook output - Enable pf¶
(env) > ansible-playbook pb-pf.yml -i iocage.ini -t pf_rcconf_pf
PLAY [Test role vbotka.freebsd.pf] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [iocage_05]
TASK [vbotka.freebsd.pf : Rcconf-pf: Enable and start pf.] *********************
changed: [iocage_05]
RUNNING HANDLER [vbotka.freebsd.pf : Start pf] *********************************
changed: [iocage_05]
PLAY RECAP *********************************************************************
iocage_05 : ok=3 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
Result¶
isc-dhcpd status¶
(env) > ssh admin@handy sudo service isc-dhcpd status
dhcpd is running as pid 4208.
/usr/local/etc/dhcpd.conf¶
(env) > ssh admin@handy cat /usr/local/etc/dhcpd.conf
# Ansible managed
# Global options
option domain-name "g3.example.com";
option domain-name-servers 8.8.8.8, 8.8.4.4;
default-lease-time 600;
max-lease-time 7200;
# Denotes this server as the primary DHCP server for the local network
authoritative;
# Internal subnet configuration
subnet 10.1.0.0 netmask 255.255.255.0 {
range 10.1.0.100 10.1.0.200;
option routers 10.1.0.1;
option broadcast-address 10.1.0.255;
}
pf status¶
(env) > ssh admin@handy sudo service pf status
Status: Disabled for 0 days 00:00:03 Debug: Urgent
Interface Stats for wlan0 IPv4 IPv6
Bytes In 0 0
Bytes Out 0 0
Packets In
Passed 2705 0
Blocked 391 0
Packets Out
Passed 0 0
Blocked 1501 0
State Table Total Rate
current entries 28
searches 4722 1574.0/s
inserts 53 17.7/s
removals 25 8.3/s
Counters
match 514 171.3/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 0 0.0/s
proto-cksum 0 0.0/s
state-mismatch 0 0.0/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@handy cat /etc/pf.conf
# Ansible managed
# template: default2-pf.conf.j2
# MACROS
ext_if = "wlan0"
int_if = "bridge0"
localnet = "10.10.1.0/24"
localvnet = "10.1.0.0/24"
logall = "log"
icmp_types = "{ echoreq, unreach }"
icmp6_types = "{ echoreq, unreach }"
tcp_services = "{ ssh }"
# 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)
nat on $ext_if from $localvnet to any -> ($ext_if)
# FILTERING
antispoof for $ext_if
anchor "blacklistd/*" in on $ext_if
anchor "f2b/*"
block $logall all
pass in on $ext_if proto tcp to any port $tcp_services flags S/SA keep state
pass inet proto icmp icmp-type $icmp_types
pass inet6 proto icmp6 icmp6-type $icmp6_types
pass from { self, $localnet, $localvnet } to any keep state
# EOF