Very Advanced Sysadmins Only!!!
Make sure you DOCUMENT every tiny little change you make!!!
OK, I am done yelling at you, but seriously, this is where we have made many mistakes, and they can be very serious, either locking people out or blowing our security wide open. These configurations are very powerful and thus very dangerous.
The iptables is part of the standard Red-Hat / Linux firewall. The usual way to configure this is through the guis, but BEWARE, we have a customized setup, so don't use the ****ing guis. The reason for the customization is that this allows us to use netgroups, i.e. we pull lists of system names from the LDAP database and allow certain services to every system in that list. The other reason not to use the gui is that it is too easy to think you know what you are doing, while you have no clue.
The LDAP Connection
To get a set of rules from LDAP we have a custom Perl script that gets these rules from the LDAP tables called "Netgroup". In this area of LDAP are a number of tables of object class "NisNetgroup" (and "top"), which contain a set of "NisNetgroupTriple" entries. For each table the scripts /usr/local/bin/netgroups2iptables.pl will make a corresponding iptables table. To see the resulting rules added to the iptables, type:
/usr/local/bin/netgroup2iptables.pl -v -dump
For the proper functioning of our iptables, it is thus pertinent (that is a fancy word for very important) that the LDAP server is running and the connection to LDAP can be made. After the iptables are started the init system then needs to execute:
(On some systems this will be called "iptables-npg").
For each line in each table you will then get a new iptables rule that states:
iptables -A accept-@table_name -s system-ip -j ACCEPT
Now, because we are dealing with iptables, we can also write a line that adds a jump ( -j) to another table. This is done by adding a non-blank memberNisNetgroup entry to our LDAP table. This will cause a jump to that set of rules instead of to the "ACCEPT" rule. So the entry "memberNisNetgroup specials" in the table "cn=supersystems" makes an iptable rule:
iptables -A accept-@supersystems -j accept-@specials
This allows us to chain the tables, so you can make one table with all the servers and then write a rule to allow, say NFS access and MySQL access to all the systems that are servers without needing to re-list all the systems that are considered servers.
Note: that the BACKUP SYSTEM makes use of the same tables! So adding a new "server" causes the backup system to try to connect to that server as well.
Note: that the scripts won't work if the Perl LDAP.pm module is not installed. Install it with:
yum install perl-LDAP # OR if this is not available: perl -MCPAN -e 'install Net::LDAP'
Note: that this system has a vulnerability: The iptables-npg can become corrupted on an /etc/init.d/iptables save command.
The normal configuration for the iptables is in /etc/sysconfig/iptables and /etc/sysconfig/iptables-config. The startup script is /etc/init.d/iptables
We have customizations as follows:
- /etc/init.d/iptables-netgroups This script runs /usr/local/bin/netgroup2iptables.pl (On some systems this is called /etc/init.d/iptables-npg a bit confusing, to be fixed.)
- /usr/local/bin/netgroup2iptables.pl A perl scripts which pulls the netgroup information from the LDAP. It uses "iptables-save" (system command) to get the current iptables.
- /etc/sysconfig/iptables-npg The iptables that the iptables-config points to for the data.
So new rules for allowing access must be set in /etc/sysconfig/iptables-npg and you must never use the "iptables save" command!
Iptables is an increadibly powerful system that allows filtering and forwarding and all sorts of fancy stuff. With sufficient smarts it can be used to create tunnels and forwarding and all sorts of weirdness. Since we don't want weirdness, please control yourself and don't write rules that say forward all the http traffic on pepper to einstein! Don't write a rule that allows your machine to get to everything on a server either!
The basic functionality of iptables is contained in it's tables, which contains a "chain" of rules. This means that it flows through the chain until it hits a rule that matches, at which point it jumps (-j) to the next chain. The main chain in INPUT, which is where everything starts, and ACCEPT or REJECT where things end.
You can see the current set of rules, and how many times each got "hit" by typing:
iptables -v -L
add a "-n" to not have the ip addresses reverse looked up, which can be slow. Add a "--line-numbers" to get the number for each rule, so that you don't risk mis-counting.
The file /etc/sysconfig/iptables-npg contains the main chains with rules. Additional rules are added by the netgroups2iptables.pl script. Note that each rule is added with an "-A TableName <rule>" line. Each TableName table must first be declared at the top (and zeroed out) with a line:
:TableName - [0:0]
For more details see the documentation.
You can add a new ad-hoc rule to the a table as well. Say we want to allow "improv.unh.edu" to temporarily browse the 631 port so we can configure cups. You need to add this rule, but now with -A because then it will be at the bottom, past the reject everything rule. To insert it BEFORE rule 5:
iptables -I INPUT 5 -s improv.unh.edu -p tcp -m tcp --dport 631
Do not add a wide open rule to your own workstation! Do not forget to delete your ad-hoc rule when you are done! . T
iptables -D INPUT 5
Of course, this still won't work, since cups is usually set up to only listen to localhost. Duh.
There is a special problem for NFS mounts. If you run "rpcinfo -p localhost", you will see that the port used by "mountd" and it's friends are something different all the time. This is new behavior in later RHEL 5.x releases. You first need to edit /etc/sysconfig/nfs to pin these ports to certain numbers, then add the correct rule to the iptables. For consistency sake I suggest for /etc/sysconfig/nfs:
LOCKD_TCPPORT=32050 LOCKD_UDPPORT=32050 MOUNTD_PORT=32051 STATD_PORT=32052 RQUOTAD_PORT=32053
Note: no spaces!
Actually, I don't think the STATD_PORT is used...
Finally, if you are at wits end, add a log rule BEFORE the rule you wish to debug. You write a rule but the target is LOG instead of ACCEPT (or REJECT). Then you "tail -f /var/log/messages" and watch all the garbage come in. This also shows up at dmesg. Example, log all attempts of nic.unh.edu to contact our system:
iptables -I INPUT 1 -s nic.unh.edu -j LOG --log-level 1 --log-prefix "Stuff from nic: "
For our systems
For our servers, we completely trust the backend network, so accept everything. You need to use "ifconfig" to make sure which is which!
NOTE: Change the lines for the appropriate interface: -A INPUT -i eth0 -j ACCEPT -A INPUT -i ! eth0 -s 10.0.0.0/24 -j REJECT --reject-with icmp-net-prohibited
Rule for allowing "ping" and "traceroute" to the machine:
-A INPUT -p icmp --icmp-type any -j ACCEPT
Rule to allow NFS (make sure that the ports are pinned in /etc/sysconfig/nfs):
-A INPUT -p tcp -m multiport --dports 111,2049,32050,32051,32053 -j nfs-acl -A INPUT -p udp -m multiport --dports 111,2049,32050,32051,32053 -j nfs-acl -A nfs-acl -j accept-@servers -A nfs-acl -j accept-@npg_clients
The last two rules are filled by the netgroups2iptables.pl script.
From the LDAP tables, we get:
- accept-@servers - filled by Netgroup->servers, List all servers.
- accept-@npg_clients - filled by Netgroup->npg_clients, all NPG workstations.
- accept-@dept_clients - filled by Netgroup->dept_clients, all Department computers with access.
- accept-@mysql_clients -filled by Netgroup->mysql_clients, systems allowed to access mysql database.
There are other tables that combine the above tables, but these are now being discontinued.
For our workstations, we only allow ssh and connections established by the workstation itself. This is a simple, easy, and relatively secure setup. The only openings are ones that users make (and are transient by nature) and ssh, which is fairly well covered by denyhosts.
Deny All Except a Select Few
First Deny all
iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP
Then start allowing stuff in: SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
Allow a specific IP to access everything
iptables -A INPUT -s 192.168.1.19 -j ACCEPT
Do it for a MAC address
iptables -A INPUT -m mac --mac-source 00:00:00:00:00:01 -j ACCEPT