Setting Up A Secure Subversion Source Code Repository

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!

11 thoughts on “Setting Up A Secure Subversion Source Code Repository

  1. 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

    Like

  2. 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

    Like

  3. 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.

    Like

  4. Hi Dan,

    I am having trouble with…

    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]

    Can you explain a little about what is going on here, as when I run this vi seems to be trying to open 5 files. Also what is supposed to be in the place of [dans-ssh-key] is it the key iteself?

    Any help would be appreciated.

    Gary

    Like

  5. The idea here is twofold. First, we will only allow the user access to the system with public/private key exchange. Second, by editing the user’s authorized_keys file ( i.e. /home/dan/.ssh/authorized_keys ), we drastically limit the commands they are able to execute on the remote server. In the example I gave above, exactly one: ‘svnserve’.

    /var/svn/repos was the directory where my svn server repository lived. The no forwarding params effectively shutdown the possibility for any monkey business on this server for the user. Their only interaction will be with subversion. And yes, [dans-ssh-key] is the user’s public key, to be entered with a space delimiter after the ‘no-pty’ param in my example above.

    I’ve updated the format of the post to hopefully better communicate my idea, so take another look at that sample code.

    Like

  6. Hi Dan,
    Nice to see this. Any tips or pointers or links for me to secure the SVN Sever hosted on Ubuntu (or any specific version of Linux) with LDAP Authentication ?

    Thanks

    VC

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.