Subversion Security for Teams

I’ve already ranted about why I still use SVN instead of Git. That said, it isn’t always obvious how to set up an SVN server securely, especially if you want fine-grained access control so certain users only get access to certain repositories or projects within repositories. It’s actually pretty easy with a few clever tricks.

My Requirements

  • Lightweight server – you shouldn’t need a lot of resources. In general, I run subversion in a proxmox VM with 2GB of RAM allocated and 1 processor core. I use minimal Ubuntu server as the OS.
  • Server access must only be via ssh. These days, nothing should be accessible over the internet that doesn’t use ssh and public key security.
  • The server should support multiple repositories.
  • You should be able to restrict user access to certain repositories and also specific projects (folders) within a given repository.
  • Disaster recovery should be easy.

How To Do It

1. Setup the server VM

  • Download the Ubuntu Server iso and store it in the /var/lib/vz/template/iso folder of your Proxmox host machine (if you don’t use proxmox, you probably should).
  • Create a Proxmox VM with 2GB RAM, 32GB disk space, and 1 CPU core which should be sufficient and select the Ubuntu ISO.
  • During installation, select the minimal install; it has nearly everything you’ll want and installing more things is easy using apt.
  • During installation, enable openssh access and create your superuser account.
  • Once installed update and upgrade as usual.
  • Install your public key in your home/myUser/.ssh/authorized_keys file. If you’re not familiar with how to do this, see here.
  • Once you have confirmed that your public key login is working, disable root login and password access in /etc/ssh/sshd_config.

2. Install Subversion and tools

  • Install subversion from the ubuntu repo
    sudo apt-get install subversion
  • Install your favorite editor any other tools you might want (vim, iputils-ping, etc.)

3. Create Subversion User and Repository

  • Create a user named “svn”
    sudo adduser svn
  • Create a folder to hold your SVN repositories:
    sudo mkdir /srv/svn
  • Assign ownership of the SVN repository to the svn user
    sudo chown svn:svn /srv/svn
  • Create an SVN repository:
    sudo svnadmin create /srv/svn/myRepo
  • Make sure the entire new repo is owned by the svn user:
    sudo chown -R svn:svn /srv/svn/myRepo

4. Setup SSH access

  • Create folder /home/svn/.ssh (should have 700 privilege)
  • Create file /home/svn/.ssh/authorized_keys (should have 600 privilege)
  • Add the SSH public key(s) for your workstation(s) to the authorized_keys file.
  • In front of each key add (so this and the key are all on one line):
    command=”svnserve -r /srv/svn/myRepo -t –tunnel-user=myUserName”
    An example of two lines in the file might be:
    command=”svnserve -r /srv/svn/ -t –tunnel-user=bob” ecdsa-sha2-nistp521 <Bob’s ECC public key>== BobLaptop1
    command=”svnserve -r /srv/svn/myRepo -t –tunnel-user=alice” ssh-rsa <Alice’s public RSA key>== AliceContractorPC
  • You will probably want other options in addition to the command option to keep things locked down. All options should be comma-separated with no spaces unless within double-quotes; options you might want after the command option might include:
    ,no-port-forwarding,no-agent-forwarding,no-pty,no-X11-forwarding
    So a full line for alice might look like:
command="svnserve -r /srv/svn/myRepo -t --tunnel-user=alice",no-port-forwarding,no-agent-forwarding,no-pty,no-X11-forwarding <Alice's public RSA key>== AliceContractorPC

5. Setup SVN fine-grained User Authorization

  • Edit /srv/svn/myRepo/conf/svnserve.conf
    anon-access=none
    auth-access=write
    authz-db = authz
  • Edit /srv/svn/myRepo/conf/
    [/]
    unrestrictedUserName = rw
    [/projectA]
    restrictedUserName = rw
  • This sets up an unrestricted user with complete access to all projects in myRepo
    and a restricted user who only has access to projectA within my Repo
    SVN authz supports groups for very flexible permissions:
    [groups]
    myGroup = userA, userB
    [/projectB]
    @myGroup = rw

Users will always access the server as user svn. The trick is in the authorized_keys file which will choose the right SVN username based on the public key that matched your login. So when Bob logs in, he will use his private key (which will match his public key in the authorized_keys file which will also assign his –tunnel-user name to “bob” (for example). When Alice logs in, she will use her private key (which will match her public key in the authorized_keys file which will also assign her –tunnel-user name to “alice” (for example). SVN will further restrict their access within each repository according to their tunnel-user name in the authz file(s).

Some nifty things to note:

  • You don’t have to create linux login users for bob and alice. In fact the only users who should have login shell access are you (your super-user account) and svn and they should only have public key access (no password login should be allowed).
  • When bob and/or alice login as the svn user, they only get access to SVN
    (the only command they can run is svnserve per the authorized_keys file).
  • You can restrict bob or alice to a specific repo in the authorized_keys file by setting their svn “root” using the -r parameter. So, for example for alice:
    command=”svnserve -r /srv/svn/myRepo -t –tunnel-name=alice”
    Alice is then restricted to the myRepo repository and may be further restricted by the authz file for that repository based on her tunnel-name to limit her to specific projects. She will not even know that there are other repos; all references to projects will be relative to the root, so for example she might checkout:
    svn+ssh://svn@myhost.mydomain.com/myProject
    Where myProject is in myRepo and Alice would not know about myRepo2.
  • You can implement fine-grained restrictions within each repository using the authz mechanism. You can read about that in detail here.
  • To access the server (e.g. from TortoiseSVN or your favorite SVN client), you access using the svn+ssh protocol with a URL like this:
    svn+ssh://svn@myhost.mydomain.com
    Your private key will grant you access as the svn user and determine which user SVN treats you as for security purposes.

Backups

Although you can always backup your repo(s) using the svn dump facility:
svnadmin dump /srv/svn/myRepo | bzip2 > myRepo_dump-$(date +%Y%m%d).svn.bz2
That only backs up the repository itself; it doesn’t backup all the work you did above to setup logins and permissions.

IMO, it’s much better for disaster recovery to simply backup your entire SVN server using proxmox. That way, you can stand up a new proxmox machine, restore the backup, and you’re up and running in a few minutes!