View previous topic :: View next topic |
Author |
Message |
pietinger Moderator
Joined: 17 Oct 2006 Posts: 5136 Location: Bavaria
|
Posted: Wed Jun 03, 2020 11:18 pm Post subject: Gentoo FireWall for a DMZ and LAN with iptables (IPv4) |
|
|
(This post is dedicated to a very nice guy from this forum)
If you have problems to understand some of my steps, I recommend you to read the 2nd post of this thread first:
https://forums.gentoo.org/viewtopic-t-1112806-highlight-.html
This is not only a "How-To" (build FireWall-Rules with iptables), moreover I wrote this for learning how to optimize a more complex configuration than a simple router with only 2 interfaces. What we build here is for real world setups and you can use it, after you understand what we did (I hate it, when people find a script, use it, and then shout about it, because they dont understand anything).
What we want to build:
Code: |
+-------------------+
| DSL-Modem/-Router |
| 192.168.x.1/24 |
+-------------------+
|
+-----------------------------------+
| eth0: 192.168.x.2/24 |
|-----------------------------------| many Clients in your LAN
| Gentoo FireWall with 3 interfaces | | | | | | | | |
|-----------------------------------| +----------------------+
| eth1: 10.0.0.1/24 |----|Switch for LAN network|
|-----------------------------------| +----------------------+
| eth2: 172.16.0.1/24 | | | |
+-----------------------------------+ | +---------------------------+
| +----| Admin Station 10.0.0.2/24 |
+----------------------+ +---------------------------+
|Switch for DMZ network|---- more server ?
+----------------------+
| |
+---------------+ +---------------+
| Proxy-Server | | Webserver |
| 172.16.0.2/24 | | 172.16.0.3/24 |
+---------------+ +---------------+
|
Assumptions:
- No client in our LAN is allowed to go directly into the internet (with 2 exceptions for DNS and NTP)
- Every client browses the internet by using a proxy in our Proxy-Server
- We have many Gentoo Clients doing rsync to gentoo. This is handled also by the Proxy-Server
- Our Web-Server should be accessible from the internet (and of course from our LAN also)
- Our Gentoo FireWall (FW) must be maximally protected. Only SSH coming from the Admin-Station is allowed. No any other traffic into it is allowed.
---
- Of course you can use other private IP adresses than I use in this setup. The reason why I use private class-A-, class-B- and class-C-adresses is simple: If you see "something" with 10.0.0.x you know immediately, it must be "something" with a station in my LAN. If you see 172.16.0.x you know immediately ... DMZ ...
- You have in your DSL-Router "port forwarding" for port 443 and port 80 configured (to 192.168.x.3 and the same ports).
- You know how to enable forwarding with sysctl in your FW
- You was able to configure the needed network setups in all stations ... IF NOT: Do this first !
---
Recommendation for FW:
- Install a gentoo NO-MULTILIB profile
- Dont install any desktop
- Harden your kernel
- At boottime start only: sshd, ntpd (or ntp-client) and iptables
---
Side-Note to DHCP: Dont use it right now. Give every Server a static IP-adress. If you implement DHCP later, do it only for your clients. I can assert that even in a big company the mainframe and all servers (and even network-printers) have all static adresses.
Beginning with the end
Do you remember what we did when we selected a way in our router with 2 interfaces ? (No? Read what I said at the beginning of this post) We did the selection with "-i $INTERFACE" or "-o $INTERFACE", but it wasnt needed to define both (because of only 2 interfaces).
In a FW with 3 interfaces we have 12 ways a data-packet can go. And now, we have to tell our kernel which input-interface going to which output-interface we want to filter. If we specify only the input-interface in our table "filer" all packets to BOTH other interfaces would be matched. The same reverse: If we specify only the output-interface in our table "filer" all packets coming from BOTH other interfaces would be matched. So, we never shall specify only one interface ? Wrong. Sometimes we can skimp some rules, when selecting only one interface. Moreover we can skimp more rules, if we dont even specify one interface. We do this now. Instead of 12 rules, we need only 5 rules ...
You remember we set the default policy for all tables to DROP. But for our own clients, it would be better when we REJECT a packet, so the station gets the information this was not allowed. This is the last we define (3). Before that we do our final LOGGING. You can use a "catch-all" rule for this, or you define the logging for every possible way (2). What is the benefit ? You can search in your /var/log/messages for every token we use in our different log-explanations. And we have no drawbacks, because at this time, performance is not an issue - the packet is going to die And before this (1), we drop - silently - all packets which can appear and we dont want to log (because harmless and normal, if you have windows clients). Now you see all 12 possible ways ...
(as long as the firewall in your DSL-Router works correct, you will never see some log-entries ... think which ?)
Code: | ###### (1) drop some stuff without logging ######
iptables -A INPUT -p udp --dport 137 -j DROP # netbios-ns
iptables -A INPUT -p udp --dport 138 -j DROP # netbios-dgm
iptables -A INPUT -p tcp --dport 139 -j DROP
iptables -A INPUT -p tcp --dport 145 -j DROP
iptables -A INPUT -p udp --dport 67 -j DROP
iptables -A INPUT -p udp --dport 68 -j DROP
iptables -A INPUT -p 2 -j DROP # internet group management protocol
iptables -A FORWARD -p 2 -j DROP
# maybe there will be more hamless packets you want to drop silently,
# but you will see them in your log-file and then you can add it here
###### (2) Logging everything ######
### from WAN to ...
# ... LAN
iptables -A FORWARD -i $WAN -o $LAN ${logit} "DROP !!! WAN-LAN "
# ... DMZ
iptables -A FORWARD -i $WAN -o $DMZ ${logit} "DROP !!! WAN-DMZ "
# ... FW
iptables -A INPUT -i $WAN ${logit} "DROP !!! WAN-FW "
### from LAN to ...
# ... WAN
iptables -A FORWARD -i $LAN -o $WAN ${logit} "REJECT !!! LAN-WAN "
# ... DMZ
iptables -A FORWARD -i $LAN -o $DMZ ${logit} "REJECT !!! LAN-DMZ "
# ... FW
iptables -A INPUT -i $LAN ${logit} "REJECT !!! LAN-FW "
### from DMZ to ...
# ... WAN
iptables -A FORWARD -i $DMZ -o $WAN ${logit} "REJECT !!! DMZ-WAN "
# ... LAN
iptables -A FORWARD -i $DMZ -o $LAN ${logit} "REJECT !!! DMZ-LAN "
# ... FW
iptables -A INPUT -i $DMZ ${logit} "REJECT !!! DMZ-FW "
### from FW to ...
# ... WAN
iptables -A OUTPUT -o $WAN ${logit} "REJECT !!! FW-WAN "
# ... LAN
iptables -A OUTPUT -o $LAN ${logit} "REJECT !!! FW-LAN "
# ... DMZ
iptables -A OUTPUT -o $DMZ ${logit} "REJECT !!! FW-DMZ "
# as long as your FW works correct and isnt "hacked" you should never see some of these log-entries
###### (3) The End ######
# first we drop all packets coming from WAN (2 ways)
iptables -A FORWARD -i $WAN -j DROP
# then we reject the rest coming from LAN or DMZ (4 ways)
iptables -A FORWARD -j REJECT
# we reject all packets going from our FW to LAN, WAN or DMZ (= 3 ways)
iptables -A OUTPUT -j REJECT
# first we drop all packets coming from WAN to our FW (1 way)
iptables -A INPUT -i $WAN -j DROP
# then we reject the rest coming from LAN or DMZ to our FW (2 ways)
iptables -A INPUT -j REJECT
### this is the last part of our real world skript ### |
We used some variables. So we have to define them ... lets start with:
First part of our FW-Rules
We define some variables and set some rules you already (should) know. Then we define masquerading and DNAT for our Web-Server. Read every line and ask yourself, whats going on there. You should understand ervery line. After this we go to the main part.
Code: | #!/bin/sh
#
# 2020-06-03: Initial Sript for: FW
#
### Defines ###
# define general logging
logit="-j LOG --log-prefix"
# define interfaces
WAN="enps...." # Interface 192.168.0.2 to DSL-Router
LAN="enps...." # Interface 10.0.0.1 to LAN network
DMZ="enps...." # Interface 172.16.0.1 to DMZ network
# define addresses
ip_wan_dns1="a.b.c.d" # free internet dns-server1: xxxxxx
ip_wan_dns2="a.b.c.d" # free internet dns-server2: xxxxxx
ip_wan_ntp="a.b.c.d" # time-server: xxxxxx
ip_dmz_proxy="172.16.0.2" # our Proxy-Server
ip_dmz_web="172.16.0.3" # our Web-Server
ip_lan_admin="10.0.0.2" # our Admin-Station
# define ports
po_dmz_proxy="8118" # privoxy listens on this port
### Basic Settings ###
iptables -F
iptables -X
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE
iptables -t nat -A PREROUTING -i $WAN -j DNAT --to-destination ${ip_dmz_web}
### this is the first part of our real world skript ### |
Main Part I.
We dont allow every way of our 12 possible ways. Lets say we have only 7 allowed ways a packet can go. Now we have to differentiate between ways "going through" the table FORWARD, or packets going in our FW (INPUT) or coming from there (OUTPUT). Why ? Because of performance issues. With INPUT and OUTPUT we cannot get any problem, it is nearly nothing we allow there. But we can have many rules in our table FORWARD. So, we make the easy things first in our main part
What we want allow our FW ?
No connection to our LAN (one way is dead) ! Only NTP and DNS to the internet. And: It is a Gentoo box, and therefore it must be able to update in a gentoo way (rsync and https). But we dont want it to do this directly with the internet. Our FW must go to our Proxy-Server for both. Yes, you have to install a proxy- and rsync-daemon at host 172.16.0.2
My Recommendation for Proxy-Server:
https://wiki.gentoo.org/wiki/Privoxy
For rsync you find in chapter "Rsync server" all you need:
https://wiki.gentoo.org/wiki/Home_router
Code: | ### Firewall Out ###
# accept all rsync / https / http to Proxy-Server
iptables -A OUTPUT -o $DMZ -d ${ip_dmz_proxy} -p tcp --dport 873 -j ACCEPT
iptables -A OUTPUT -o $DMZ -d ${ip_dmz_proxy} -p tcp --dport ${po_dmz_proxy} -j ACCEPT
# accept dns to internet (WAN)
iptables -A OUTPUT -o $WAN -d ${ip_wan_dns1} -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -o $WAN -d ${ip_wan_dns2} -p udp --dport 53 -j ACCEPT
# accept ntp to time-server (WAN)
iptables -A OUTPUT -o $WAN -d ${ip_wan_ntp} -p udp --dport 123 -j ACCEPT
### Firewall In ###
# accept SSH IN from ADMIN with logging
iptables -A INPUT -i $LAN -s ${ip_lan_admin} -p tcp --dport 22 ${logit} "ACCEPT IN SSH ADMIN "
iptables -A INPUT -i $LAN -s ${ip_lan_admin} -p tcp --dport 22 -j ACCEPT
### this is the main part I. of our real world skript ### |
Now we have handled 3 ways of 7 allowed ways ... missing the other 4 ways ...
Main Part II. - User-defined Chains II.
In the last chapter of my 2nd post (see above), I wrote about user-defined chains and ONE kind of constellation, you can use it. Now I show a second reason to use it:
We will get "many" rules in our FORWARD table. If you are unlucky its rule number 23 which matches and allows (accept) you something. This we can break and make it smaller with using some user-defined chains - we really only need 2 chains here:
We simply ask if it is a packet coming from LAN going to DMZ, and if yes, we jump into an extra chain. If not, the second question is, do you come from DMZ going to WAN, and if yes, we jump into the second extra chain. The third question is a question containing only 2 rules, and therefore we dont jump anywhere and ask direct. Dont forget: This is the second half ...
Code: | ### from LAN to DMZ
iptables -A FORWARD -i $LAN -o $DMZ -j MY-LAN-DMZ
### from DMZ to WAN
iptables -A FORWARD -i $DMZ -o $WAN -j MY-DMZ-WAN
### from internet (WAN) to our Web-Server
iptables -A FORWARD -i $WAN -o $DMZ -d ${ip_dmz_web} -p tcp --dport 443 -j ACCEPT
iptables -A FORWARD -i $WAN -o $DMZ -d ${ip_dmz_web} -p tcp --dport 80 -j ACCEPT
### this is the main part IIb. of our real world skript ### |
OK - You know, we have to define these two user-definied chains before we use it. So we do now. But before, we think about DNS and NTP. You want to go to a time-server and DNS-server from everywhere (LAN AND DMZ). We could define the rules in both chains, but we can also define it once WITHOUT defining an INPUT-interface and defining only the OUTPUT-interface WAN. This we do in IIc. But first our two chains:
Code: | iptables -N MY-LAN-DMZ
### We allow from LAN to DMZ
# accept all rsync / https / http to Proxy-Server
iptables -A MY-LAN-DMZ -d ${ip_dmz_proxy} -p tcp --dport 873 -j ACCEPT
iptables -A MY-LAN-DMZ -d ${ip_dmz_proxy} -p tcp --dport ${po_dmz_proxy} -j ACCEPT
# accept all https / http to Web-Server
iptables -A MY-LAN-DMZ -d ${ip_dmz_web} -p tcp --dport 443 -j ACCEPT
iptables -A MY-LAN-DMZ -d ${ip_dmz_web} -p tcp --dport 80 -j ACCEPT
# ADMIN can do SSH to all servers in our DMZ with logging
iptables -A MY-LAN-DMZ -s ${ip_lan_admin} -p tcp --dport 22 ${logit} "ACCEPT DMZ SSH ADMIN "
iptables -A MY-LAN-DMZ -s ${ip_lan_admin} -p tcp --dport 22 -j ACCEPT
iptables -N MY-DMZ-WAN
### We allow from DMZ to internet (WAN)
# Our Proxy is allowed to do all rsync / https / http into the internet
iptables -A MY-DMZ-WAN -s ${ip_dmz_proxy} -p tcp --dport 873 -j ACCEPT
iptables -A MY-DMZ-WAN -s ${ip_dmz_proxy} -p tcp --dport 443 -j ACCEPT
iptables -A MY-DMZ-WAN -s ${ip_dmz_proxy} -p tcp --dport 80 -j ACCEPT
### this is the main part IIa. of our real world skript ### |
The last thing (really !) we do, is allowing DNS and NTP for everyone:
Code: | ### We allow from LAN - AND - DMZ to WAN
# accept dns to internet (WAN)
iptables -A FORWARD -o $WAN -d ${ip_wan_dns1} -p udp --dport 53 -j ACCEPT
iptables -A FORWARD -o $WAN -d ${ip_wan_dns2} -p udp --dport 53 -j ACCEPT
# accept ntp to time-server (WAN)
iptables -A FORWARD -o $WAN -d ${ip_wan_ntp} -p udp --dport 123 -j ACCEPT
### this is the main part IIc. of our real world skript ### |
Now - we are finished.
Not really. We are missing one important thing for our users: eMail !
Why I didnt made some rules for this ? It should be easy. Because, you have two ways you can go:
1. An own Mail-Server in your DMZ, or
2. Simply allow some hosts in your LAN (10.0.0.x) to connect directly to your eMail-Providers. This would be a "new way": From LAN to WAN. And I would suggest to make it with a third user-defined chain. Do you think, you can handle this ?
Yes, we can optimize this script a little bit more:
a) We have 5 doubled rules for NTP and DNS
b) What if, we change the default policy to REJECT ?
c) Check with "iptables -L -v -n" the number of packets you have in two days. Then change the order of your rules according to the load (e.g. first https, then http, then rsync).
Edit 2022-10-16: If you ask me now why I dont have rules for a NAT Loopback ( https://en.wikipedia.org/wiki/Network_Address_Translation#NAT_hairpinning ), my answer is: DONT use this ! Use Split DNS or do a DNS spoofing ! It is easier and much more performant.
Have fun, and please report any issues in this thread (I love it to make typos ...) |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|