PF Seek for some help for securing email server with PF

Hello all,

I have the following setup on a VPS of mine.
I have created an email server using jails (BastilleBSD). So far everything works great. On the actual VPS (the host) I have the following /etc/pf.conf:

Code:
# Main Variables
ext_if = "vtnet0"
host_ssh_port = "8199"
icmp_types = "{ echoreq unreach }"


# Jail Variables
jail_proxy = "192.168.100.10"
jail_mail = "192.168.100.25"


set block-policy drop
scrub in on $ext_if all fragment reassemble max-mss 1440
set skip on lo
set skip on bridge0


# Bastille Jails tables handling Jails' IPs
table <jails> persist

# IPv4 private address ranges
table <private> const { 10/8, 172.16/12, 192.168/16 }
nat on $ext_if from 192.168.100.0/24 to ! <private> -> ($ext_if:0)
nat on $ext_if from <jails> to any -> ($ext_if:0)
rdr-anchor "rdr/*"


#rdr via ipv4 to mail
rdr pass on $ext_if proto tcp from any to ($ext_if) port { 25, 465, 587, 143, 993 } -> 192.168.100.25

#rdr via ipv4 to nginx-proxy
rdr pass on $ext_if proto tcp from any to ($ext_if) port { 80, 443 } -> 192.168.100.10

block in all

#PASS ICMP
pass inet proto icmp icmp-type $icmp_types

pass out quick keep state
antispoof for $ext_if inet


# Allow incoming SSH (port 8199)
pass in inet proto tcp from any to any port $host_ssh_port flags S/SA keep state

I would like to implement rate litiming for all email ports, but so far I am not able to properly config PF. As far as I know, when I have such config with jails and NAT, I cannot directly implement rate limiting to "rdr on". So what are my options here?
 
Don't use rdr pass, it causes all other rules to be skipped. Split this up with a separate rdr and pass rule.

Code:
     If the pass modifier is given, packets matching the translation rule are
     passed without inspecting the filter rules:
 
OK, I found the way of doing it... I think, at least it is working, not sure if the is the most performant way of doing it:


Code:
# Main Variables
ext_if = "vtnet0"
host_ssh_port = "8199"
icmp_types = "{ echoreq unreach }"

# Jail Variables
jail_proxy = "192.168.100.10"
jail_mail = "192.168.100.25"

set block-policy drop
scrub in on $ext_if all fragment reassemble max-mss 1440
set skip on lo
set skip on bridge0

# Bastille Jails tables handling Jails' IPs
table <jails> persist

# IPv4 private address ranges
table <private> const { 10/8, 172.16/12, 192.168/16 }

# Cloudflare IP ranges table
table <cloudflare> persist

# NAT rules
nat on $ext_if from 192.168.100.0/24 to ! <private> -> ($ext_if:0)
nat on $ext_if from <jails> to any -> ($ext_if:0)

# Redirect rules
rdr-anchor "rdr/*"

# Redirect mail traffic to mail jail
rdr on $ext_if proto tcp from any to ($ext_if) port { 25, 465, 587, 143, 993 } -> $jail_mail

# Redirect HTTP/HTTPS traffic to nginx-proxy
rdr on $ext_if proto tcp from any to ($ext_if) port { 80, 443 } -> $jail_proxy

# Default blocking policy
block in all

# Allow ICMP traffic
pass inet proto icmp icmp-type $icmp_types

# Allow outgoing traffic
pass out quick keep state

# Antispoofing
antispoof for $ext_if inet

# Allow incoming SSH
pass in inet proto tcp from any to any port $host_ssh_port flags S/SA keep state

# Allow HTTP and HTTPS traffic only from Cloudflare IPs
pass in on $ext_if proto tcp from <cloudflare> to $jail_proxy port { 80, 443 } flags S/SA keep state

# Allow Email traffic only from anyCloudflare IPs
pass in on $ext_if proto tcp from any to $jail_mail port { 25, 465, 587, 143, 993 } flags S/SA keep state
 
One thing..

Are you running this server for yourself, small team or global?
If yourself or small team, consider to change 465, 587, 143 and 993 from the open world. You don’t need to have this exactly ports for you clients, you just get a lot of attacks. You only need port 25 to be on 25.
If this is a global server, I understand.

And do you really need all 465, 587, 143 and 993?
 
Back
Top