Subversion over SVN+SSH on Debian ++++++++++++++++++++++++++++++++++++ :Posted: 2007-12-04 17:02 :Tags: Debian, Hosting The traditional way of setting up subversion is via Apache but what if you don't want to install Apache? In that case you can use ``svnserve`` but what if your host won't let you run a persistant server? In that case you can create a linux system account for every user and give them induvidual SSH logins. You then give your users a URL starting ``svn+ssh://`` instead of the usual ``http://``. The Subversion client recognises this form of URL and invokes a local ssh process, connecting to the host, authenticating as the user, then spawning a private ``svnserve`` process on the remote machine running as that user. The ``svnserve`` command is being invoked in tunnel mode (-t) and its network protocol is being tunneled over the encrypted connection by ``ssh``, the tunnel-agent. ``svnserve`` is aware that it's running as the user, and if the client performs a commit, the authenticated username will be attributed as the author of the new revision. This is all well and good but you might not wa nt to have to create user accounts for each of the users you want to give access to subversion. In this case you can create one system user account and use a different SSH private key for each user you want to grant access to. You then setup the ``~/.ssh/authorized_keys`` file so that each user only has access to ``svnserve`` and that each ``svnserve`` process is started with their particular username so that all the commits are handled correctly. This is only possible with subversion 1.1.0 and above. This is what we are going to do for two users, ``james`` and ``mike``. ``james`` is a linux user, ``mike`` is a Windows user. First let's setup the server:: sudo apt-get install subversion openssh-server Then create a subversion user ``svn``, a home directory, an ``.ssh`` directory and finally set the correct permissions:: sudo useradd svn sudo mkdir /home/svn sudo mkdir /home/svn/.ssh sudo chown -R svn:svn /home/svn If you intend to be able to login as ``svn`` for testing purposes later you should set a password:: sudo passwd svn Create the directory for the repositories:: sudo mkdir /var/svn Setup a ``repo`` repository and commit the first import:: sudo mkdir /var/svn/repo sudo mkdir /tmp/repo sudo mkdir /tmp/repo/branches sudo mkdir /tmp/repo/tags sudo mkdir /tmp/repo/trunk sudo svnadmin create /var/svn/repo sudo svn import /tmp/repo file:///var/svn/repo -m "initial import" sudo rm -rf /tmp/repo Change the permissions so that the svn user and svn group have access:: sudo chown -R svn:svn /var/svn/repo Set the permissions to 770 and the umask to 2 so that any files are created have the correct permissions:: sudo chmod 2770 -R /var/svn/repo At this point you can test the setup manually. As a user other than ``svn`` try this:: svn co svn+ssh://svn@localhost/var/svn/repo . This should prompt you for the password a couple of times and then checkout the repository. We are half way there, next we need to set up two SSH public-private key pairs, one for Mike, one for James. As the ``svn`` user run:: ssh-keygen -t rsa -b 1024 -f mike.key ssh-keygen -t rsa -b 1024 -f james.key With each command you can just press ```` twice unless you want to set a password. You will now have the files ``mike.key``, ``mike.key.pub``, ``james.key`` and ``james.key.pub`` in the current directory. The ``.key`` files are the private keys. They should be given securely to Mike and James repsectively. Anyone who gets hold of the files will have the same permissions to the repository as James and Mike so they should be treated with the same respect as a password and not posted online! Since Mike is on Windows he will need `WinSCP `_, `PuTTY `_, `PuTTYgen `_ and `TortoiseSVN `_ (the latter requires adminsitrator access to install). Here's what he does: * Use WinSCP to copy the ``mike.key`` file to his desktop if he didn't recieve it any other way * Open PuTTYgen and from the ``Conversions`` menu, select ``Import``, then browse to and select ``mike.key``. Leave the passphrase boxes blank and select ``Save private key``. Click ``Yes`` on the confirmation box, and save the key with a ``.ppk`` extension, like ``mike.ppk``. This is now a key that PuTTY can use. * Start PuTTY again. Fill out the hostname box, then scroll down to SSH > Auth. Browse for the ``mike.ppk`` file. Then go back up to Sesson, give the session a name (for example ``mike``) and save it. Test by logging in with the username ``ssh``. You should see something like this:: login as: svn Authenticating with public key "imported-openssh-key" ( success ( 1 2 ( ANONYMOUS EXTERNAL ) ( edit-pipeline svndiff1 absent-entries ) ) ) * With this in place you can set up TortoiseSVN with the key, [I haven't tested this next bit yet] First, create a new folder, then right-click it and select SVN Checkout. In the dialog box, enter this in the URL field ``svn+ssh://svn@mike/var/svn/repo``. ``svn+ssh`` is how TortoiseSVN will access your server, ``svn@mike`` is your credentials for logging in (mike is the session we set up using the keys in PuTTY), and ``/var/svn/repo`` is where the repository is located on the server. Later on in this tutorial we'll configure the server so this can be accessed as ``svn+ssh://svn@mike/repo``. From James's point of view the process is a bit simpler becasue on Linux the ``.key`` file doesn't need to be converted to a ``.ppk`` file: * Create a ``~/.ssh`` directory:: mkdir ~/.ssh * Copy the private key to ``~/.ssh/id_dsa`` you don't already have it:: scp svn@example.com:/home/svn/james.key ~/.ssh/id_dsa Now that the private keys are set up it is time to setup the public keys on the subversion server. Copy the contents of ``mike.key.pub`` and ``james.key.pub`` to ``/home/svn/.ssh/authorized_keys`` so that the each publick key is on a separate line:: touch .ssh/authorized_keys cat mike.key.pub >> .ssh/authorized_keys cat james.key.pub >> .ssh/authorized_keys It should look something like this but with lots of characters in place of ``...``:: ssh-rsa AAA...acFHU= svn@example ssh-rsa AAA...acBDH= svn@example The three columns are TYPE KEY COMMENT. Since the last part is a comment it makes sense to change it to the names of the users so you remember which line referrs to who:: ssh-rsa AAA...acFHU= mike ssh-rsa AAA...acBDH= james This is all well and good but at the moment Mike and James can also SSH directly into the ``svn`` account so we want to restrict their access. Each line in the ``authorized_keys`` file can also have a ``command="COMMAND"`` section at the start. The subversion client executes ``svnserve -t`` when it SSHs in but you can also specify the executable to use explicitly:: command="/usr/bin/svnserve -t" ssh-rsa AAA...acFHU= mike command="/usr/bin/svnserve -t" ssh-rsa AAA...acBDH= james Now you might want to limit the users to a particular repository, you can do this with the ``-r`` option:: command="/usr/bin/svnserve -t -r /var/svn/" ssh-rsa AAA...acFHU= mike command="/usr/bin/svnserve -t -r /var/svn/" ssh-rsa AAA...acBDH= james James and Mike can access the ``repo`` repository with ``svn+ssh://svn@localhost/repo`` instead of ``svn+ssh://svn@localhost/var/svn/repo`` You will probably want to limit the other things the users can do with the ``svn`` account so you'd probably add ``no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding`` to the command like this:: command="/usr/bin/svnserve -t -r /var/svn/",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding ssh-rsa AAA...acFHU= mike command="/usr/bin/svnserve -t -r /var/svn/",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding ssh-rsa AAA...acBDH= james So far, the ``svnserve`` command still doesn't know which username it is supposed to be using so we add the ``--tunnel-user`` option to tell it explicitly:: command="/usr/bin/svnserve -t -r /var/svn/ --tunnel-user=mike",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding ssh-rsa AAA...acFHU= mike command="/usr/bin/svnserve -t -r /var/svn/ --tunnel-user=james",no-port-forwarding,no-pty,no-agent-forwarding,no-X11-forwarding ssh-rsa AAA...acBDH= james At this point everything should now work as expected. Both James and Mike should be able to access and commit to the repository without needing a password and their commits should be logged as ``james`` and ``mike`` respectively because they are using different private keys and we are using the ``--tunnel-user`` approach. No other users should be able to access the repository except the ``svn`` user if you know the password. Further reading: http://svnbook.red-bean.com/en/1.1/ch06s03.html http://allyourtech.com/content/articles/23_12_2005_setting_up_subversion_and_tortoisesvn.php http://allyourtech.com/content/articles/24_12_2005_ditching_the_password_prompts_in_tortoisesvn.php http://svn.collab.net/repos/svn/trunk/notes/ssh-tricks http://svn.haxx.se/dev/archive-2004-03/0253.shtml http://bitworking.org/news/Getting_subversion_svn_ssh____to_work_with_PuTTY http://www.linuxfromscratch.org/blfs/view/svn/server/svnserver.html For testing it is also possible to set the ``$SVN_SSH`` variable specifying the private key to use with ``-i`` so that you can try connecting as different users. For example:: export SVN_SSH="ssh -i /home/james/.ssh/mike.key