# PF rules for database inside internal firewall



## gpatrick (Sep 2, 2009)

There is an external firewall and a dmz which has 3 domains (example.org, example.com, example.net).  The web servers are on 10.1.2 (.20, .21., .22) and a reverse proxy 10.1.2.23. 

Inside the internal firewall is a database which only the web servers should access to retrieve data when needed.  The database is on 10.1.3 (.20).

What rules for the internal firewall do I need so only traffic from web servers can access the database and return data?

Thanks.


----------



## SirDice (Sep 2, 2009)

Assuming it's MySQL and you're running PF something like this:

```
webservers = { 10.1.2.20, 10.1.2.21, 10.1.2.22 }

pass in on $if_dmz proto tcp from $webservers to 10.1.3.20 port 3306 keep state
```


----------



## mamalos (Sep 3, 2009)

You either seem to use two firewalls for your setup, or you use a single firewall ("spider" setup) for all your network segments (ext, dmz, int). In either case you should allow incoming traffic on your dmz interface from your dmz machines towards the internal network, and also allow outgoing traffic on your internal interface from the dmz to your internal network, for the specific hosts and ports (of course). 

So, to make sure that I understood correctly: The three web/blabla servers are located on your dmz network, and the database server is located on the internal network.

If so:

For both cases you need the following code on your ruleset. For the case of the two firewalls setup, these rules should be placed on your *internal firewall*:


```
#$if_dmz refers to the network segment of your DMZ with network address 10.1.2.0/24, and $if_int refers to your internal segment hosting the database server, with network address 10.1.3.0/24

webservers = { 10.1.2.20, 10.1.2.21, 10.1.2.22 }
dbserver   = "10.1.3.20"
dbport     = "1234"

pass in quick on $if_dmz inet proto tcp from $webservers to $dbserver port $dbport modulate state flags S/SAFR

pass out quick on $if_int inet proto tcp from $webservers to $dbserver port $dbport modulate state flags S/SAFR
```

All the above is valid, only if your default policy is block, and you don't use NAT anywhere between the two networks 

Hope it helped.


----------



## SirDice (Sep 3, 2009)

The second pass out rule is unneeded as the traffic is already allowed by the first.


----------



## mamalos (Sep 3, 2009)

No SirDice,

if your default policy is block (if you start with "block all") then you need both rules to establish the traffic flow on both interfaces. If you omit the second rule, your packets will pass the dmz interface and then they will stop inside the firewall, since it will be refusing access for the specific packets towards the internal network segment.

This is what firewalls are all about, isn't it? Rules for each interface and for both directions.


----------



## SirDice (Sep 3, 2009)

mamalos said:
			
		

> No SirDice,
> 
> if your default policy is block (if you start with "block all") then you need both rules to establish the traffic flow on both interfaces. If you omit the second rule, your packets will pass the dmz interface and then they will stop inside the firewall, since it will be refusing access for the specific packets towards the internal network segment.



No, it's similar to a rule like:

```
pass in on $if_in from $internal_net to any keep state
```

Traffic comes in on $if_in and goes out $if_out. No need for a separate pass out on $if_out rule.

You would only need a "pass out on $if_out" when the firewall itself would initiate the connection.


----------



## mamalos (Sep 3, 2009)

SirDice,

I will give you an example. Two interfaces, two networks, one IP on each interface. The ruleset is as follows:


```
int_if="re0"
ext_if="re1"
int_net="10.0.0.1/8"

block all
pass in quick on $int_if inet proto tcp from $int_net to any modulate state
```

With this ruleset THERE IS NO WAY outgoing traffic passes the ext_if. If it were like that, then pf would be in a lot of trouble! What would happen if we had 7 interfaces? Incoming traffic would be forwarded to all other six? This is quite substantial when building firewalls. Please, try this ruleset in some router with at least two cards and tell me if the traffic is passed out through the external interface. You will see that it won't.

In order for your last example to be valid, you should have stated (or implied) a rule somewhere in your ruleset that would mention something like the following:


```
pass out on $if_out from any to any keep state
```

This is exactly what I stated in my previous example. Once "block all" is specified in the beginning of the ruleset, then two rules are needed in order to get from one side to the other, one for each interface.


----------



## SirDice (Sep 3, 2009)

I'd hate to break this to you but I've setup PF for many years and I've never used a "pass out" rule to accompany a "pass in" rule. Oddly enough it has been working for years.



> What would happen if we had 7 interfaces? Incoming traffic would be forwarded to all other six?


No, it entirely depends on the machine's routing table where it would go out. PF has nothing to do with that.



> In order for your last example to be valid, you should have stated (or implied) a rule somewhere in your ruleset that would mention something like the following:


Nope, I start with a "block all".



> This is exactly what I stated in my previous example. Once "block all" is specified in the beginning of the ruleset, then two rules are needed in order to get from one side to the other, one for each interface.


Nope. You need to view the firewall including all it's interfaces as one entity. Not a seperate entity for each interface. When traffic goes _through_ the firewall it will hit the ruleset only once. Hence one rule is enough to pass the traffic.


----------



## DutchDaemon (Sep 3, 2009)

SirDice is right, mamalos. 

I have a NAT'ing router, and the 'pass out on $ext_if' rules are *only* used for traffic *originating* from the router itself (expressed by 'from $ext_if to any'). 

Traffic from the LAN, destined for the Internet is handled by a simple set of 'pass in quick on $int_if' rules which keep state. 

The routing table (and NAT) does the rest, and no 'block all' rule (which there most certainly is) touches it.

I think 'to any' is much more powerful than you realise .. which is why one should be extremely careful with 'any' rules.


----------



## mamalos (Sep 3, 2009)

Dutch Daemon and SirDice you are true. On all my firewalls I use:

set state-policy if-bound

which is why I say all this. The default state-policy of pf is floating, so this is why you get this behavior. The fact that I use if-bound policy gives me more control over my packets, but this doesn't prove any of you wrong


----------

