Fedora Core 3 Firewall Setup

June 2005

My project du jour is getting updating the firewall for the lab from RedHat 8 to Fedora Core 3. We are doing a Linux install for the lab so we can have a training toward the end of the month.

The firewall will actually be serving several important functions for the lab:

Install

Actually installing the system was something of a challenge. I've got the ISO images, but no blank CDs. I used a funky HTTP install for the machines in the lab, but the firewall only has 32mb of RAM and the FC3 installer refuses to run. So, I had to actually pull the drive and run the install in another box and then move it back. Disappointingly, the support for the ISA network cards which were auto-detected in RedHat 8, did not work in FC3. I had to go in and edit /etc/modprobe.conf by hand.

After some mucking about thought I managed to get it up and running. It was not horrible, but the number of problems I had definitely would have thwarted almost any novice:

  1. I had to move the drive once because the installer wouldn't run
  2. I had to move it back again because the first startup runs a graphical setup program that wasn't starting correctly. (And worse, was failing silently, so all I knew was that it wasn't starting.)
  3. Then I had to configure the ISA network cards by hand.

Finally though it was up and running with all the hardware working.

NAT

My little lab is NATed away from the rest of the university. We didn't used to be this way, but students here are frequently changing the IP addresses as a part of the course and though I emphasized the importance of being careful, they weren't. The university admins got frustrated with it and eventually stuck us off on our own. I prefer this solution to the previous one, which was simply to unplug our lab from the main switch.

The NAT was quick and simple: (we are 192.169.99.0/24 and the uni is 192.168.2.0/24)

iptables -t nat -A POSTROUTING -s 192.168.99.0/255.255.255.0 -j SNAT --to-source 192.168.2.176
service iptables save

There is also a server for the Cisco curriculum and a SMB fileserver at 192.168.99.250. I wanted that traffic to pass through, so I also did:

iptables -t nat -A PREROUTING -d 192.168.2.176 -p tcp -j DNAT \
    --dport 80 --to-destination 192.168.99.250
iptables -t nat -A PREROUTING -d 192.168.2.176 -p tcp -j DNAT \
    --dport 138:139 --to-destination 192.168.99.250
iptables -t nat -A PREROUTING -d 192.168.2.176 -p udp -j DNAT \
    --dport 138:139 --to-destination 192.168.99.250
service iptables save

DNS Server

The DNS servers provided Mauritel are fairly unreliable. For this reason and to provide dynamic DNS in conjunction with the DHCP, I wanted to run a DNS server.

The setup is simple enough. I added a couple zones (forward and reverse) to the chroot jail at /var/named/chroot/var/named/ for the local addresses in the lab and then added the shared dyndns stuff to /etc/named.conf.

This was the first place I hit a snag. Something new in FC3 was the integration of Security Enhanched Linux (SELinux). I've never used it before and it was denying access to the new zones that I'd created.

The problem with traditional Linux security is granularity. There are normal users and there is root and the layering of protections between them is pretty slim. For instance, to run a program like Apache, I have to be able to bind port 80. To do so, the process has to be running as root. Another term for root is the "superuser" and while running as root I embody that term in a Nietzscheian übermensch kind of way. I can look at or delete anyone's files I want to. I can send out forged emails or sniff network traffic. I am above the law and only bounded by my capabilities and imagination.

The process that is normally used is to mediate this problem is that the Apache process will essentally give up its Godhood and become a normal user after it has done whatever it needed to do. This process though has its problems, mostly inherent in having to trust Apache. A better solution would be to be able change the environment so that Apache was only given limited power in the first place so even if it is made to misbehave, it can't do any harm. This is what SELinux begins to provide.

All subjects (users, programs or processes) and objects (files and devices) are now assigned identities, roles and types. There are security policies which are made based on those attributes.

The error I am getting when I try and start named is:

audit(911588074.103:0): avc:  denied  { read } for  pid=15535
   exe=/usr/sbin/named name=named.conf dev=dm-0 ino=267969
   scontext=root:system_r:named_t tcontext=root:object_r:user_home_t tclass=file

If I just look at the file permissions, everything seems fine:

ls -l named.conf*
-rw-r--r--  1 root named 1547 déc 12  2004 named.conf
-rw-r--r--  1 root root  1329 nov 20 02:10 named.conf.orig

The file is readable by the named user who is what the bind process is running as. When we look at the SELinux contexts though, we can see the problem. (The programs ls, ps and id all now take a Z parameter than shows SELinux contexts.)

ls -lZ named.conf*
-rw-r--r--  root named  root:object_r:user_home_t    named.conf
-rw-r--r--  root root   root:object_r:named_conf_t   named.conf.orig

The file /etc/selinux/targeted/src/policy/domains/program/named.te contains the directive: (I had to install the selinux-policy-targeted-sources package to have the source.)

r_dir_file(named_t, named_conf_t)

This means that subjects of type named_t should be given read access to objects of type named_conf_t. Previously in the file there was the line:

can_exec(named_t, named_exec_t)

Which means that subjects of type named_t can execute objects of type named_exec_t. (/usr/sbin/named is of type named_exec_t.)

So, to fix my problem, I have to fix the context. The way to that is:

restorecon -v /var/named/chroot/etc/named.conf

The same problem exists for the new zone files, so I also have to do:

restorecon -v /var/named/chroot/var/named/*

DHCP Server

In an attempt to reduce the number of problems that we are having with misconfigured machines, I set up a DHCP server. The setup is pretty straight forward. I got the mac address off of each machine set up some blocks:

The basic file came from /usr/share/doc/dhcp-3.0.1/dhcpd.conf.sample and I edited it and put it at /etc/dhcpd.conf.

There is a SELinux problem here as well. There is a ownership problem like with named, but additionally, for the dnydns there is a shared file, /etc/rndc.key, with the authentication key used to update the server.

When I initially tried to run the program, I got an access denied error and in the logs it said:

audit(911596073.741:0): avc:  denied  { search } for pid=16624
   exe=/usr/sbin/dhcpd name=named dev=dm-0 ino=426311
   scontext=root:system_r:dhcpd_t tcontext=system_u:object_r:named_zone_t tclass=dir

/etc/rndc.key is just a symlink to /var/named/chroot/etc/rndc.key. The directory is of type named_conf_t which by the default policy dhcpd can't access. There is probably a more graceful way to deal with this problem, but all I did was to grant it premission to the whole context: (as well as giving permission to read rndc.key of the same type)

cat >> /etc/selinux/targeted/src/policy/domains/program/dhcpd.te << EOF

# Added to allow shared key config with bind:
allow dhcpd_t named_conf_t:dir { search };
allow dhcpd_t named_zone_t:dir { search };
allow dhcpd_t named_conf_t:file { read getattr };
EOF
make -C /etc/selinux/targeted/src/policy/ load

LDAP Server

I've done the DNS and DHCP servers before. I've even done a domain controller and some LDAP programming. I've never had a Linux lab to run before, so this was my first time setting up a shared authentication source for Linux boxen. The majority of the information on the setup came from the Linux Documention Project.

The first issue was to get the server up and running. This took an edit of /etc/openldap/slapd.conf to set the suffix, rootdn and rootpw. Also I tighetened the default security policy which is nonexistent and enabled TLS.

The default security policy gives everyone read access to everything, which is something of a problem. It also restricts write access only to the server administrator which means no users can change their passwords. So the security changes in slapd.conf have to be put into place before the setup will work.

Also, the migration will put the entries into an organizational unit, People under the base dn and groups under Group. Once the server is started you have to create those base entries. If necessary, you can clear the directory first using ldapdelete or just removing all the data files in /var/lib/ldap/.

service ldap stop
rm -rfv /var/lib/ldap/*
service ldap start
admin=$(grep -e ^rootdn /etc/openldap/slapd.conf | \
        sed -e "s/^rootdn[[:space:]]\+\"\([^\"]\+\)\"/\\1/")
ldapadd -H ldaps://localhost -D "$admin" -xW -f base.ldif

To migrate the existing information over to LDAP uses some perl scripts incuded in the distribution. Some setup is required by setting the environment variable LDAP_BASEDN before running:

export LDAP_BASEDN="o=Académie Cisco,o=Université de Nouakchott,c=MR"
/usr/share/openldap/migration/migrate_passwd.pl /etc/passwd > passwd.ldif
ldapadd -H ldap://localhost -D "$admin" -xW -f passwd.ldif
/usr/share/openldap/migration/migrate_group.pl /etc/group > group.ldif
ldapadd -H ldap://localhost -D "$admin" -xW -f group.ldif

This firewall will not actually be authenticating against the LDAP server, so the other changes are to the clients. I needed to update the configuration of the name service switch at /etc/nsswitch.conf, the PAM config at /etc/pam.d/system-auth and the default LDAP config at /etc/ldap.conf. (system-auth and ldap.conf were primarily updated by authconfig.) Also, to unify things a bit, I removed /etc/openldap/ldap.conf and made that a symlink to /etc/ldap.conf. Nsswitch uses the file in etc and ldapsearch uses the one in openldap, but the format is the same.

The one important thing to note with using the same file for both /etc/ldap.conf and /etc/openldap/ldap.conf is that PAM does not respect the uri directive, and so if you used that it is also necessary to include a host entry.

The debugging of this step proved a little troublesome, some commands that I found useful:

To verify that the ldap server was running and that I could connect from the client:

ldapsearch -x -H ldaps://firewall "(uid=will)"

On the server, in order to know which connections were being made and how, I did:

slapd -u ldap -d 1 -h "ldap:/// ldaps:///"

The debug levels is a bitmask (so you add the values to combine them):

LevelEffect
-1enable all debugging
0no debugging
1trace function calls
2debug packet handling
4heavy trace debugging
8connection management
16print out packets sent and received
32search filter processing
64configuration file processing
128access control list processing
256stats log connections/operations/results
512stats log entries sent
1024print communication with shell backends
2048print entry parsing debugging

In the end I turned on all debugging and found that my problem was I had used both a ldaps:// uri and the ssl start_tls command in /etc/ldap.conf. It was trying to start TLS twice and was failing. After this was fixed I could do:

getent passwd

And it would return results both from /etc/passwd on the machine and from the LDAP server.

Also the passwd command now works correctly to change passwords. The one potential issue is I can't change a user's password without knowing their old password. The system has to bind the LDAP server with an account with the permission to change the password and only the user and rootdn have that right. What I would like is to have it use the rootdn to bind when I'm running as root. I can have it do that, but only if I store the password in /etc/ldap.secret and I don't want to do that on all the workstations. I'll have to deal with this later.

Domain Controller

Though my lab is a salle of logiciel libre, the primary operating system currently installed is XP Pro with French and Arabic MUI. A nice setup even if it does come from the evil empire. Hopefully with this new Fedora setup I can get some people weaned.

The machines all have really restricted local user accounts that only let the students read and run a few basic programs. For the other teachers and myself though I want for them to be able to log in with a roaming profiles. Given that I hardly want to have to touch each computer to add accounts, I need a domain controller.

It just took making a few changes to the default /etc/samba/smb.conf.

Before I could use the tools included for managing the LDAP server, I had to install a perl LDAP module:

perl -MCPAN -e 'install ldap'

Or, actually for the server I was setting up I was having a problem with the OOM killer kicking in and killing off both the CPAN update and my ssh session, so I had to do the install by hand:

After the modules were installed, I updated the config file for the included ldap tools at /usr/share/doc/samba-3.0.8/LDAP/smbldap-tools/smbldap_conf.pm. Then I ran the script to create all the needed base entries:

perl /usr/share/doc/samba-3.0.8/LDAP/smbldap-tools/smbldap-populate.pl

Then I added a couple NT accounts just to try out that it was working:

smbpasswd -a root

To see if I could connect then I did:

smbclient //localhost/root -U root

Now I wanted to take hosts and join them to the domain controller. Each machine has to be added to the database to join the domain. To do this automatically, the domain controller needs access to some scripts. Rather than putting the actual paths in the config file, I made some symbolic links:


    

    
groupadd smbdomain
mkdir -p /home/samba/netlogon