Building an OpenBSD Gateway - Part 2
Written by HE PingPing
Posted on: 11.24.2008 at 08:09am
Section: Tutorials

In Part 1 we successfully installed OpenBSD 4.4-RELEASE.  In this Part 2 we'll be doing some post-install configuration – securing our install in preparation for the installation and configuring of the network services that we will be running on our gateway (Part 3).

If you haven't done so already, boot the machine and login in as root.  You'll see you have new mail and you'll be asked what terminal type you want.  The mail is a message from Theo de Raadt, head of the OpenBSD project.  It contains some useful information about post-installation which you can read at your leisure by typing 'mail' <ENTER> and entering the number corresponding to the item of mail you wish to read, which, in this case, is just '1'.  However, we need to specify our terminal emulator first.  At the prompt, accept the default value offered [vt220].  It's kind of annoying having to do this every time we log in, so the first thing we'll do is make our selection permanent.

Permanently Setting the Terminal Emulator

If you're coming from a GNU/Linux background, one of the differences you'll notice in OpenBSD is the default text editor.  Nano is ubiquitous in GNU/Linux and it's available in OpenBSD but it doesn't come on the install CD.  To get Nano working we have to install it ourselves from either the (pre-compiled) Packages collection, or compile it from source using the Ports collection.  We'll install Nano later but, for now, we need to be aware that OpenBSD ships with vi as the default text editor.  If you've never used vi before, I recommend you learn it sometime.  It's much more complex than Nano but – like anything – once you get comfortable with it you'll wonder why you didn't start using it earlier.  Vi has the additional advantage that it's usually installed by default on virtually every *nix you'll ever come across.  However, we're not going to spend much time with vi in this tutorial as we really just want to get our gateway up and running but we will go through one, simple exercise using vi – just to give you an initial feel for how it's different from Nano.  At the root prompt type the following:

vi /root/.profile <ENTER>

We're now opened the /root/.profile file in the vi editor.  Use the cursor keys to navigate to the third line from the bottom – the line beginning 'if [ -x /usr/bin/tset ]: then'.  Once the cursor is positioned at the very beginning of this line, press the 'i' key to go into vi's 'insert' mode.  Now type '#' at the beginning of the line.  This will comment out the line so that it will be ignored at all future logins.  Use the arrow keys again to move to the beginning of the next line and, again, type '#' to comment out this (second last) line.  Don't worry if it won't let you get to the very beginning: it'll probably insist that the beginning starts after a gap representing a tab stop.  It's not a problem, just as long as the '#' occurs before any text on the line.  Once more, use the arrow keys to move to the beginning of the final line.  This time, you'll need to press 'i' again before you type the '#'.  Once you've commented out this line, press <ESC> to leave the insert mode, and save your progress by pressing ':' and then 'wq!' <ENTER> to write the changes and quit vi.  Now, you may be thinking that was a lot of work entering and existing an 'insert' mode for such a little change, but to experienced vi users, it's a walk in the park.  However, we haven't actually specified which terminal we want to use, we've only just commented out a few lines.  We still need to tell our install which emulator to automatically load every time we log in.  We need to make another change.  In fact, we're going to be making quite a few changes to various files as we go along so you may want to take time out right now, to spend some time coming up to speed on vi.  If you're impatient, like me, you'll want to make those changes using Nano so we're now going to install it.

Installing Nano

Remember that FTP mirror address we wrote down in Part 1 when we looked at the list of .iso image mirrors?  Well now we're going to need it.  At the root prompt type:

export PKG_PATH=ftp://<your mirror address>/pub/OpenBSD/4.4/packages/i386/ <ENTER>

where 'your mirror address' is the FTP mirror address you noted down.  My mirror is ftp://mirror.public-internet.co.uk so I type:

export PKG_PATH=ftp://mirror.public-internet.co.uk/pub/OpenBSD/4.4/packages/i386/ <ENTER>

TIP: don't forget the trailing '/'.
Now enter the following at the root prompt:

export FETCH_PACKAGES=yes <ENTER>

Now that we've set up our environmental variables to facilitate using OpenBSD's Packages collection, we can actually go ahead and install the Nano package by typing:

pkg_add nano <ENTER>

Now you'll see OpenBSD downloading and installing Nano and its dependencies.  Once it's finished it should look something like:

# pkg_add nano
libiconv-1.12: complete                                                      
gettext-0.17: complete                                                      
nano-2.0.7: complete                                                        
#

Now that Nano has been installed, we can use it to edit our /root/.profile file to specify the terminal to use on login and to make the above environmental variable changes permanent.  Type 'nano /root/.profile' <ENTER> and insert the following lines at the beginning of the file (above the PATH statement):

export TERM=vt220
export PKG_PATH=ftp://<your mirror address>/pub/OpenBSD/4.4/packages/i386/
export FETCH_PACKAGES=yes

Save these changes and exit Nano by using Ctrl+O.

Adding a New (unprivileged) User

OpenBSD has a script called 'adduser' that automates the user creation process.  At the root prompt, simply type 'adduser' and press <ENTER> and then follow the instructions.  At one point, you'll be asked 'Invite <YOUR USERNAME> into other groups: guest no [no]:'.  Here we need to make a decision about security.  

The normal response to such a question is to enter 'wheel'.  A member of the 'wheel' group can switch user ('su') to become root if they know root's password.  Therefore, any attempt at unauthorised root access would require knowledge of EITHER:

1.  the non-privileged user's username;
2.  the non-privileged user's password; and
3.  root's password.

OR if the cracker attempts to login as 'root':

1.  root's password

Since we'll be restricting remote root logins (via SSH) later on in this tutorial, we need only consider the first situation.  Now, if we don't include our non-privileged user in the wheel group, then it won't be able to switch user to root.  Therefore, in order to do any maintenance we would have to log in at the gateway directly as root, ie. we would not be able to do any maintenance remotely via SSH.  Now this may be an acceptable situation, but if we want to run our gateway 'headless' so that we can access it remotely then we have a problem if, at the same time, we don't allow root logins over SSH.

The solution is to use 'sudo'.  Sudo can be configured to allow an unprivileged user to execute commands as if it was root while not actually being root.  With sudo you can also specify exactly which commands the non-privileged user ('sudoer') can invoke.  This affords a level of 'granularity' that is really only limited by what you choose.  You could be forgiven for thinking sudo is a panacea to our problems.  However, it's not.  From the man page:

“Once sudo executes a program, that program is free to do whatever it pleases, including run other programs.  This can be a security issue since it is not uncommon for a program to allow shell escapes, which lets a user bypass sudo's access control and logging.  Common programs that permit shell escapes include shells (obviously), editors, paginators, mail and terminal programs. ”

For example, restricting the sudoer to only running the /bin/ksh command (ie. sudoer can invoke the korn shell) allows the sequence of commands:

$  sudo /bin/ksh
Password:
#  visudo

which allows the non-privileged user to edit the /etc/sudoers file and give him/herself unlimited privileges.

Note that when sudo is invoked it asks for a password.  By default, this is the user's own password.  In this configuration, unauthorised root access can be obtained purely by guessing the username/password combination.  There is no need to guess root's password with such a set up.  Therefore, we must configure sudo such that the sudoer is prompted for root's password so that we have the three levels of security we discussed above:

1.  the non-privileged user's username;
2.  the non-privileged user's password; and
3.  root's password.

So what's the difference between sudo configured, as above, and 'su'?  Well, aside from being able to refine the set of privileges, sudo also benefits from better logging.  While /var/log/authlog captures both authorised and unauthorised use of 'su', ALL uses of sudo get logged to /var/log/secure.  In other words, /var/log/secure ('sudo') provides an audit trail of what commands were executed by whom and when whereas /var/log/authlog ('su') only collect login attempts.  Of course, sudo may not stop an unauthorised sudoer changing the contents of /var/log/secure to 'cover their tracks'.  However, having the audit trail can be useful for the bona fide user who has inadvertently executed a command and can't remember which command it was in order to undo the damage it did.  The key thing to remember with sudo is that it's no substitute for a strong root password.  Now let's go ahead and set up a 'sudo' architecture.

Configuring Sudo

To edit the /etc/sudoers file we must use 'visudo', so invoke the following command as root:

visudo <ENTER>

You're now in the vi editor, editing the /etc/sudoers file.  Go to the end of the last line in the file using the arrow keys and press 'i' to go in to insert mode.  Then press <ENTER> twice to create two lines and then type:

Defaults rootpw
<your user's name>    ALL=(ALL) SETENV: ALL

Finally, press <ESC> to get out of insert mode and press ':' then type 'wq!' and hit <ENTER> to save the changes.  Here, we've given your user complete privileges but we've also changed the default password to root's, ie. whenever we use sudo we'll be asked for root's password, not our user's.

Log out and log back in as your (non-privileged) user and test out sudo by typing:

cat /var/log/authlog <ENTER>

You should see a 'permission denied' message.  Now type:

sudo cat /var/log/authlog <ENTER>

and enter root's password at the prompt.  This time you should see the output from authlog.  

Prohibit Root Login on SSH

Now that we've set up our sudo architechture, we're going to lock-down the root account even further, by prohibiting root logins over SSH.  To do this we need to amend /etc/ssh/sshd_config and restart the SSH daemon, sshd.  

Logged in as our unprivileged user, type 'sudo nano /etc/ssh/sshd_config' and press <ENTER>.   Enter root's password at the prompt.  Now we're in the sshd_config file.  Scroll down and change the line:

#PermitRootLogin yes

to

PermitRootLogin no

and exit, writing your changes (Ctrl+O).  Now restart the ssh daemon (sshd):

$ cat /var/run/sshd.pid
<sshd's process ID >
$ sudo kill -HUP <sshd's process ID>

To check it has restarted:

$ cat /var/run/sshd.pid
<sshd's new process ID>

Okay, so we're now using 'sudo' instead of 'su' to do our admin and we've shut out root from SSH  access.  So, if a cracker wants to access our gateway, they'll either have to physically access our gateway, or have to guess the name of our non-privileged user, his/her password and also root's password.  As our non-privileged user is not in the 'wheel' group it can't 'su' to root and any attempt to do so will be recorded in /var/log/authlog.  Any attempt to use sudo will be recorded in /var/log/secure.  Hopefully, by now, they'll have given up and moved on to cracking someone else's network.  Of course, if they're persistent, there are other measures we can take but these are outside the scope of this tutorial.  For now, we'll content ourselves with the SSH and sudo configuration we've done.

Checking Our Running Services

If a cracker can't guess our passwords, then the only way they can get 'in' is by exploiting any vulnerability within an application that is 'listening' on an 'open' port.  We're running the base install of OpenBSD with nano being the only package we've added.  Nano doesn't listen on ports so, from an open ports perspective, we're just running the base install.  We've allowed remote SSH logins (sshd) and we've set up the Network Time Protocol daemon (ntpd). So we know we have these two applications listening on open ports.  Since these applications have gone through rigorous code audit, we can rest assured that there are no known vulnerabilities associated with them.  But what about other services?  Are there any other applications listening on open ports?  Let's have a look.  Type:

netstat -naF inet <ENTER>

and you'll get a table that looks similar to mine:

$ netstat -naF inet
Active Internet connections (including servers)
Proto  Recv-Q  Send-Q  Local Address        Foreign Address   (state)
ip        0           &0          *.*                            *.*                          17
Active Internet connections (including servers)
Proto  Recv-Q  Send-Q  Local Address        Foreign Address   (state)
tcp       0             0         192.168.0.3.22       192.168.0.2.44241 ESTABLISHED
tcp       0             0         *.22                          *.*                          LISTEN
tcp       0             0         127.0.0.1.587          *.*                          LISTEN
tcp       0             0         127.0.0.1.25            *.*                          LISTEN
tcp       0             0         *.37                          *.*                          LISTEN
tcp       0             0         *.13                          *.*                          LISTEN
tcp       0             0         *.113                        *.*                          LISTEN
Active Internet connections (including servers)
Proto  Recv-Q  Send-Q  Local Address        Foreign Address   (state)
udp      0             0         192.168.0.3.12183  193.1.193.157.123
udp      0             0         127.0.0.1.512          *.*                  
udp      0             0         192.168.0.3.3609    84.2.42.31.123        
udp      0             0         192.168.0.3.8362    91.194.67.1.123      
udp      0             0         192.168.0.3.3070    81.169.136.18.123    
udp      0             0         192.168.0.3.1073    85.17.141.90.123      
udp      0             0         *.514                        *.*      

Yours will be different, but there are two things we can say about the above table:

1. compared with the likes of Red Hat, et. al there are very few services listening - 6 in total, with two listening to the localhost (127.0.0.1) only, one on port 22 (sshd), two for our ntpd timeserver (ports 37 and 13) and the final one (port 113) pertaining to sendmail.  In fact, if we'd answered 'no' to the ssh and timeserver prompts during the installation process, there'd be only three services listening – all pertaining to sendmail (ports 25, 113 an 587) with only one (port 113) listening for outside requests.  In fact port 113 is only used by sendmail to identify the name of a user sending email so, if we hadn't switched on ssh and ntpd during install, there would be no 'external' services listening by default.  Another instance of OpenBSD's approach to security: nothing is switched on until you switch it on.

2. those of you who know a bit about UDP will understand why there's no detail reported under the 'state' column – UDP is a stateless protocol – and you'll also understand that UDP is not a reliable protocol, offering little threat from outside intrusion attempts.  Incidentally, it's syslog listening for UDP requests on port 514.

If you're interested further in seeing which ports are used by which protocol, take a look inside /etc/services.

Crontab Reports

As our final bit of post-installation configuration we're going to alter crontab so that the regular reports are e-mailed to an external e-mail address where we can read them.  This requires editing the crontab file and replacing the word 'root' with our e-mail address (which I've assumed is 'youruser@youremail.com' for the sake of this illustration).  To do this type:

$ sudo crontab -e

and change the lines containing 'daily output', 'weekly output' and 'monthly output'.  On each of those lines replace the word 'root' at the end of the line with youruser@youremail.com then save the changes (again, the default editor is vi so use vi commands to achieve this).

And that's it.  Phew! That was quite a bit of work.  Congratulate yourself.  We can now move on to Part 3 where we'll begin building our gateway's network services – starting with the Dynamic Host Configuration Protocol (DHCP).