Tunneling over SSH
svnserve's built-in authentication can be very handy, because it avoids the need to create real system accounts. On the other hand, some administrators already have well-established SSH authentication frameworks in place. In these situations, all of the project's users already have system accounts and the ability to “SSH into” the server machine.
It's easy to use SSH in conjunction with svnserve. The client simply uses the svn+ssh://
URL schema to connect:
$ whoami
harry
$ svn list svn+ssh://host.example.com/repos/project
harry@host.example.com's password: *****
foo
bar
baz
…
In this example, the Subversion client is invoking a local ssh process, connecting to host.example.com
, authenticating as the user harry
, then spawning a private svnserve process on the remote machine running as the user harry
. 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 harry
, and if the client performs a commit, the authenticated username will be attributed as the author of the new revision.
The important thing to understand here is that the Subversion client is not connecting to a running svnserve daemon. This method of access doesn't require a daemon, nor does it notice one if present. It relies wholly on the ability of ssh to spawn a temporary svnserve process, which then terminates when the network connection is closed.
When using svn+ssh://
URLs to access a repository, remember that it's the ssh program prompting for authentication, and not the svn client program. That means there's no automatic password caching going on (see the section called “Client Credentials Caching”). The Subversion client often makes multiple connections to the repository, though users don't normally notice this due to the password caching feature. When using svn+ssh://
URLs, however, users may be annoyed by ssh repeatedly asking for a password for every outbound connection. The solution is to use a separate SSH password-caching tool like ssh-agent on a Unix-like system, or pageant on Windows.
When running over a tunnel, authorization is primarily controlled by operating system permissions to the repository's database files; it's very much the same as if Harry were accessing the repository directly via a file://
URL. If multiple system users are going to be accessing the repository directly, you may want to place them into a common group, and you'll need to be careful about umasks. (Be sure to read the section called “Supporting Multiple Repository Access Methods”.) But even in the case of tunneling, the svnserve.conf
file can still be used to block access, by simply setting auth-access = read
or auth-access = none
. [43]
You'd think that the story of SSH tunneling would end here, but it doesn't. Subversion allows you to create custom tunnel behaviors in your run-time config
file (see the section called “Runtime Configuration Area”). For example, suppose you want to use RSH instead of SSH. In the [tunnels]
section of your config
file, simply define it like this:
[tunnels]
rsh = rsh
And now, you can use this new tunnel definition by using a URL schema that matches the name of your new variable: svn+rsh://host/path
. When using the new URL schema, the Subversion client will actually be running the command rsh host svnserve -t behind the scenes. If you include a username in the URL (for example, svn+rsh://username@host/path
) the client will also include that in its command (rsh username@host svnserve -t). But you can define new tunneling schemes to be much more clever than that:
[tunnels]
joessh = $JOESSH /opt/alternate/ssh -p 29934
This example demonstrates a couple of things. First, it shows how to make the Subversion client launch a very specific tunneling binary (the one located at /opt/alternate/ssh
) with specific options. In this case, accessing a svn+joessh://
URL would invoke the particular SSH binary with -p 29934
as arguments—useful if you want the tunnel program to connect to a non-standard port.
Second, it shows how to define a custom environment variable that can override the name of the tunneling program. Setting the SVN_SSH
environment variable is a convenient way to override the default SSH tunnel agent. But if you need to have several different overrides for different servers, each perhaps contacting a different port or passing a different set of options to SSH, you can use the mechanism demonstrated in this example. Now if we were to set the JOESSH
environment variable, its value would override the entire value of the tunnel variable—$JOESSH would be executed instead of /opt/alternate/ssh -p 29934.
SSH configuration tricks
It's not only possible to control the way in which the client invokes ssh, but also to control the behavior of sshd on your server machine. In this section, we'll show how to control the exact svnserve command executed by sshd, as well as how to have multiple users share a single system account.
Initial setup
To begin, locate the home directory of the account you'll be using to launch svnserve. Make sure the account has an SSH public/private keypair installed, and that the user can log in via public-key authentication. Password authentication will not work, since all of the following SSH tricks revolve around using the SSH authorized_keys
file.
If it doesn't already exist, create the authorized_keys
file (on Unix, typically ~/.ssh/authorized_keys
). Each line in this file describes a public key that is allowed to connect. The lines are typically of the form:
ssh-dsa AAAABtce9euch… user@example.com
The first field describes the type of key, the second field is the uuencoded key itself, and the third field is a comment. However, it's a lesser known fact that the entire line can be preceded by a command
field:
command="program" ssh-dsa AAAABtce9euch… user@example.com
When the command
field is set, the SSH daemon will run the named program instead of the typical svnserve -t invocation that the Subversion client asks for. This opens the door to a number of server-side tricks. In the following examples, we abbreviate the lines of the file as:
command="program" TYPE KEY COMMENT
Controlling the invoked command
Because we can specify the executed server-side command, it's easy to name a specific svnserve binary to run and to pass it extra arguments:
command="/path/to/svnserve -t -r /virtual/root" TYPE KEY COMMENT
In this example, /path/to/svnserve
might be a custom wrapper script around svnserve which sets the umask (see the section called “Supporting Multiple Repository Access Methods”). It also shows how to anchor svnserve in a virtual root directory, just as one often does when running svnserve as a daemon process. This might be done either to restrict access to parts of the system, or simply to relieve the user of having to type an absolute path in the svn+ssh://
URL.
It's also possible to have multiple users share a single account. Instead of creating a separate system account for each user, generate a public/private keypair for each person. Then place each public key into the authorized_users
file, one per line, and use the --tunnel-user
option:
command="svnserve -t --tunnel-user=harry" TYPE1 KEY1 harry@example.com
command="svnserve -t --tunnel-user=sally" TYPE2 KEY2 sally@example.com
This example allows both Harry and Sally to connect to the same account via public-key authentication. Each of them has a custom command that will be executed; the --tunnel-user
option tells svnserve -t to assume that the named argument is the authenticated user. Without --tunnel-user
, it would appear as though all commits were coming from the one shared system account.
A final word of caution: giving a user access to the server via public-key in a shared account might still allow other forms of SSH access, even if you've set the command
value in authorized_keys
. For example, the user may still get shell access through SSH, or be able to perform X11 or general port-forwarding through your server. To give the user as little permission as possible, you may want to specify a number of restrictive options immediately after the command
:
command="svnserve -t --tunnel-user=harry",no-port-forwarding,\
no-agent-forwarding,no-X11-forwarding,no-pty \
TYPE1 KEY1 harry@example.com
No comments:
Post a Comment