Setting Up A Secure Subversion Source Code Repository

by Dan Ackerson on December 28, 2008 · 7 comments

Our source code repository is currently hosted at the offshore development site and there is no external access to it (neither through the Internet nor a VPN). While this is certainly desirable from a security standpoint, I’d really love to see what the developers are actually working on.

I asked the director there to put me on the mailing list for commits. He replied they didn’t have such a system since all the developers sat in the same room. Plus, the developers weren’t so thrilled about getting a bunch of commit mails in their inbox every day. I immediately thought what about vacation or sick leave? What about a lunch break? Are these guys really together 24/7? And how much work is it to setup a mail filter anyways?

I asked him how long it would take to set up mail notifications and he said he’d look into it. The next day, he told me that it wasn’t so straightforward to implement and what was my real reason for wanting this information anyways? Wait a minute, I thought, I’m flying completely blind here – with no clue what’s being worked on – and they’re not even willing to throw me a bone?

To resolve this I decided to create our own repository and migrate the source code from the offshore site. I’ll have complete control of the code then – able to setup permissions, branches, and email notifications. Plus, the new server will double as a continuous integration server when we’re ready for that step.

My requirements for a Subversion repository are fairly straightforward. It needs to be secure, fast and reliable. Initially, I took a look at some of the commercial providers (beanstalk, unfuddle and SVNRepository.com to name a few). But, as we are developing here in Europe, I was worried about lag times and network overhead going across the Atlantic Ocean. A self-hosting option here in Europe would not only be cheap, but, I’d eventually be able to set up my own continuous integration server.

So, I leased the cheapest possible virtual server from HostEurope for 13 EUR / month (including FTP backup). I get root access on a Debian 4 server, 256MB RAM and a 15GB harddisk partition. There’s no charge for upgrading (or downgrading) the virtual host environment so I’ll be able to upgrade with a button push when I’m ready for more RAM and horsepower. Let me show you how I set it up.

Installing Subversion

The base install instructions from subversionary.org worked right out of the box. I have a Debian 4.0 host and installed Subversion using apt-get:

sudo apt-get update
sudo apt-get install subversion subversion-tools

The subversion-tools package includes (among other things) some handy perl scripts which we’ll make use of later for our commit hooks.

Repository User Configuration

Now to create the svn user (without a login shell) who will own all the repository files, and the developers will be using the repository. We’ll add the developers directly to the svn group:

sudo useradd svn -s /bin/false
sudo useradd dan -G svn
sudo useradd mark -G svn
sudo useradd susie -G svn

Creating the Repository

I created the repository in /var/svn and assured the correct ownership:

sudo mkdir -p /var/svn
sudo svnadmin create /var/svn/repos
sudo chown -R svn.svn /var/svn

Securing the Server

We want the repository to be available only via ssh. As we’ll eventually disable password based authentication all together, let’s copy the public keys of the all users to their home directories:

scp id_dsa.dan.pub kis1.hosteurope.net:/home/dan/.ssh/authorized_keys

*nix folks won’t have a problem handing over a public key. For Windows users, point them to the standard PuTTy tools from Simon Tatham.

Now, let’s secure the sandbox for these accounts by specifying the ‘command’ option to run svnserve in each users’ authorized_keys file (as one line):

sudo vi /home/dan/.ssh/authorized_keys
  command="svnserve -t -r /var/svn/repos --tunnel-user=dan",
    no-port-forwarding,no-agent-forwarding,no-x11-forwarding,no-pty
    [dans-ssh-key]

The ‘-r /var/svn/repos’ parameter not only lets us hide the full path from the users, it restricts their access to just this repository – this basically becomes their root directory. The other options ensure there’s no funny business allowed with port forwarding or other types of connection attempts.

Initial Checkout

From your local machine, you should now be able to verify the availability of your secure subversion repository:

svn co svn+ssh://dan@kis1.hosteurope.net/ local-dev
  Revision 0.
svn info
  URL: svn+ssh://dan@kis1.hosteurope.net
  Repository Root: svn+ssh://dan@kis1.hosteurope.net
touch local-dev/test.txt
svn add local-dev/test.txt
  A local-dev/test.txt
svn ci -m "initial commit"
  Adding test.txt
  Transmitting file data .
  Committed revision 1.

Congratulations! You’ve verified read and write capabilities to your ssh secured repository. The basic install is done.

Now that you’ve also verified public key authentication works, you can further lock down your server by disabling ssh password authentication.

sudo vi /etc/sshd/ssh.conf
...
PasswordAuthentication no

**WARNING** Before you do this, ensure you’ve either created a separate admin account for yourself (including appropriate permissions in /etc/sudoers) or have placed your public key in the authorized_keys file of the root user (and that the root user is allowed to login as some systems have this disabled by default). Failing to do this will basically lock you out of your server if you’ve added the ‘command=”svnserve…’ option to your user account’s authorized_keys file!

Just restart your sshd daemon

sudo /etc/init.d/ssh restart

and you’ve made your server even more secure.

Next week, I’ll show you how to setup fine grained read-write permissions and generate email notifications per commit using built-in subversion hook scripts. Subscribe here so you won’t miss it!

Did you enjoy this article? Please subscribe to the RSS Feed to receive updates on Agile Methodologies & DevOps.

Related Posts

{ 7 comments… read them below or add one }

1 Ricardo Mestre December 29, 2008 at 11:15 am

Hi Dan,

Great article, and I’m looking forward to the second part of it! Thanks!

2 Dan Ackerson December 29, 2008 at 11:24 am

Hi Ricardo,

glad you liked it…was fun to research and write about it. Second part was even cooler ;) .

Wishing you a Happy New Year!

3 Ricardo Mestre December 30, 2008 at 10:08 pm

Hi Dan,

Thanks, and I wish you also a great 2009!

Greetings,

Ricardo

4 eric_88888888 February 26, 2009 at 10:50 am

Dear Dan,

great to see – took me a while to finish svn server – unfortunatly I did not found your page first.

A small article about svn hooks could be helpful – I am lost in there.

best regards,

eric

5 Dan Ackerson February 26, 2009 at 11:40 am

Hi Eric,

you’re absolutely right – I failed to backlink the subsequent article on svn hooks. I hope this helps you!

6 Naresh December 9, 2009 at 8:16 am

Hi All,

I want to deploy this simple ruby on rails application using capistrano, from local machine to unfuddle.com account. and I have account on unfuddle.. http://feeder.unfuddle.com/svn/feeder_fd

I have a local SVN Repository on my root path
/root/svn/#{application name},

This is my config/deploy.rb file..

set :application, “feeder2″
set :repository, “file:///root/svn/feeder2″ #here i dont know wht to put ???????????????????????? Do i need to put here this http://feeder.unfuddle.com/svn/feeder_fd or my local SVN repo ???????????

set :scm, :subversion
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`

role :web, “127.0.0.1:3000″ # Your HTTP server, Apache/etc
role :app, “127.0.0.1:3000″ # This may be the same as your `Web` server
role :db, “127.0.0.1:3000″, :primary => true # This is where Rails migrations will run
role :db, “127.0.0.1:3000″

set :deploy_via, :remote_cache

set :server_name, “http://feeder.unfuddle.com”

# If you are using Passenger mod_rails uncomment this:
# if you’re still using the script/reapear helper you will need
# these http://github.com/rails/irs_process_scripts

# namespace :deploy do
# task :start {}
# task :stop {}
# task :restart, :roles => :app, :except => { :no_release => true } do
# run “#{try_sudo} touch #{File.join(current_path,’tmp’,'restart.txt’)}”
# end
# end

How do I get this running ? I want to do it ASAP, Can u please help me,

and ya wht is the meaning of this statement ??
svn co svn+ssh://dan@kis1.hosteurope.net/ local-dev

let me correct if i m wrong ?
1) dan is username,,but which username? username of repo account of unfudlle ???
2) kis1.hosteurope.net is subdomain like mine is feeder.unfuddle.com ???

and after doing this ? How to deploy an application using cap deploy:setup, :check or anything else ????

Awating for Reply

Naresh

7 Matthias Marschall December 9, 2009 at 9:31 am

woah, Naresh, wait a minute. You’re mixing up everything here. Let me try to sort it out for you:
First of all, you cannot deploy your app to unfuddle.com. Unfuddle.com is your SVN repository – the place where your code lives. AFAIK, they do not provide any hosting space for deploying your applications. Your deploy.rb shows that you want to deploy to localhost. That sounds ok. When you use unfuddle.com as your SVN repository, you do not need a local one. You let capistrano check out your app from the unfuddle repo to your local server.

That said, you should set your unfuddle SVN repo in your deploy.rb file as the :repository.
When defining roles, you must not use any port numbers (:3000 in your case).
The :server_name is the name of the host you want to deploy your application to – in your case: localhost.

And last but not least, you do not have to care too much about that svn co statement as capistrano will do the checkout from unfuddle to your localhost for you.
Hope this helps to get you back on track.

Leave a Comment