Fedora Core 3: Running CVS in a chroot Jail
permalinkSetting up a CVS server on a Unix system usually means that you either run CVS in its insecure :pserver:
mode or run it over SSH, requiring that the CVS users have a shell account and consequently, full access to your system. The concept of a “chroot jail” is an essential part of isolating remote service users from remote system administrators.
Thanks to the magic of pam_chroot
, you can host a full-featured, encrypted and secure CVS server on any server with SSH. Users are able to connect to CVS via SSH but are denied access to any sort of command-line.
pam_chroot
is part of the standard PAM modules. It consults /etc/security/chroot.conf
for a list of users to be chroot
jailed:
# /etc/security/chroot.conf
# format:
# username_regex chroot_dir
someuser /home/chroot_directory
This entry indicates that whenever the user “someuser” logs in, they are to be shuttled off into the virtual root /home/chroot_directory
. They will only have access to commands and libraries available within that virtual root.
A default-configured Fedora Core 3 system won’t have chroot
in place out-of-the-box. We need to tell the system that whenever the user logs in via SSH, they should first be authenticated and then dropped into the chroot
jail if we’ve set them up in chroot
.conf. This is done by editing the /etc/pam.d/sshd
entry and adding the pam_chroot.so
entry:
#%PAM-1.0
auth required pam_stack.so service=system-auth
auth required pam_nologin.so
account required pam_stack.so service=system-auth
password required pam_stack.so service=system-auth
session required pam_selinux.so
session required pam_stack.so service=system-auth
session required pam_limits.so
session required pam_chroot.so
session optional pam_console.so
Once the user has authenticated via the system authentication stack the chroot
will take effect. Note that the remainder of PAM authentication is beyond the scope of this article. Consult the pam man-page and system documentation for more information.
The final step to enabling chroot
on SSH is disabling privilege seperation in the SSH daemon. Privilege seperation is part of the SSH secure design that drops root access in certain parts of the application that don’t need it. Since the chroot
system call requires root access, we need to disable this part of the system. This is done by editing the /etc/ssh/sshd_config
file and adding the line:
UsePrivilegeSeparation no
You’ll need to restart SSH to let it pick up the configuration change.
servive sshd restart
Now that the chroot
setup is complete, we need to build the chroot
jail. You’ll need to determine exactly what your users will need within the jail and copy those files only. Make sure that you’ve got the cvs package installed before following these steps.
The following steps are inspired by the information provided by Julio Merino for a similar setup in NetBSD:
# Create the CVS chroot directory
mkdir -p /var/chroot/cvs
# Create the required root directories
cd /var/chroot/cvs
mkdir -p bin cvs dev etc home lib sbin tmp var
# Link the usr directory to the root
ln -s . usr
# Set the appropriate permissions on cvs and tmp
chmod 770 cvs
chmod 1777 tmp
We’ll now copy the required binaries to the chroot
jail:
cp /bin/sh bin/sh
cp /bin/ls bin/ls
cp /usr/bin/cvs bin/cvs
Note that CVS will need /dev/null
too, so we’ll copy it:
cp -a /dev/null dev/null
We can then run a single command to populate the required libraries for the binaries we installed. This command is handy to keep around (also from Julio Merino’s article). You’ll see some warnings about duplicate libraries and invalid files that appear as hex numbers - these are harmless garbage from the ldd output:
cp `ldd bin/* sbin/* | awk '{print $3}'` lib
At this point, the CVS chroot
should be complete. You can test it using the chroot
command as root:
chroot /var/chroot/cvs bin/ls -l
drwxr-xr-x 2 0 0 4096 Nov 15 04:09 bin
drwxrwx--- 2 0 0 4096 Nov 15 04:07 cvs
drwxr-xr-x 2 0 0 4096 Nov 15 04:08 dev
drwxr-xr-x 2 0 0 4096 Nov 15 04:07 etc
drwxr-xr-x 2 0 0 4096 Nov 15 04:08 lib
drwxr-xr-x 2 0 0 4096 Nov 15 04:07 sbin
drwxrwxrwt 2 0 0 4096 Nov 15 04:07 tmp
lrwxrwxrwx 1 0 0 1 Nov 15 04:07 usr -> .
drwxr-xr-x 2 0 0 4096 Nov 15 04:07 var
chroot /var/chroot/cvs bin/cvs
Usage: cvs [cvs-options] command [command-options-and-arguments]
where cvs-options are -q, -n, etc.
(specify --help-options for a list of options)
where command is add, admin, etc.
(specify --help-commands for a list of commands
or --help-synonyms for a list of command synonyms)
where command-options-and-arguments depend on the specific command
(specify -H followed by a command name for command-specific help)
Specify --help to receive this message
The Concurrent Versions System (CVS) is a tool for version control.
For CVS updates and additional information, see
the CVS home page at http://www.cvshome.org/ or
Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html
If you received any errors about missing libraries or the like, copy them by hand to the lib directory in your chroot
jail.
We’re now ready to create our CVS users. First thing we’ll do is create a group for them all to belong to:
groupadd cvsusers
Now add your CVS users, making their default group cvsusers
. We’ve added a default shell that we’ll use later. The home directory for this user, /home/cvsuser1
by default, will still exist in the root filesystem. You can use this directory for setting SSH keys if you prefer to log in using private key authentication instead of passwords. For now, use the passwd command to set the appropriate passwords for each user you’re adding:
# Create the user with a default group of "cvsusers"
useradd -g cvsusers -s /sbin/nologin cvsuser1
# Create the alternate home directory in the chroot jail
mkdir /var/chroot/cvs/home/cvsuser1
# Set the user's password
passwd cvsuser1
# Add the user to the PAM chroot configuration
echo cvsuser1 /var/chroot/cvs >> /etc/security/chroot.conf
Once you’ve added the appropriate users for your CVS, copy your /etc/group
and /etc/passwd
files to the jail and remove all lines but those of your cvs users:
cp /etc/passwd etc/passwd
cp /etc/group etc/group
Set the group ownership of the cvs directory to your new cvsusers
group:
chown .cvsusers cvs
Next, we’ll copy the files required for reverse lookups of uid/gid to username/groupname. Without this, CVS will end up with entries like uid750
in its history. It’s also the reason that zeroes appear instead of root for the username/groupname in the ls -l
command we tested above. Note that reverse lookups are handled within glibc using the name switch server (NSS) and the default lookup source is the passwd/group files:
cp -a /lib/libnss*files* lib
Now, you should be able to see the reverse lookup for cvsusers in your chroot
jail. If not, check to make sure that all of the required nss files were copied over.
chroot /var/chroot/cvs bin/ls -dl cvs
drwxrwx--- 2 0 cvsusers 4096 Nov 15 04:07 cvs
We’re going to create the default shell nologin
we assigned to each of the CVS users above. By running the only allowed command explicitly, we prevent the users from logging in or running any other command. Since the file is being created as nologin, we can ensure that they wouldn’t be able to log in to the root filesystem if the chroot
failed in any way. Create this file as nologin
in the chroot
’s sbin
directory:
#!/bin/sh
/bin/cvs server
Now make it executable with chmod
:
chmod +x /var/chroot/cvs/sbin/nologin
All of the required system files have been copied over, so we can now create our CVS repository:
chroot /var/chroot/cvs bin/cvs -d /cvs init
chown .cvsusers /var/chroot/cvs/cvs/CVSROOT
You should be able to log in to cvs via SSH and test your CVS server before we lock it down. Don’t forget to set passwords for your CVS users or SSH won’t let them in:
cd /tmp
CVS_RSH=ssh cvs -d:ext:cvsuser1@localhost:/cvs checkout CVSROOT
cvs checkout: Updating CVSROOT
U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg
If you can grab the files from the CVSROOT
directory, you’ve successfully created a chroot
-jailed CVS server. To test the security of this setup, try a few things to break it:
ssh localhost -l cvsuser1
cvsuser1@localhost's password: ****
Connection to localhost closed.
ssh localhost -l cvsuser1 bin/ls
cvsuser1@localhost's password:
< it hangs up here in cvs server mode, hit ctrl-c to kill this >
Killed by signal 2.
sftp cvsuser1@localhost
Connecting to localhost...
cvsuser1@localhost's password:
< it hangs up here in cvs server mode, hit ctrl-c to kill this >
Killed by signal 2.
Remember each of the steps above for adding new CVS users. Congratulations, your CVS server is now secure!
Read full post