As I mentioned in an earlier post, I think every developer should have a private development environment to match his/her production architecture. In general that means that I need a firewall that exposes a limited set of services provided by set of web, application, and database server tiers. Using Solaris zones to model a production architecture, the Global zone can be configured to act as firewall, and the Local zones represent your service hosts.

A firewall is commonly configured with two ip addresses - one external facing (the public ip address), and one internal facing (on a private subnet). To configure a Solaris global zone as a firewall, first select a private subnet for the environment.

Example:
Global Zone public IP: 192.168.1.200
Global Zone private IP: 172.0.1.1
Create local zones web01, dbs01 on IPs 172.0.1.2 and 172.0.1.3

My /etc/hosts file:
192.9.168.200 global
# 172.0.1.1 is a logical ip address configured in the global zone
172.0.1.1   frw01
172.0.1.2   web01
172.0.1.3   dbs01

Our next step is to configure ipnat (network address translation) to expose the services of web and dbs hosts to the outside world through the global zone.

Our ipnat configuration has to handle two types of requests:
Inbound - an external host connects to the global zone to contact an exposed service.
- and -
Outbound - an internal host wants to access a service on the public network (for example, contacting an external dns server).

We can get by with two ipnat rules - rdr and map. The rdr rule is used to redirect a packet to a new destination, and the map rule is used to rewrite the source address of the packet.

Example 1: Forward inbound port 80 request to web01:80

In this case we use a rdr rule to forward the request to the web01 host, and a map rule to rewrite the source address so that when the packet reaches the local zone, it looks like the packet came from the global zone private address rather than some public ip
address that the local zone cannot resolve. 

rdr bge0 192.168.1.200/32 port 80 -> 172.0.1.2 port 80 tcp
map bge0 from any to 172.0.1.2 port = 80 -> 172.0.1.1/32

Note: In these examples, my default physical interface is bge0 - substitute your default interface in place of bge0 if it is different. You can use the output of 'ifconfig -a' to identify your default interface.

Example 2: Add outbound rule so all local zones can access an external dns server

The only rule required here is the map rule, this time we want to rewrite the outbound private address of any local zone to the public address of the global zone, so that when the packet reaches the dns server, the dns server can return the response data.

map bge0 from 172.0.1.0/24 to 4.2.2.1/32 port = 53 -> 192.168.1.200/32 portmap tcp/udp 1025:65000

Here any client on the private subnet (172.0.1.0) will have it's source address re-written to the public address of the global zone (192.168.1.200) when the packet is sent out. In addition, the portmap parameter instructs ipnat to rewrite the source port. You will always use the portmap parameter when rewriting a whole subnet (172.0.1.0) to resolve potential source port conflicts. Consider the case where web01 and dbs01 both send a dns request with source port 10000. If the ipnat is not instructed to manage source ports, there would be no way to tell which host should get the response from the dns server.

One extra step is required to enable outbound access to your private subnet zones. Since the local zones are on an isolated private subnet, they need a default route. Two possibilities are:

1. run routed in the global zone:
    # routeadm  -e ipv4-routing -e ipv4-forwarding -u

2. Instruct the local zones to use the global zone's default router. (This is my preference).

    From the global zone:
    # route add net $globalsubnet/${netmask} ${addr} -interface
    globalsubnet = 192.168.1.200
    netmask = 24
    addr = ip address of local zone host

    To enable  an external default router on web01:
    # route add 192.168.1.0/24 172.0.1.2 -interface

    Finally, publish the mac address of the global zone's default router so the local zones can find it:
    # ip=`netstat -rn | grep default | head -1 | awk '{print $2}'`
    # ping ${ip} > /dev/null
    # ether=`arp -an | grep $ip | awk '{print \$NF}'`
    #arp -s $ip $ether

Hope this is useful - Enjoy!

Comments:

Oops, left off one bit of information - how to start the ipnat service ...

1. Add your rules to the file /etc/ipf/ipnat.conf
2. enable ipfilter service with: "svcadm enable ipfilter"

Posted by jay on July 18, 2008 at 11:47 AM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed

This blog copyright 2008 by Jay Danielsen