Basic Linux Security


So, you want to run Linux (or you already are), but you're afraid it's not secure...

Great! If your box ever connects to a network, you're right!

Security is a process. It is a never-ending process that most people would rather forget about, but it is a fact of life in a connected world. This document is intended as a general introduction to securing a GNU/Linux system. It is not intended as a specific guide for any particular distribution or version or purpose. If the instructions in this document result in the destruction of hardware or software or data, you're on your own.


If you've just installed your system, then the chances are rather high that you are running unnecessary services, some of which probably contain known vulnerabilities. DON'T PANIC! :-)

Here are the things you need to do:

The first step is the hardest. You have to read up on a ton of things and synthesize a lot of information. As you're going through this process, however, you will gradually be securing your system.

A good tip I read is to make a list of all of the packages currently installed on your system. This way if you accidentally remove too many packages, you can refer back and determine which package you might need to reinstall. With an RPM-based distribution, this would be done with the following command:

rpm -qa > ~/date.rpms   (e.g. /root/20031206.rpms)

Now, start looking through the list and learning about the packages. The rpm command to use here is

rpm -qi pkgname   (e.g. rpm -qi apmd)

When you find a package that you don't need, you can remove it with rpm -e pkgname. Your package management system may warn you that another package depends on this package. Learn what that package is. Then you can remove both or neither.

Applying security patches is critical! Do NOT underestimate the importance of this. The moment a security vulnerability is announced, the likelihood of your system being compromised begins to rise.

Look to your distribution provider for security updates and instructions or software that enables you to apply those updates. Most major distributions provide an errata page, a mailing list, and update software. Bookmark the page, join the mailing list (NOW), and learn how to configure and use the software!


Okay, now that you've removed any completely irrelevant programs from your system, it's time to turn off unnecessary services. Services under Linux are often referred to as daemons and the program names therefore often end with a 'd'. On all Linux systems I've worked with, services are started and stopped using scripts in /etc/init.d/ or /etc/rc.d/init.d/. Usually you just run the script followed by 'start', 'stop', 'restart', 'status', etc.

To check what services are running, use netstat like this:

netstat -lt

Try it with the 'n' option to see port numbers instead of service names. Then you can see which service is listening on that port using 'lsof'.

For each service you shut down, you want to make sure it isn't started up again on the next system start. This is accomplished in various ways under each distribution. Generally, what all of those tools are actually doing is creating or destroying links in the /etc/rc.d/rc#.d/ directories. Let's look at some of those links now. Try this command:

ls -l /etc/rc.d/rc5.d/

You will see something like the following:

lrwxrwxrwx  ...  S10network -> ../init.d/network
lrwxrwxrwx  ...  S11pcmcia -> ../init.d/pcmcia
lrwxrwxrwx  ...  S12syslog -> ../init.d/syslog

The l in the first column means these are links. This is further reinforced by the arrow and the path following the filename. The name of the first link here is S10network and it points to ../init.d/network. These are all just links to the scripts that we were just using to stop unwanted services. When the system enters runlevel 5, it looks in /etc/rc.d/rc5.d and starts all of the services whose links begin with an S, in the order in which they appear in the directory. The numbers are there to enforce that ordering. When the system leaves runlevel 5, it will stop all of the services whose links start with a K.

So, by simple removing a link from this directory, you will prevent that service from starting in the corresponding runlevel! Of course, it would be tedious to actually manage your system services at this level, so there are tools which do it for you. That tool under Red Hat (and friends) is chkconfig (dumb name, I know). To see the ways of invoking this command, just run it without arguments:

chkconfig version 1.3.8 - Copyright (C) 1997-2000 Red Hat, Inc.
This may be freely redistributed under the terms of the GNU Public License.

usage:   chkconfig --list [name]
         chkconfig --add 
         chkconfig --del 
         chkconfig [--level ]  )

First, you should know what your system is currently configured to do. That command would be

chkconfig --list

The output will look something like the following, with each service having a row and each runlevel having a column. For each cell in the matrix, the service is either "on" or "off".

alsa            0:off   1:off   2:on    3:on    4:on    5:on    6:off
dm              0:off   1:off   2:off   3:off   4:off   5:on    6:off

So, to disable a particular service in all runlevels, you would run

chkconfig --del servicename   (e.g. portmap)

Portmap is a good one to turn off anyways, unless you're using NFS. To disable that service in just a few runlevels, you would run

chkconfig --level 345 portmap off

Of course, there are also graphical ways of doing all this. Feel free to search out the tool that's the most comfortable for you.

There is another way in which services are controlled, however. Some services use an intermediate server called inetd, which is short for "internet daemon". inetd listens for requests on behalf of other services. When it receives a request for one of those services, it runs the corresponding daemon (server) and passes off the connection to that new process. The configuration file is /etc/inetd.conf. To prevent inetd from listening on behalf of a service, just comment out that line in inetd.conf. To comment out the line, insert a "#" at the beginning of the line, so it looks something like this:

#ftp      stream tcp nowait root  /usr/sbin/tcpd    in.ftpd -l

After making a change to this file, you need to save it and restart inetd so it reads the updated configuration file.

/etc/init.d/inetd restart

If your distribution doesn't provide those scripts, you can "hup" the process:

killall -HUP inetd

Once you've disabled all of the services in inetd.conf that you do not need, you should evaluate the need to run inetd itself. If no services are being offered by inetd, then you should disable it entirely using the chkconfig method described above.

NOTE: Many distributions have taken to using a more robust replacement for inetd, such as xinetd. You will find the configuration for xinetd in /etc/xinetd.conf and /etc/xinetd.d/. Each file in /etc/xinetd.d/ corresponds to a service and you can turn it off simply by changing the "disable" value to yes, like this:

service printer
{
        socket_type     = stream
        protocol        = tcp
        ...
	disable         = yes
}

Recent versions of chkconfig and other system services configuration tools understand inetd and xinetd and can do this configuration work for you.


Now that you have your system limited to only the necessary services, and all of the security patches for those services have been applied, you need to restrict access to those services. The easiest thing you can do is to properly configure tcp_wrappers. tcp_wrappers is a system library that applications can call when they receive an incoming request. The library can take action based on the source of the request and inform the calling program whether or not that request should be served.

tcp_wrappers is configured via two files in /etc/, hosts.allow and hosts.deny. Unless you are running a public server, you should have a default deny policy and only allow connections from hosts that you trust. To to this, your hosts.deny file should look like this:

ALL: ALL

That is, deny all services from all sources. Then, to allow hosts from your local network and from a remote network access to a particular tcp_wrappers-enabled service, like ssh, you would put in your hosts.allow file the following:

sshd: 192.168.1. .talug.org

This is assuming that your network is 192.168.1.0 with a 24-bit netmask (255.255.255.0). Note that you can also use hostnames and domainnames, like .talug.org, as well as keywords like LOCAL to describe matching sources. tcp_wrappers looks up the source IP address of the request to see if it belongs to that domain. This means that you are trusting another system, so the use of hostnames and domainnames is discouraged. You should use IP addresses and networks whenever possible.

To allow access to all tcp_wrappers-enabled services from all local hosts (hosts in your domain) and from your own system's loopback interface, you could add the following:

ALL: LOCAL 127.0.0.1

127.0.0.1 is the reserved address which represents the local machine (a.k.a. localhost).

NOTE: If you choose to use domainnames or hostnames, those are dependent upon a successful DNS lookup. If the domain name service is unreachable at the time that a request comes in, it will not match your rule and the request may be denied!

That covers the minimum steps that everyone should take to reduce the potential for a break-in. The next step would be to erect a firewall on your system to filter out unwanted traffic before it even reaches the daemons. I leave that for another document. I will point you in the direction of two projects, however. They both seek to simplify the complex procedures involved in properly constructing a firewall using iptables, the built-in Linux packet filter. One is built for KDE: KMyFirewall; the other is built for GNOME: Firestarter.


Finally, now that you've seen a lot of how this stuff works at the lower levels, I'll introduce you to a nice web-based system administration tool called Webmin. "Using any browser that supports tables and forms, you can setup user accounts, Apache, DNS, file sharing and so on." It may even already be installed and running on your system. To log in, just point your browser to https://localhost:10000/ and log in as root.

Once logged in, you can setup a webmin user account that does not correspond to a real account on the system and that does not have access to the most critical sections. Then, you can setup "IP Access Control" under "Webmin Configuration" to limit the IP addresses that can log in (like tcp_wrappers). Now you can remote administrate your box from any of the allowed IP addresses (as long as your firewall isn't blocking port 10000!).

Now, you can perform all of the administration tasks described above and much more without having to use the command-line!


I hope you found this document useful.

Jason Bechtel