Friday, February 17, 2012

Setting up a Subversion Repository for a Small Team

Most organizations that use Subversion for source control set up an Apache server in front of the repository. For a small team, this can be daunting, especially if nobody on the team has experience running and configuring Apache. Even in a larger organization, with experienced Apache admins, I question the benefit. Especially if you rely on Apache's built-in authentication mechanism, which involves keeping a private list of Subversion users, separate from your organization's main user list. One that's unlikely to get updated every time someone joins or leaves the organization.

There is an alternative: Subversion comes with the svnserve server, which listens on port 3690, and speaks it's own protocol with Subversion clients. It's deceptively easy to use:

# on the server
svnserve -d -r /opt/svn/repo/

# and on the client ...
svn co svn://localhost workdir

But there are several problems with running svnserve like this. First, you manually started the server, and you have to restart it if the system ever goes down. While you can configure inetd to automatically start the server, that adds a task for your sysadmins. And unless your developers are also your sysadmins, this will take time and may be a point of contention.

A bigger problem is that running svnserve in this way means that all commits are anonymous. The output of svn annotate will be meaningless, but worse, anybody that can physically access your repository will be able to update it. Clearly, you wouldn't want to expose this repo through the corporate firewall. And while svnserve provides several options for authentication, they take you back to a second user database.

But there's an alternative: identify the repository using a svn+ssh URL. This tells a client to open an SSH connection to the server, and run svnserve over that connection.

svn co svn+ssh://localhost/opt/svn/repo workdir

There is a lot to recommend this approach. First, it uses the server's own user database for authentication and authorization; no more anonymous commits. Second, system administrators are a lot more willing to open the SSH port to the outside world, rather than some custom server that has unknown security holes. Third, an experienced user can set up public key authentication, making the whole login process transparent.

The biggest drawback to running Subversion in this way is that, because each user connects as him or herself, all users need to be able to physically write files in the Subversion repository. In a small team, where everybody knows everybody else, I don't see this as a big issue. However, if you're concerned about security, you can take the following steps:

  • Use a dedicated host for the Subversion repository, and configure SSH to limit “ordinary” users to only run svnserve (you'll still need full access for admins).
  • Create a “subversion” user group — or, for larger teams, a project group “ and assign it to the people who are to have access.

Once you've created the repository, you need to grant write permissions on some of the files in it. Assuming that you're creating repositories in the /opt/svn directory, and have a subversion group, here are the commands to set up your repository (run by root):

cd /opt/svn
svnadmin create repo

# there are some files in the repository that get created from the first commit;
# having root create the standard trunk/tags/branches layout gets you that commit

svn co file://`pwd`/repo working
cd working
svn mkdir trunk
svn mkdir tags
svn mkdir branches
svn commit -m "create initial structure"
cd ..
rm -rf working

# now we can modify the actual repository 

chgrp -R subversion repo
cd repo/db
chmod g+w .
chmod -R g+w current min-unpacked-rev rep-cache.db revprops revs transactions txn-* write-lock

If you've changed all the files correctly, running ls -al on the /opt/svn/repo/db directory should show you this:

total 56
drwxrwsr-x 6 root subversion 4096 Feb 11 22:02 .
drwxr-xr-x 6 root subversion 4096 Feb 11 21:53 ..
-rw-rw-r-- 1 u1   subversion    2 Feb 11 22:02 current
-r--r--r-- 1 root subversion   22 Feb 11 21:53 format
-rw-r--r-- 1 root subversion 1920 Feb 11 21:53 fsfs.conf
-rw-r--r-- 1 root subversion    5 Feb 11 21:53 fs-type
-rw-rw-r-- 1 root subversion    2 Feb 11 21:53 min-unpacked-rev
-rw-rw-r-- 1 root subversion 4096 Feb 11 21:54 rep-cache.db
drwxrwsr-x 3 root subversion 4096 Feb 11 21:53 revprops
drwxrwsr-x 3 root subversion 4096 Feb 11 21:53 revs
drwxrwsr-x 2 root subversion 4096 Feb 11 22:02 transactions
-rw-rw-r-- 1 u1   subversion    2 Feb 11 22:02 txn-current
-rw-rw-r-- 1 root subversion    0 Feb 11 21:53 txn-current-lock
drwxrwsr-x 2 root subversion 4096 Feb 11 22:02 txn-protorevs
-rw-r--r-- 1 root subversion   37 Feb 11 21:53 uuid
-rw-rw-r-- 1 root subversion    0 Feb 11 21:53 write-lock

No comments: