Mercurial SharedSSH setup with hg-admin-tools
I'm looking at setting up a multi-user mercurial installation using the SharedSSH methodologies. There are three methods listed on the page, of which the hg-admin-tools method is the most comprehensive. All three of these methods use a common starting point.. the access to the repository is through an ssh URL, and ssh keys are used to coordinate access to the repositories by listing individual keys in .ssh/authorized_keys. By adding peoples ssh keys to .ssh/authorized_keys the first line of giving repository access permission is based on whether their key appears in authorized_keys.
The key is to simplify management of repositories and the users allowed to access the repositories. Of the three SharedSSH methodologies the hg-admin-tools method offers the most capabilities. However my first attempt to set it up ran into a difficulty because the install script requires that the user be running an ssh-agent. It was my first time encountering ssh-agent and it took a little while to understand how to work around the fact that I don't have ssh-agent available to me.
In the hg-admin-tools distribution is a README explaining that to install hg-admin-tools one must simply run the install script. However, this script failed for me, as I said. Let's dig a little into the script.
The install script starts with
ssh-add -L > first-adminkey
The server I'm using to test is running Ubuntu and this command gave me an empty file. Hurm.. Unfortunately the documentation wasn't much help, except to note that "ssh-add -L" is a way to retrieve an ssh key from the ssh-agent. As I said I don't have an ssh-agent and it wasn't clear if there was any connection between normal ssh keys and any key which ssh-agent would provide. However tracing further in hginit it's clear that the contents of the first-adminkey file become a file in the hgadmin repository which is to contain an ssh key:-
mv admin/hg-admin-tools/first-adminkey repos/hgadmin/keys/admin/first
Let's back up a half step. The hg-admin-tools method relies on a repository named hgadmin and inside this repository is a directory named keys within which are to be placed files containing ssh keys of registered users. In other words the file hgadmin/keys/admin/first would be a file containing an ssh key.
Ah hah! This gives us a simple workaround. The idea here is to simply initialize the hg-admin-tools with an ssh key of someone who will be the administrator of the repositories. Therefore it's a simple matter of copying your personal ssh key into the file first-adminkey then to comment out the ssh-add command in the "install" script before running it. That is, install would start like so:
# NOTE: Instead copy your personal ssh key to first-adminkey
# ssh-add -L > first-adminkey
Once you do this the rest of the install script will function as designed. I'm happy to say this workaround did the trick for me, and I've been able to do several operations on the test repository setup.
Now let's look at what hg-admin-tools lets one do.
First, let's retrieve the hgadmin repository. On your normal user account execute these commands
$ mkdir ~/hg
$ cd ~/hg
$ hg clone ssh://hg@repository-host/hgadmin
$ cd hgadmin
The URL ssh://hg@repository-host is where the shared repositories will be stored. The "hg" user ID is created by the "install" script (FWIW "install" can only be run on a Unix host on which the "adduser" command exists). Everybody who uses any of these shared repositories will access the repositories with a URL that begins with ssh://hg@repository-host. The .ssh/authorized_keys file for this "hg" user contains some magic listing anybody who has an ssh key registered with hgadmin.
The hgadmin directory contains two things: a) a file named "hg-ssh-access.conf" and b) a directory named "keys"
In "keys/admin/first" will be the ssh key which started out life in the first-adminkey file discussed above. To register a user with hgadmin requires these steps:-
- Make a file named keys/users/user-name which contains that users public ssh key
- Execute: hg add
- Execute: hg push
There is a bit of magic inside the ssh://hg@repository-host/hgadmin repository such that when it receives an incoming changeset it regenerates the .ssh/authorized_keys file for the "hg" login. The presence of a key file inside the keys directory is what registers some person with hgadmin, and to unregister someone requires simply to delete their key file and push hgadmin back to the server because the regenerated .ssh/authorized_keys file will not have their ssh key.
The file named "hg-ssh-access.conf" contains definitions controlling who can do what in the shared repositories. The hg-admin-tools README contains the nitty-gritty-details... rather than go through everything let's look at some highlights.
By default the file contains this:
$ cat hg-ssh-access.conf
What this says is any user who has an ssh key file under the "hgadmin/keys/admin/" will be able to initialize a repository. Remember that the key in first-adminkey became "keys/admin/first".
Creating a new repository in the shared repositories is done this way:-
$ cd ~
$ mkdir newrepo
$ cd newrepo
$ hg init
$ hg clone . ssh://hg@repository-host/newrepo
The new repository will exist with the pathname "~hg/repos/newrepo" but be accessed with the ssh URL: ssh://hg@repository-host/newrepo
Once the repository is created you can clone it: hg clone ssh://hg@repository-host/newrepo
I found however that this repository functioned a bit oddly. In particular the files contained within the repository did not show up. Once the new repository is created (as above) it was necessary to give it an hgrc file which contains the following:-
$ cat .hg/hgrc
changegroup.aaaaa_update = hg update -C default > /dev/null
On every update to the repository an "hg update" will be run so that all the changesets are applied.
Granting read-only access to a repository is done as so
- Make sure the user is registered as discussed above
- In hg-ssh-access.conf add: read repo=repo-name user=users/user-name
- Then make sure to "hg push" the hgadmin repository
That user will then be able to clone the named repository: hg clone ssh://hg@repository-host/newrepo
Granting a user the ability to push changes into a repository is done similarly. However the line to add will begin with "write" rather than "read". Once they are listed with a "write" line that user will be able to "hg push" into the repository.