Cover V13, i10
oct2004.tar

Using IPFilter to Protect Your Datacenter

Mike Scott

Security in the datacenter is a deeply contentious topic. Many people recognize the importance of the requirement, but unfortunately most companies shy away from the complexity of implementing adequate security even for their most critical servers.

As a simple illustration of the inadequacy of most installations, take a typical scenario within a large company. There are many servers connected to the corporate WAN, most of which occupy an important role in the running of an organization. However, within this inventory, there is a small subset of business-critical servers whose non-availability or compromise would cause significant financial, business, or legal problems.

In this example company, there are several offices, each of which are interconnected via the corporate WAN. A compromise in any of these offices would give network access to critical servers, protected only by the weakest point of security on that server.

How difficult would it be for an individual to gain access to the target company offices? It wouldn't be difficult. The individual would not have to be in a privileged position and could, for example, simply sign up with a local temping agency to engineer his way into a job with the cleaning service that cleans the offices after work hours. A savvy intruder could plant a wireless access point, allowing unrestricted access to the network from beyond the physical constraints of the building.

It is clear in the face of the sprawl of modern corporate [L|M|W]ANs that securing the entire network is a very difficult and, for most, logistically unfeasible undertaking. It therefore makes sense to spend more time and effort protecting the critical resources upon which your company depends.

The Traditional Approach

A traditional solution would be to consolidate the datacenter onto a (relatively) small number of subnetworks, and have those subnetworks protected by a dedicated enterprise-class firewall solution (e.g., Checkpoint Firewall-1), in much the same way as you might protect an external network connection.

This sounds like a good solution initially; however, a modern datacenter will generally contain many servers, each of which must communicate with peers and clients using a myriad of protocols and network paths. The resultant ruleset for this datacenter firewall is likely to be large, cumbersome, and very complex. When we encounter such complexity, managing updates becomes a difficult and time-consuming task, vastly increasing the likelihood of human error.

The Intrinsic Approach

In the UK there was a television advertisement for a certain brand of wood preservative, whose slogan was simply that it "does exactly what it says on the tin". IPFilter certainly lives up to that slogan -- it is a kernel module that is loaded in between the hardware driver and the IP module that allows network traffic flowing to/from the Unix kernel to be filtered, providing far superior access control to your servers than was previously possible.

Figure 1 illustrates how IPFilter integrates with the Solaris kernel modules that implement the hardware drivers and IP protocol handling. It provides an interface that can effectively block traffic traveling in either direction. It is implemented as two modules -- the "pfil" STREAMS module and the "ipfilter" module itself.

Most of the documentation available for IPFilter has been geared toward building dedicated firewall machines, but what appears to be glossed over in the currently available documentation is the potential for using it to secure individual servers. (Note that publicly available documentation for Solaris 10 is still a bit thin at the time of writing, so this may change over time.)

Of course, this technology is not new with Solaris 10 -- packet filtering has been around for a very long time indeed. If you are familiar with Linux, you are probably already aware of iptables (or its predecessor, ipchains). OpenBSD has "pf", and of course Darren Reed has been developing IPFilter for earlier versions of Solaris/FreeBSD/NetBSD for years.

In our example company, every client (or indeed any network-enabled device connected to the corporate network) has the ability to connect directly to the database servers and get a login prompt (or any other network service that the database server is configured to offer), providing a potentially valuable point of entry to an intruder.

This situation can be improved by the use of IPFilter but, to do so, the data paths of your application must be intimately known. This exercise is relatively easy to implement during initial system installation; however, retro-fitting it onto an existing service is very difficult indeed, requiring many hours of analysis and documentation to ensure that all network services are fully understood before proceeding.

A secure implementation of IPFilter has the advantages of helping to control your application set and ensuring that datapaths and inter-system dependencies are documented. Quite often, departments that are responsible for deploying an application will neglect to document the data flow between systems, making outage negotiation difficult for the systems administrator. Strictly controlling the data flow in this manner helps avoid problems by ensuring that the application does not evolve beyond the systems administrator's understanding.

Figure 2 illustrates a somewhat over-simplistic example of a three-tier application architecture. Rarely will a setup be this easy -- there will be data paths that have not been considered here (FTP uploads of batch reports, system and database backups, network printing, etc.). But to demonstrate the use of IPFilter, we shall assume that our application is indeed this simple.

We can define some network addresses for our application. For the purposes of this illustration, we shall use CIDR address notation where the trailing number after the IP address is the number of significant bits in the subnet mask -- see Table 1. See Figure 3 for an example network diagram.

So how would we begin to configure this into Solaris? In Solaris 10, the IPFilter packages are installed by default in the SUNWCall software cluster. To check whether you have the relevant packages, you can type:

$ pkginfo |grep SUNWipf
system      SUNWipfr           IP Filter utilities, (Root)
system      SUNWipfu           IP Filter utilities, (Usr)
$
To enable IPFilter on your machine, edit the /etc/ipf/pfil.ap file as shown. Uncomment your network interface type and reboot the machine:

# IP Filter pfil autopush setup
#
#      major   minor lastminor  modules

#le     -1      0       pfil
#qe     -1      0       pfil
hme     -1      0       pfil
#qfe    -1      0       pfil
#eri    -1      0       pfil
#ce     -1      0       pfil
#bge    -1      0       pfil
#be     -1      0       pfil
#vge    -1      0       pfil
#ge     -1      0       pfil
#nf     -1      0       pfil
#fa     -1      0       pfil
#ci     -1      0       pfil
#el     -1      0       pfil
#ipdptp -1      0       pfil
#lane   -1      0       pfil
The ruleset itself is stored as /etc/ipf/ipfilter.conf, and each time this file is changed the kernel module must be instructed with the new configuration. This is done with the following command:

# /etc/init.d/ipfboot reipf
We've discussed some of the broad terms associated with IPFilter; now let's see an example of a database server ruleset:

01 # Database server - inbound SQL*Net traffic from specific 
   # hosts, plus admin access
02 #
03 # For simplicity, we will allow all outbound traffic
04 # However, for a production server, I would want to lockdown 
   # outbound traffic also
05 pass out quick all keep state
06
07 # By default, we shall block all inbound traffic.
08 # If you're not on the list - you're not getting in...
09 block in all keep state
10
11 # ICMP is useful to have (ping,traceroute,etc) - some sites may 
   # wish to block this
12 pass in quick proto icmp from any to any
13
14 # Allow access to all services from our trusted host
15 pass in quick from 10.2.0.32 to any flags S keep state
16 # Allow SSH access from all hosts on our SysAdmin subnet
17 pass in quick proto tcp from 10.2.0.0/24 to any port = 22 flags 
   S keep state # SSH
18
19 # And, of course, SQL*Net connections from our application servers
20 pass in quick proto tcp from 10.1.0.1 to any port=66 flags S 
   keep state # SQL*NET
21 pass in quick proto tcp from 10.1.0.2 to any port=66 flags S 
   keep state # SQL*NET
22 pass in quick proto tcp from 10.1.0.3 to any port=66 flags S 
   keep state # SQL*NET
23 pass in quick proto tcp from 10.1.0.4 to any port=66 flags S 
   keep state # SQL*NET
For this ruleset, the rule on line #05 will allow all outbound traffic from the server by default (all of our rules here will "keep state" -- see the sidebar for more information). The keyword "quick" ensures that when this rule is matched (by the criteria "out" and "all") no further rules in the ruleset will be checked -- processing will stop (also called "first match and exit" behavior).

Line #09 sets the default policy for inbound traffic -- notice the lack of the "quick" keyword. This allows the ruleset to be further processed to allow the opportunity for an explicit rule further down the ruleset to reverse that decision by the packet filter.

ICMP (line #12) is useful because it allows support staff to use ping and traceroute to diagnose typical connectivity problems. (If desired, this rule can be omitted to further reduce the network exposure of this machine.) This rule allows any IP address to send an ICMP packet unrestricted to any IP address that this machine has defined. (Note that the "to any" could be tightened to a specific IP address on the server if that machine had multiple IP addresses defined, such as virtual IP addresses or multiple network interface controllers.)

Seems straightforward? It is indeed. Now onto the rules that do the application-level filtering that we are interested in. Line #15 allows unrestricted access from the administrative trusted host. You're already familiar with the general format of the rule, so the new keyword here is "type S". This is an additional condition on the rule processing that will match only on packets with the "SYN" flag sent (the first packet in any TCP conversation). We only need to match this packet because we are keeping state.

Line #17 defines SSH access to the server from only the administrative subnet (10.2.0.0/24) and then only to port tcp/22 (where SSHD listens for inbound connections).

Finally, the ruleset is finished off by lines #20-23, which allow access to the database servers' SQL*Net listener on port tcp/66.

The application server ruleset is similarly simple:

01 # Application server - inbound HTTP traffic from client subnets, 
   # plus admin access
02 #
03 # For simplicity, we will allow all outbound traffic
04 # However, for a production server, I would want to lockdown 
   # outbound traffic also
05 pass out quick all keep state
06
07 # By default, we shall block all inbound traffic.
08 # If you're not on the list - you're not getting in...
09 block in all keep state
10
11 # ICMP is useful to have (ping,traceroute,etc) - some sites may 
   # wish to block this
12 pass in quick proto icmp from any to any
13
14 # Allow access to all services from our trusted host
15 pass in quick from 10.2.0.32 to any flags S keep state
16 # Allow SSH access from all hosts on our SysAdmin subnet
17 pass in quick proto tcp from 10.2.0.0/24 to any port=22 flags S 
   keep state # SSH
18
19 # Allow HTTP connections from our client subnets
20 pass in quick proto tcp from 10.0.0.0/24 to any port=80 keep 
   state # HTTP
21 pass in quick proto tcp from 10.0.1.0/24 to any port=80 keep 
   state # HTTP
22 pass in quick proto tcp from 10.0.2.0/24 to any port=80 keep 
   state # HTTP
23 pass in quick proto tcp from 10.0.3.0/24 to any port=80 keep 
   state # HTTP
Outbound Filtering

To further secure the network stack, outbound filtering can be implemented also. For example, on the application servers, the following changes to the ruleset will ensure that only outbound traffic to the database servers.

Delete lines #03-05 and insert the following:

# By default, we shall block all outbound traffic
block out all keep state
# Rules to explicitly allow outbound traffic to the database servers
pass out quick proto tcp from any to 10.1.0.4 port=66 flags S keep \
state # SQL*NET
pass out quick proto tcp from any to 10.1.0.5 port=66 flags S keep \
state # SQL*NET
Remember, if you are considering this, you would also likely require rules to allow nameservice lookups (LDAP/DNS/NIS) as well as any other services upon which the server depends.

As an example, here is a real-life ruleset for a Solaris 10 NFS server:

block in all keep state
block out all keep state

pass in quick  proto icmp from any to any
pass out quick proto icmp from any to any

pass in quick proto tcp/udp from any to any port = 111 flags S \
  keep state # sunrpc

pass in quick proto tcp from trustedhost  to any .port = 514   \
  flags S keep state # rsh
pass in quick proto tcp from backup1      to any  port = 13782 \
  flags S keep state # Netbackup
pass in quick proto tcp from backup2      to any  port = 13782 \
  flags S keep state # Netbackup
pass in quick proto tcp from backup3      to any  port = 13782 \
  flags S keep state # Netbackup
pass in quick proto tcp from backup4      to any  port = 13782 \
  flags S keep state # Netbackup
pass in quick proto tcp from 10.2.0/24    to any  port = 22    \
  flags S keep state # SSH - Admin network only

pass out quick proto tcp/udp from any     to dns1 port = 53 flags \
  S keep state # DNS
pass out quick proto tcp/udp from any     to dns2 port = 53 flags \
  S keep state # DNS
pass out quick proto tcp/udp from any     to dns3 port = 53 flags \
  S keep state # DNS

pass out quick proto tcp from any to mailhost port = 25 flags S \
  keep state # SMTP
You may notice that neither of the NFS services appears in that configuration file -- this because those services are RPC-based and are prone to the port number changing when they are registered with rpcbind at boot time.

This prevents these services from being hard-coded in the configuration file, but can easily be worked around by the use of a small script to be run after nfs.server has been run in /etc/rc3.d:

rpcrule() {
        print "# $1";
        rpcinfo -p |nawk -v service=$1 -v dest=$2 '($NF == \
          service) {print
"pass in quick proto "$3" from a
ny to "dest" port = "$4" keep state"}' |uniq
}

rpcrule nfs    any | ipf -f - # Generate ipfilter rules, and feed 
                              # as stdin to "ipf"
rpcrule mountd any | ipf -f - # Generate ipfilter rules, and feed 
                              # as stdin to "ipf"
Conclusion

IPFilter is a highly configurable piece of software, and IP networking is a particularly broad topic, which makes it difficult to cover any more than the basics in the context of this article. Other things must be considered when implementing on a production server, for example:

  • The size of the state table for servers with high numbers of simultaneous network connections.
  • Variable port network services (e.g., RPC services such as NFS).
  • Monitoring and troubleshooting the IPFilter configuration.
  • Education of support personnel.

Servers are usually hardened by the removal of services from /etc/inet/inetd.conf and by disabling unnecessary daemons. IPFilter takes this one step further by allowing the kernel to actually prevent the traffic from even being presented to the services. Even if those services are running, they are guaranteed not to receive any traffic.

I have presented a demonstration of how to secure servers using the IPFilter facility within Solaris 10. IPFilter has been around for some time, available as freeware written by Darren Reed.

If you haven't already, perhaps you should start planning your use of IPFilter.

References

Darren Reed's IPFilter homepage -- http://coombs.anu.edu.au/~avalon/

IPFilter HOWTO documentation -- http://www.obfuscation.org/ipf/

"Securing Hosts with IP filter" by Amy Rich -- http://www.sun.com/bigadmin/features/articles/ipfilter.html

Mike Scott is the director of Hindsight IT Ltd, a small Solaris consultancy based in central Scotland. He has been working in the northeast and the central belt for the past 10 years, specializing in systems management with a keen interest in security and performance management. He can be contacted at sysadmin@hindsight.it.