This post is based on my notes for an initial configuration for an Ubuntu 9.04 Virtual Private Server with a focus on security. At that time I searched for a number of references on security, and while I have not kept the note of all their URLs, most of what I write below is as a result of other documents even though I cannot specifically cite them (in other words, there is little originality except perhaps for attempting to cover the entire gamut of configuration activities into one article).
Keep in mind that these steps are based on my notes which might be a little incomplete especially around the part where acidbase is installed.
Initial Configuration : Basic configuration when getting started up.
Setting up basic security : Basic Security configuration
Setting up rootkit detection : Setting up rootkit detection
Setting up Bastille : Setting up Bastille
Setting up the lamp stack : Set up the LAMP stack including mysql and apache
Setting up Snort and acidbase : Configure Intrusion detection using Snort and Acidbase.
Setting up File Integrity using AIDE : Setting up File integrity checks using AIDE
Initial Configuration
These steps cover the initial setup of a server
Setup the hostname
Lets say the hostname we want to setup is vps.
1 2 | |
Now update the /etc/hosts file to reflect the hostname and the fully qualified domain name Replace 12.34.56.78 with the IP address of your host
1 2 | |
Updating the ubuntu repositories
You will need to update your ubuntu repositories to include jaunty-updates and universe repositories. This is so that you may install additional packages as required from these repositories as well. In my case, the earlier version of the file /etc/apt/sources.list was as follows.
However please note, that repository selection and its update strategy may be linked to your company or application strategy. Please make sure these steps are consistent with your policy. If not, kindly adapt consistent with your team / organisations policy. Also instead of us.archive.ubuntu.com, you may find other country specific server names. In that case you may want to continue to use the other server name as already listed in your file.
1 2 3 4 5 | |
Upon adding jaunty-updates and the universe repositories, the resultant file is as follows.
1 2 3 4 5 6 7 8 | |
Now update the sources. This will scan all the repositories
1
| |
Finally upgrade ie. replace any existing packages which have a newer upgrade
1
| |
Download the language pack
To add the necessary for the preferred language of your choice add the appropriate language pack. In my case I add support for english (en)
1
| |
Set the timezone
Set the timezone of the server. You may choose to set it based on server location, or typical user location or to UTC.
1
| |
That will start a small app, from which you can select the timezone. I selected None of the Above which offered me a choice of timezones based on UTC offsets and subsequently selected UTC.
Setting up Mail sending
I do not need this VPS to act as a mail server. However I do need to have capabilities to send email from this machine. Many unix tools routinely assume the existence of sendmail or equivalent MTA. However that is an overkill in this context. So we shall not be installing sendmail or postfix or exim or any other equivalent. Instead we shall configure this server to be only able to send out mail using an SMTP account on another mail server. For this we shall install a tool called mailx. Note: If you have mailx already installed through another ubuntu package called mailutils, you may either continue with the same (in which case you will need to configure the remainder of the mail stack correspondingly eg. sendmail) or remove mailutils and add heirloom-mailx
1
| |
We shall also configure a global configuration for sending out mail. In my case its all right to always send mail using only one account irrespective of the process or user who is sending it.
1
| |
Note that in the above configuration, we shall be placing the mail account password in clear text. Make sure it is a mail account you do not use for any other purposes and that its password is not the same as used for any other purposes. Now enter the following as contents of the /etc/nail.rc file. Obviously change the relevant fields to appropriate values. Note that this file is configured for sending mail via gmail. You may need to configure it differently based on your own SMTP configurations.
1 2 3 4 5 6 | |
You can try testing whether this got set up successfully. Enter the following (replace youremailid@youremaildomain.com by the email id where you would like the mail to be sent to)
1 2 3 4 | |
Basic Security
In this section we shall make some basic configuration changes with a view to enhance the system security.
Mounting the shared memory as read only
Open and edit the file /etc/fstab to add an entry to mount shared memory in read only mode. The reason we do it is because many exploits use shared memory to attack other running services.
If you have a good reason to make shared memory writeable skip this step.
1
| |
Now add the following line at the end of the file
1
| |
Tightening the passwords
One of the easiest exploits is to attempt a brute force login using dictionary based attacks. In order to ensure strong ie. non-guessable passwords we shall update the password checking policy so that it allows only strong passwords. A simple way to ensure that is to ensure a reasonable minimum length and to ensure multiple character classes.
First lets install a new pam authentication module pam_cracklib. To install the same run the following
1
| |
Answer ‘Y’ to the prompt it asks for regarding continuing.
Note: if you did not add the universe repository to your sources.list file, you will not be able to install libpam-cracklib. In that case you will need to skip this step.
This should’ve resulted in the file etc/pam.d/common-password having an entry for pam_cracklib.so and pam_unix.so. Update the pam_cracklib.so entry to add one more requirement ie. minclass=4.
In my case, the resultant two lines in /etc/pam.d/common-password are as follows. Note that I added the minclass=4 clause manually.
1 2 | |
There. You now have a strong password scheme which will conduct a whole range of password checks in addition to ensuring that the password has a minimum length of 8 and each new password has at least one each of the four character classes. The four character classes are lower_case, upper_case, digit and special_characters (the last one being any non alpha-numeric character)
Creating the first user
Note: if you have already created at least one more non root user this step is not required. We are primarily creating the new user so that we shall eventually allow sudo and remote ssh login privileges to the user and disable remote ssh privileges for the root user.
Setup the first new user. One of the reasons you should create a new user is so that it will afford you the ability to allow him to perform root actions through sudo, and thus subsequently allow you to disable root access over ssh. By default when one creates a new user, another group gets created with the same name as well. In this case we shall create a new group ”dev” and then create a new user associated with that group ”someuser”. Use the groupname and the username as you would like to setup when executing the commands below. In the commands below we create a new home directory for the user, associate the /bin/bash shell with his account instead of the default /bin/sh, (I just prefer bash to the plain sh) and finally set the password for him.
1 2 3 4 5 | |
We shall also create the .ssh directory for the user which we shall be using later
1 2 3 4 5 | |
Now we shall create the keypair for the user to log in to the host remotely. Note that if you are going to do this for multiple users, then you might want to have each user run the next step locally and then copy over his public key onto the server before continuing to the ssh tightening operations described later.
The user should do the following on his local workstation from which he is most frequently likely to connect to the server (not the server that we are hardening).
Note: the part after -C in ssh-keygen is just a comment to identify the keys - enter something to identify the user and his machine. Also make sure not to keep the passphrase blank though ssh-keygen will allow a blank passphrase. The reason is that if the user’s local machine is compromised the attacker can then get an easy access to the server being hardened.
change someuser and some.host.com below based on the user id and vps name correspondingly
1 2 3 | |
Now the user should himself ssh to the remote server and on the remote server move his public key into the authorized_keys file. So execute the following command after being connected to the VPS
1 2 3 | |
At this stage the user can disconnect from the VPS and attempt to reconnect using ssh. If all works well, he should get connected to the vps in a manner where it does not prompt him for a password but instead he does get prompted for the passphrase to his private key (assuming he did set one).
This stage of updating the authorized_key file can also be performed by an administrative user / root once we later reconfigure ssh to only allow public key based logins.
Enabling the user to perform sudo operations
We shall enable any group who belongs to the group ’admin’ to be able to conduct root operations through using sudo.
First create a group ’admin’. subsequently associate the user with that group as well. Note : For best security ensure you allow associate only a very small number of users with the ‘admin’ group since that will effectively allow them control over the whole machine (assuming you setup the privileges as I subsequently describe below).
1 2 | |
Now we shall enable any user who belongs to the admin group to perform root actions by using sudo. To edit the sudo policy file do the following
1
| |
At the end of the file which is now opened up - add the following line
1
| |
Note this grants all superuser privileges to the users who belongs to admin group when conducting operations using sudo. You can use the sudo policy configurations to set up far more fine grained set of privileges, but thats beyond the scope of this document.
To test whether the configuration worked successfully, you can login as someuser and execute the following command.
1
| |
Tightening up ssh
To create the group and associate the users with them perform the following command (use the appropriate username instead of someuser for each user who you would like to allow SSH access).
1 2 | |
Now that we have at least one user id which can conduct root operations using sudo, its time to disable root login from ssh. Go open the file /etc/ssh/sshd_config. Make the following changes
This one disables root login for ssh. PermitRootLogin yes to PermitRootLogin no
Adding the following line allows only users of a particular group to login. Note: if your user count is small, you could use AllowUsers instead. We shall be separately creating the group and associating the users with the group. AllowGroups sshlogin
This change reduces the login grace time (time before a user needs to login after making the ssh login request). This is to allow better protection to sshd against DOS or brute force attacks. LoginGraceTime 20 to LoginGraceTime 20
This changes the port number that sshd listens on from the default 22. Changing the default port takes away the ability of an attacker to easily guess the port on which to attempt to penetrate the system via ssh. Port 22 to Port 9999 (or any other suitable number)
This change disables X11Forwarding over the SSH connection. It will result in you not being able to run X11 GUI applications remotely. If you need that flexibility, do not make this change X11Forwarding yes to X11Forwarding no
The next change disables password authentication (thus allowing only users with their public key being stored in the corresponding authorized_keys folder to connect using ssh). Thus passwords, which need to be transferred to the server in clear text no longer are a valid authentication mechanism. The only available choice is public key based authentication. PasswordAuthentication yes to PasswordAuthentication No
The next change disables password authentication (thus allowing only users with their public key being stored in the corresponding authorized_keys folder to connect using ssh). Thus passwords, which need to be transferred to the server in clear text no longer are a valid authentication mechanism. The only available choice is public key based authentication. PasswordAuthentication yes to PasswordAuthentication No UsePAM yes to UsePAM no
The following change of uncommenting the banner allows a welcome message (not really a welcome one :) ) to be displayed to SSH logins. It does not improve any aspect of the physical security but is more from a legal notice perspective. #Banner /etc/issue.net to Banner /etc/issue.net
Now go update the contents of the file /etc/issue.net to something similar to following
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Restart the ssh daemon and you will no longer be able to connect as root over ssh directly.
1
| |
Disabling su
As per the policy being followed, only users belonging to the ’admin’ group will have any special privileges. For all other users, we shall attempt to lock down the system to the extent feasible. As an early step we shall disable the ’su’ (switch user) command for all but those users belonging to the admin group. Note : since this disables sudo for a brief duration (between the commands), first switch over as a root before executing these commands
1 2 3 4 | |
Install rootkit detection
Install chkrootkit
1
| |
Now create this file /etc/cron.daily/chkrootkit.sh and enter the following contents (replace sever.domain.com with the servername and emailid where you would like the report to be sent to). Since the mail is rather verbose, and may lead to useful alerts getting ignored, I’ve removed the lines with the common messages. You may change or not use the grep commands as per your preference.
1 2 3 4 5 6 | |
Allow execute permissions on the file, and test once by running .. you should get a mail with the report.
1 2 | |
Installing Bastille
Bastille is a comprehensive package for security configuration.
Bastille Bug? and workaround
You may need to perform this workaround if your /etc/debian_version contains 4.0 and the current ubuntu bastille package has not resolved the issue. Ideally one should just need to install bastille from the ubuntu repositories
On Ubuntu 9.0.4 (jaunty) as of the day this document was written, I received the following error ~& ERROR: ‘DB5.0’ is not a supported operating system.
I’ve had a difficulty to install Bastille on Ubuntu 9.0.4. This is due to the fact that Bastille does not support the debian version number in /etc/debian_version. As per Bastille bug reports this got fixed in 3.0.8, but did not work for me in Bastille 3.0.9. Hence the following is a work around to install bastille.
This workaround involves downloading lynx to access internet, downloading the debian package directly, and then installing the debian package. When you reach the web page it will show you a list of mirrors. Download the .deb package from one of the mirrors
1 2 3 4 | |
Install psad which we shall need later and perl-gtk which we shall need to configure bastille with the following command
1
| |
You will notice an error message :
To resolve the same execute the following :
1 2 | |
Now run bastille in an interactive mode
1
| |
The resultant dialog with bastille is too long and I am just showing the final configuration file which is produced as a result of bastille configuration. I’ve used the port 22 as a proxy for the SSH port which I assume you’ve changed to some other value - use the other value instead of 22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
Installing the Lamp Stack
Let us use the not so well known tasksel command to download all the packages necessary for a lamp stack. Note that tasksel is simply a convenience tool around apt-get and allows one to install a whole bunch of packages based on a class of necessity - in this case a LAMP (Linux,Apache,MySQL,PHP) stack.
1
| |
During the installation you will be required to create the password for the mysql root user. In interest of tight security do make sure to create a really strong password.
This actually sets up the basic LAMP stack and that should get you operational.
Securing Apache
Change the user and group apache runs as
You may be aware that installation of apache resulted in a new userid and group being created (both called www-data). I just find it a little bit more comforting to change the well known usernames to something that are less predictable. In the steps below I change www-data to apache but you may want to use something a little less predictable than apache.
1 2 | |
We shall need to change the same in the apache configuration file. Edit the file /etc/apache2/envvars and change the two lines as follows
1 2 | |
Install and configure mod_security
Earlier when we configured, bastille and through it the iptables firewall, we allowed incoming public traffic on the SSH, HTTP and HTTPS ports. We’ve already covered the tightening of SSH security. However we still do not have a good way to control HTTP and HTTPS traffic. The solution to that is installing the apache module mod_security. It allows us abilities to inspect and if necessary reject or redirect HTTP/S traffic. The full description of mod_security is beyond the scope of this document, but a good example of how it can be used further to implement application level security as well can be had from the document Securing web services with mod_security. Another useful overview page is Secure your Apache2 with mod-security.
We shall start off with installing mod_security.
1
| |
You should notice a new file in /etc/apache2/conf.d called security. These are the global mod_security settings.
Change the following variables in the file to make server identification difficult. Note that while these settings do not enhance the security directly, they do make it harder for an intruder to easily identify the specific server and configuration, thus making it harder for him to attempt configuration specific exploits.
1 2 3 | |
Also uncomment the following four lines. Note that this may require you to configure other web applications which are not configured appropriately.
1 2 3 | |
While not related to mod_security, to minimise server information leakage, you may consider changing these two variables to the shown values in /etc/php5/apache2/php.ini
1 2 | |
As mentioned above, there is a whole range of additional controls you can enforce using mod_security. Depending upon your specific requirements feel free to leverage mod_security much more.
Disable apache modules you do not need
In general it is better to turn off unrequired modules unless you really need them. The default configuration installs a number of modules which may not be required. The modules that have been enabled are in the /etc/apache2/mods-enabled directory which are all symbolic links to the modules that have been installed in the /etc/apache2/mods-available directory. Note that turning off some modules may affect some web applications you install, in which case you may choose to subsequently turn them on only if necessary. New modules can be enabled with sudo a2enmod module_name command and enabled modules can be disabled by sudo a2dismod module_name command.
Depending upon my requirements, I disabled the following modules
1 2 3 | |
Chrooting apache
This is an advanced topic that I shall skip. Note that if you do setup chrooting, there’s a lot of additional considerations which will need to be observed, considerations especially around shared libraries and configuration files which will make the overall process of configuration extremely difficult.
Setting up snort and acidbase
Author’s Note: Careful - Very likely, there were a few things that I might have missed or incorrectly noted especially in the context of acidbase and following these instructions may not get acidbase running properly. You may have to do some steps outside these notes to get it all working properly. Unfortunately I am unable to rerun the process on a fresh server so am unable to immediately note the possible lacunae in the notes
Now that you have a mysql server going, create a new database for snort. In the following section I use snortdb as the database, snort as the user and snortpwd as the password for the database. However I do encourage you to replace the same with some non easily guessable names and passwords.
Here’s the commands to create a new snort database and user. In the following example ’$’ is the unix prompt while ’>’ is the mysql prompt.
1 2 3 4 5 | |
Now we shall install snort.
1
| |
The installation process will require you to enter the network that you wish to protect. Since in this case we are only protecting a single machine, enter the IP_Address/32 eg. 12.34.56.78/32
The process will prompt you whether you wish to configure the database. Select “Yes” .. the script will proceed but terminate abnormally with the error “subprocess post-installation script returned error exit status 6”
Now execute the following commands to setup the tables in the database. At the end you shall open the snort configuration file to enter the database configuration parameters
1 2 3 4 | |
Uncomment the line that starts with output database: log, mysql and add the configuration information at the end as shown
1
| |
Now remove the file as shown below to indicate that the database configuration has been done and start snort. The subsequent command confirms that snort daemon is indeed up and running
1 2 3 | |
Now, lets install acid which is a web based application to be able to view snort alerts
1
| |
Select No when it prompts you for configuring the database. By default it uses the database and userid ’snort’ and I prefer to keep these different from a predictable default, in which case acidbase database initialisation will fail.
Edit the file /etc/dbconfig-common/acidbase.conf.
Set the following values
1 2 3 | |
The default configuration allows acid data to be accessed only from the machine where it is involved. Since this shall be a VPS which we shall be accessing remotely, it is time to relax the constraint. If you have a good idea of the network IPs that you will be accessing the acid web application from, update the same in the allow from directive in /etc/acidbase/apache.conf, else relax it fully to allow from all.
Also protect the ’/acidbase’ url by http basic authentication. The resultant section in the file /etc/acidbase/apache.conf looks like :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
You will need to create a user id / password pair for the app or point AuthUserFile above to another file where you already have the ones set up for your server.
To do so you shall need to run the following command :
1
| |
If you need additional user ids to be installed use the command as shown above again with different user ids - but make sure not to use the -c switch since thats only used the first time to create the password file.
Now start the web application by restarting apache
1
| |
Goto the web page http:vps_fully_qualified_domain_name/acidbase/base_db_setup.php, click on ’Create Base AG//’ and you are on your way.
File integrity checking using AIDE
Install AIDE
1
| |
Update the aide configuration file etc/default/aide to update your email id where you would prefer the integrity check reports sent (Look for the variable MAILTO) Now initialise the aide configuration
1 2 3 | |
Now run the process (which will be running once daily)
1
| |
This process takes a long time (about 5 mins for me) and will at the end email you a report if any files changed compared to the ones in the default database.