Tuesday, August 26, 2014

Building a firewall for a Debian web server

This post addresses how to configure the Linux firewall to protect a Debian-based web application server. While there are GUI tools for the job, we will focus on the command-line tool iptables.

The scenario is that you have just installed Debian (or Ubuntu) on a server connected to the Internet. This will be used as a web server hosting your WordPress blog. I assume that you already have Apache, and WordPress installed. Please refer to my earlier post for instructions on how to install WordPress on Debian.

Basic Requirements

Before we build the firewall, let's write down the basic requirements - the types of traffic the machine will accept and those it will drop.

  • Accept all outbound traffic (from server to the Internet).
  • Accept inbound ssh logins.
  • Accept inbound Web requests.
  • Accept inbound ping requests.
  • Log firewall-specific warnings.

Build firewall

Please follow the order of the steps below. The procedural order is designed to minimize the chance of locking yourself out by mis-configuring the firewall.

  1. Log in to the server either on the physical console or remotely via ssh.

    The physical console is better because then you don't need to worry about being locked out. However, it is not always possible to access the console because the machine may be sitting afar in a data center.

  2. Examine the current firewall configuration.
    $ sudo iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination

    Note the policies for INPUT, FORWARD, and OUTPUT. The typical default firewall is configured to accept all traffic, both inbound and outbound.

  3. Flush the firewall.

    Flush only if:

    • your firewall is not 'clean' - it has existing rules, and
    • the INPUT policy is ACCEPT.

    If the INPUT policy is not ACCEPT, you can make it so like this:

    $ sudo iptables -P INPUT ACCEPT

    To flush the firewall:

    $ sudo iptables -F

    Now, we are ready to add the firewall rules, one by one. Note that they comprise the basic rules to satisfy our stated requirements. Not included are specific rules to thwart common Internet attacks.

  4. Add rule # 1.
    $ sudo iptables -I INPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    The above rule accepts any incoming traffic that is part of, or related to, an existing connection. If you are currently logged in via a remote ssh session, this rule prevents you from being locked out. So, it is important that you create it first.

  5. Add rule # 2.
    $ sudo iptables -I INPUT 2 -m conntrack --ctstate NEW -p tcp --syn --dport 80 --j ACCEPT

    This rule accepts all new incoming WordPress connections to port 80.

  6. Add rule # 3.
    $ sudo iptables -I INPUT 3 -m conntrack --ctstate NEW -p tcp --syn --dport 22 --j ACCEPT

    Rule # 3 accepts all new incoming ssh sessions to port 22.

  7. Add rule # 4.
    $ sudo iptables -I INPUT 4 -p icmp --icmp-type echo-request -m limit --limit 2/second -j ACCEPT

    This rule accepts incoming ping echo requests at the maximum rate of 2 requests per second.

  8. Add rule # 5.
    $ sudo iptables -I INPUT 5 -m limit --limit 2/min -j LOG --log-prefix "INPUT:DROP:" --log-level 6

    All incoming traffic that are not accepted by any prior rule get logged at a maximum rate of 2 entries per minute. The default log file is /var/log/messages. For easy identification, the log entries are prefixed with the string 'Input:Drop:'.

  9. Change default INPUT and FORWARD policies to DROP.

    With the policy change, all incoming traffic not explicitly accepted by any of the above rules are dropped.

    $ sudo iptables -P INPUT DROP $ sudo iptables -P FORWARD DROP

Your basic firewall is complete. You can view the newly created firewall rules via the following:

$ sudo iptables -L Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere ctstate NEW tcp dpt:httpflags: FIN,SYN,RST,ACK/SYN ACCEPT tcp -- anywhere anywhere ctstate NEW tcp dpt:sshflags: FIN,SYN,RST,ACK/SYN ACCEPT icmp -- anywhere anywhere icmp echo-request limit: avg 2/sec burst 5 LOG all -- anywhere anywhere limit: avg 2/min burst 5 LOG level info prefix "INPUT:DROP:" Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination

Save firewall

The firewall that you just created will not persist. If you reboot the server, the firewall will revert to the default configuration - accept all traffic - before you made all the above modifications. To save the firewall changes permanently,

  1. Install iptables-persistent package.
    $ sudo apt-get install iptables-persistent
  2. Make an explicit save.

    After you finish modifying the firewall, you need to explicitly save the firewall configuration in the file /etc/iptables/rules.v4 using the command below.

    $ sudo iptables-save > /etc/iptables/rules.v4

Custom log file

The above firewall logs all dropped incoming traffic to the general system log file /var/log/messages. To avoid cluttering the file, I recommend sending the iptables-related log entries to a separate file, say /var/log/iptables.log. This is possible because iptables-related log entries are prefixed with a custom identifier - 'INPUT:DROP:'.

  1. Create a rsyslog rule to redirect firewall log entries.

    A new file /etc/rsyslog.d/10-iptables.conf is created to hold the rsyslog rule.

    $ cat > /etc/rsyslog.d/10-iptables.conf :msg, contains, "INPUT:DROP:" -/var/log/iptables.log & ~

    The first line in the file specifies that if a log entry contains the custom identifier, it is sent to /var/log/iptables.log.

    The second line skips forward to the next log entry, thereby preventing double logging into /var/log/messages.

  2. Restart rsyslog daemon.
    $ sudo service rsyslog restart

Tuesday, August 19, 2014

Using double dash to specify pesky command line parameters

Many Linux commands accept command-line options and positional parameters. The grep command searches for a pattern in a given file. Its 2 positional parameters are the pattern and the filename. It accepts options such as -i which specifies that the search is case insensitive.

An interesting scenario is when a positional parameter has a value starting with a dash ('-'). This makes the parameter indistinguishable from an option. For example, you try to grep the string -tea in a given file.

$ grep -i '-tea' test.txt grep: invalid option -- 't' Usage: grep [OPTION]... PATTERN [FILE]... Try 'grep --help' for more information.

The -tea is interpreted as an option. Consequently, the command failed.

To solve the problem, insert the double dash (--) on the command line to mark the end of all options. Everything that come after the -- marker are interpreted as positional parameters.

$ grep -i -- '-tea' test.txt Beverages -tea and coffee- are served.

Anther example scenario for using the double dash is the deleting of a file with a pesky file name. Suppose you want to delete a file named '-a'.

$ rm -a rm: invalid option -- 'a' Try `rm --help' for more information.

Enter -- to mark where the positional parameters start.

$ rm -- -a

Sunday, August 10, 2014

Tips on GNOME Classic workspaces

In the world of affordable, dual 27-inch monitors, the GNOME virtual screen feature (aka workspaces) may not hold the same prominent position as before. But, to people like myself who still operate machines equipped with only a single 19-inch monitor, using workspaces effectively is still a big productivity booster.

Below are some tips for using GNOME Classic workspaces.

Tip 1: Change # of default workspaces

By default, the GNOME desktop has 4 workspaces available. The default number can be changed. I, for one, would like to decrease the number of workspaces to 2. I hardly ever need more than 2. With 4 workspace icons spanned out at the bottom of the GNOME Classic screen, I often accidentally click on the wrong one.

To change the default number of workspaces, first install the wmctrl tool. (This tool is also featured in my previous post on how to change window manager.)

$ sudo apt-get install wmctrl

To modify the number of workspaces to 2:

$ wmctrl -n 2

Note that the change takes effect immediately. Also, the change persists after you log out of GNOME.

Tip 2: Keyboard shortcuts to move window to another workspace

Move focus to the window that you want to move. This can be achieved by simply clicking inside that window.

Press the Shift+Ctrl+Alt+RightArrow keys to move the window one workspace to the right. Similarly, press the Shift+Ctrl+Alt+LeftArrow keys to move one workspace to the left.

Tip 3: Keyboard shortcuts to switch workspaces

Before I learn of the keyboard shortcuts, I always mouse over to the workspace switcher app at the bottom of the GNOME Classic screen. From there, I can either click a workspace icon, or scroll using the mouse's scroll wheel, to switch to the target workspace.

If you prefer keyboard shortcuts to the mouse,

  • press the Ctrl+Alt+RightArrow keys to switch to the workspace on the right of the current workspace, or
  • press the Ctrl+Alt+LeftArrow keys to switch to the workspace on the left.

Tip 4: Customizing keyboard shortcuts

You can view the entire list of GNOME keyboard shortcuts, and even customize them according to your personal preferences.

  1. Open System Settings.
    $ gnome-control-center

    You can also open System Settings from the user menu in the top right corner.

  2. Open Keyboard / Shortcuts / Navigation.
  3. Change keyboard shortcut.

    To edit a keyboard shortcut, click to select the corresponding row. Note that a new label is displayed: New accelerator. Press the new keyboard shortcut keys.

Monday, August 4, 2014

Chrome Remote Desktop connects from your Android device to Linux

Google recently announced the beta release of the Chrome Remote Desktop for Linux. It allows you to remotely connect to a Linux machine from within the Chrome browser. Judging from the early comments in the Google product help forum, setting up the Chrome Remote Desktop on a Linux machine is still rather quirky for certain configurations. This post details my experience of successfully installing and setting up Chrome Remote Desktop to connect from an Android device to a Debian Wheezy machine.

First, install and setup Chrome Remote Desktop on the Debian machine. Then, install the Chrome Remote Desktop app on the Android device.

Install on Debian

  1. Install Google Chrome.

    The official Debian Wheezy repository includes the Chromium browser, which is the unbranded, open-sourced version of Chrome. To avoid any compatibility issues, download the official Google Chrome browser package directly from the Google product page. Then, install it as follows:

    $ dpkg -i google-chrome-stable_current_amd64.deb
  2. Add Chrome Remote Desktop to Chrome.
  3. Configure virtual desktop.
    • Create script to start virtual desktop.

      Create the file ~/.chrome-remote-desktop-session, which contains the command to start your preferred desktop environment. You may look up the command in the corresponding desktop file located in the /usr/share/xsessions directory. For instance, if the desktop is GNOME, look up the Exec command in /usr/share/xsessions/gnome.desktop.

      $ grep '^Exec=' /usr/share/xsessions/gnome.desktop Exec=gnome-session

      Note that gnome-session - the text after 'Exec=' - is the command to start the virtual session. Insert the command to ~/.chrome-remote-desktop-session as follows:

      $ cat > ~/.chrome-remote-desktop-session exec gnome-session
    • Change screen resolution (optional).

      By default, the screen resolution of the remotely-connected virtual desktop is 1600 x 1200 pixels. To modify the default resolution, append a line to ~/.profile. For instance, to make it 1024 x 768,

      $ cat >> ~/.profile export CHROME_REMOTE_DESKTOP_DEFAULT_DESKTOP_SIZES=1024x768
  4. Install Chrome Remote Desktop daemon.
    • Download the 32-bit or the 64-bit Debian package for Chrome Remote Desktop from the Google Chrome Remote Desktop app page.
    • Install the Debian package.

      My first attempt failed due to dependency problems: some required packages were not pre-installed.

      $ sudo dpkg -i chrome-remote-desktop_current_amd64.deb ... dpkg: dependency problems prevent configuration of chrome-remote-desktop: chrome-remote-desktop depends on xvfb-randr | xvfb; however: Package xvfb-randr is not installed. Package xvfb is not installed. chrome-remote-desktop depends on xbase-clients; however: Package xbase-clients is not installed. chrome-remote-desktop depends on python-psutil; however: Package python-psutil is not installed. ...

      To resolve the dependency problems, run apt-get -f install and then re-install the package:

      $ sudo apt-get -f install Reading package lists... Done Building dependency tree Reading state information... Done Correcting dependencies... Done The following extra packages will be installed: python-psutil xbase-clients xvfb The following NEW packages will be installed: python-psutil xbase-clients xvfb ... $ sudo dpkg -i chrome-remote-desktop_current_amd64.deb

      A daemon named chrome-remote-desktop is created.

      $ sudo chkconfig --list |grep chrome chrome-remote-desktop 0:off 1:off 2:on 3:on 4:on 5:on 6:off
  5. Authorize Chrome Remote Desktop.

    When you run the Chrome Remote Desktop app for the first time, you will be asked to grant permission for the app to do its job.

    • Open a new tab in Chrome, and enter chrome://apps/.
    • Click Chrome Remote Desktop icon.
    • Click Continue, then Accept.

  6. Enable remote connections.
    • Click the Get started button in the My Computers box.
    • Click Enable remote connections.

      If the Enable remote connections button does not appear on the screen, make sure that the ~/.chrome-remote-desktop-session file is created.

    • Enter a PIN.

    The Debian machine is now ready to accept remote connections. You should see its hostname - panther - listed in the My Computers box.

    If you encounter any connection error, please examine the log file - /tmp/chrome_remote_desktop_YYYYMMDD_HHMMSS_xxxxxx - for clues on what might have gone wrong.

Install and connect from Android

  1. Install the Chrome Remote Desktop app from Google Play onto your Android device.
  2. Open the app on the Android device.
  3. Click the hostname - panther - to remotely connect to it.
  4. Enter the PIN for authentication to the remote host.

    A virtual session is created.

Monday, July 28, 2014

Mix and match stable and testing releases in Debian

My Debian system runs the current stable Debian distribution Wheezy. However, there are software packages that are only available in the current testing distribution Jessie. Examples are dateutils, and Enlightenment 0.17. Too eager to wait for Jessie to become stable, and too lazy to build these packages from source, I used the apt-pinning technique to coerce APT, Debian's package manager, to install these packages on Wheezy.

Apt-pinning lets you mix and match the different distributions in a Debian release: stable, testing, and unstable. The steps below explain how to specify that all packages should be installed or updated from Wheezy (the stable version), with the exception of dateutils which we 'pin' to Jessie (the testing version).

Disclaimer: Apt-pinning is considered an advanced topic in Debian. Use at your own risk.

  1. Add testing to sources.list.

    The file /etc/apt/sources.list specifies the software releases you want and where to fetch them.

    Assuming that your sources.list file currently links to Wheezy only, it should resemble something like the following, notwithstanding the actual mirror site.

    deb http://deb.vanvps.com/debian/ wheezy main contrib non-free deb http://security.debian.org/ wheezy/updates main deb http://deb.vanvps.com/debian/ wheezy-updates main

    Append the following line to the file:

    deb http://deb.vanvps.com/debian/ jessie main contrib non-free
  2. Specify install priority preferences.
    • Create the file /etc/apt/preferences if it does not exist.

      This file specifies the priority preferences of which Debian version (e.g., testing vs stable) to install for packages.

    • Insert the following lines.
      Package: dateutils Pin: release n=jessie Pin-Priority: 750 Package: * Pin: release n=wheezy Pin-Priority: 700 Package: * Pin: release o=Debian Pin-Priority: -10

      Any package that is not named dateutils, and is not part of Wheezy is matched by the third section with a priority of -10. A negative priority means that the package will never be installed or upgraded. This entails that no package from Jessie other than dateutils will ever be installed or upgraded.

      When a newer version of dateutils becomes available in Jessie, dateutils will be updated. This is because the dateutils package is matched by the first section, which takes precedence over the third section.

      It is highly recommended that you read the man(5) page for apt_preferences to know more about setting preferences.

  3. Update APT repository.
    $ sudo apt-get update
  4. Install dateutils.

    The following command installs dateutils from testing, and also attempts to fulfill its dependencies from testing.

    $ sudo apt-get -t testing install dateutils

To upgrade your system, execute, as usual, sudo apt-get upgrade. dateutils is upgraded from Jessie while all other packages are upgraded from Wheezy.