Jailing SSH

There are a lot of potential reasons to run sshd in a jail. Doing so can be an alternative to ugly hacks such as scponly shells, or can provide a safe shell login environment.

While configuring sshd to run in a jail isn't terribly difficult, it's not terribly straight forward either. There's really no reason to run an entire jail with all services just to get keep a login process imprisoned

Note that you can use the same process described here to create "lightweight" jails running almost any process. We have done so with Apache and Squid to date, just to name a few.

  1. Create the jail environment

    I recommend the use of the ezjail port here, as it simplifies the management and creation of jail environments. You can also follow the instructions in the jail man page to do it the manual way.

    If you're starting from scratch, you can follow these steps:

    1. Install ezjail from ports:
      cd /usr/ports/sysutils && make install clean
    2. Edit /usr/local/etc/ezjail.conf to your liking.
    3. Create the ezjail base environment:
      ezjail-admin update

    That only needs done once per host system. Use ezjail-admin to create individual jails:

    ezjail-admin create JAILNAME JAILIP

  2. Tweak rc.conf so sshd starts: sshd does not start by default. This will get it going:

    1. Start the jail:
      /usr/local/etc/rc.d/ezjail start <JAILNAME>
    2. Find out what jail ID is assigned to your jail:
      jls
    3. Manually start a shell in the jail (JID is the id you found in the previous step):
      jexec <JID> /bin/sh

      Note that you can also use my jailme program for this.

    4. You are now logged into the jail as root.
    5. Manuall fire up sshd:
      /etc/rc.d/sshd forcestart
    6. Type lots of garbage so sshd can generate keys.
    7. use logout or CTRL-D to exit the jail.
    8. Your jail is still running, stop the ezjail instance
      /usr/local/etc/rc.d/ezjail.sh stop <JAILNAME>
  3. Configure the jail to start as lightweight as possible

    In /usr/local/etc/ezjail/JAILNAME, there will be a variable set to "/bin/sh /etc/rc". Change the value to "/usr/sbin/sshd"

  4. Set up somewhere for log information to go

    With no syslog running in the jail, sshd's log messages will disappear into the bit bucket. If you use syslog-ng, you can configure a single syslog daemon to gather log messages from all your sshd jails and put them in the host's logs. Near the beginning of your syslog-ng.conf, you'll see a structure something like this:

    source src { unix-dgram("/var/run/log");
                 unix-dgram("/var/run/logpriv" perm(0600));
                 internal(); file("/dev/klog");
               };
    

    For each jail you create, add two lines to allow it to listen for log messages. for example, if my jail is in /jails/firstjail, I would change the above config to:

    source src { unix-dgram("/var/run/log");
                 unix-dgram("/var/run/logpriv" perm(0600));
                 internal(); file("/dev/klog");
                 unix-dgram("/jails/firstjail/var/run/log");
                 unix-dgram("/jails/firstjail/var/run/logpriv" perm(0600));
               };