diff -r d5c3bb61607b -r 2f0ea1163b9e README --- a/README Tue Feb 24 10:31:48 2009 +0000 +++ b/README Fri Mar 06 08:56:48 2009 +0000 @@ -1,7 +1,8 @@ mercurial-server -A set of tools for managing authorization and access control for -ssh-based Mercurial repositories +mercurial-server makes a group of repositories available to the developers +you choose, identified by ssh keys, with easy key and access management +based on hg. Paul Crowley, paul@lshift.net, 2008-2009 @@ -10,74 +11,71 @@ http://hg.opensource.lshift.net/mercurial-server/ -WHAT IT GIVES YOU - -These tools make it easier to provide a centralized repository host -with read/write access to many repositories for many developers. - -All of the repositories controlled by these tools are owned by a single user -(the "hg" user in what follows), but many remote users can act on them, and -different users can have different permissions. We don't use file permissions to -achieve that - instead, developers log in as the "hg" user when they connect to -the repository host using ssh, using ssh URLs of the form -"ssh://hg@repository-host/repository-name". A restricted shell prevents them -from using this access for unauthorized purposes. Developers are authenticated -only using SSH keys; no other form of authentication is supported. +All of the repositories controlled by mercurial-server are owned by a +single user (the "hg" user in what follows), but many remote users can act +on them, and different users can have different permissions. We don't use +file permissions to achieve that - instead, developers log in as the "hg" +user when they connect to the repository host using ssh, using ssh URLs of +the form "ssh://hg@repository-host/repository-name". A restricted shell +prevents them from using this access for unauthorized purposes. Developers +are authenticated only using SSH keys; no other form of authentication is +supported. To give a user access to the repository, place their key in an appropriately-named subdirectory of "/etc/mercurial-server/keys" and run -"/etc/mercurial-server/refresh-auth". You can then control what access they have -to what repositories by editing the control file -"/etc/mercurial-server/access.conf", which can match the names of these keys -against a glob pattern. +"/etc/mercurial-server/refresh-auth". You can then control what access they +have to what repositories by editing the control file +"/etc/mercurial-server/access.conf", which can match the names of these +keys against a glob pattern. For convenient remote control of access, you can instead (if you have the privileges) make changes to a special repository called "hgadmin", which -contains its own "access.conf" file and "keys" directory. Changes pushed to this -repository take effect immediately. The two "access.conf" files are +contains its own "access.conf" file and "keys" directory. Changes pushed to +this repository take effect immediately. The two "access.conf" files are concatenated, and the keys directories merged. QUICK START -You and all developers using this system will need an SSH public key, and will -almost certainly want to be running ssh-agent (or its equivalent, eg Pageant -under Windows). If you're not familiar with ssh-agent, you should learn about -that before using this. +You and all developers using this system will need an SSH public key, and +will almost certainly want to be running ssh-agent (or its equivalent, eg +Pageant under Windows). If you're not familiar with ssh-agent, you should +learn about that before using this. -In what follows, certain operations (eg installing mercurial-server itself) have -to be done on the repository server (which we call "repository-host"), but any -operation that involves checking in or out of Mercurial can be done wherever is -most convenient to you; the most usual arrangment would be that you'd do these -things at the machine you sit at, and on which you run ssh-agent, which is what -authenticates you when you talk to the repository server. +In what follows, certain operations (eg installing mercurial-server itself) +have to be done on the repository server (which we call "repository-host"), +but any operation that involves checking in or out of Mercurial can be done +wherever is most convenient to you; the most usual arrangment would be that +you'd do these things at the machine you sit at, and on which you run +ssh-agent, which is what authenticates you when you talk to the repository +server. -Ensure there is no user called "hg" on the repository host, and run "./install". -This installs the mercurial-server files and control files, and creates and sets -up the "hg" user. +Ensure there is no user called "hg" on the repository host, and run +"./install". This installs the mercurial-server files and control files, and +creates and sets up the "hg" user. -Place your SSH public key in the directory "/etc/mercurial-server/keys/root". I -suggest creating yourself a directory and naming the key after your hostname (ie -the file is called something like -"/etc/mercurial-server/keys/root/yourname/yourhostname") so that you can easily -manage users who have a different key on each host they use. Then run +Place your SSH public key in the directory "/etc/mercurial-server/keys/root". +I suggest creating yourself a directory and naming the key after your hostname +(ie the file is called something like +"/etc/mercurial-server/keys/root/yourname/yourhostname") so that you can +easily manage users who have a different key on each host they use. Then run "/etc/mercurial-server/refresh-auth". -The repository is now ready to use, and you are now the sole user able to change -and create repositories on this repository host. +The repository is now ready to use, and you are now the sole user able to +change and create repositories on this repository host. CREATING REPOSITORIES -To create a new repository, you clone a local repository onto the remote server. -So if you want a new empty repository called "myproject", you can do (as -yourself): +To create a new repository, you clone a local repository onto the remote +server. So if you want a new empty repository called "myproject", you can do +(as yourself): hg init myproject hg clone myproject ssh://hg@repository-host/myproject ADDING OTHER USERS -Because your key is in the "keys/root" subdirectory, you have the equivalent of -"root privileges" over mercurial-server (not the whole computer, just +Because your key is in the "keys/root" subdirectory, you have the equivalent +of "root privileges" over mercurial-server (not the whole computer, just mercurial-server). You can add other root users by putting their keys next to yours, or you can make less privileged users by putting their keys in the "keys/users" subdirectory - these users will be able to read and write to any @@ -110,17 +108,17 @@ In other words, hgadmin is a version controlled version of "/etc/mercurial-server/keys", and changes to it take effect immediately. Only "keys/root" users can act on "hgadmin" - those with keys in "keys/users" are -locked out. Multiple admins can use Mercurial's version control to cooperate on -controlling access to the repository server in a natural way. You can also add -"root" users by putting their key in the "keys/root" directory in just the same -way - these users will now be able to control hgadmin and create new +locked out. Multiple admins can use Mercurial's version control to cooperate +on controlling access to the repository server in a natural way. You can also +add "root" users by putting their key in the "keys/root" directory in just the +same way - these users will now be able to control hgadmin and create new repositories just as you can. -Once you're working with "hgadmin", it can be convenient to remove all the keys -in "/etc/mercurial-server/keys" and all the entries in +Once you're working with "hgadmin", it can be convenient to remove all the +keys in "/etc/mercurial-server/keys" and all the entries in "/etc/mercurial-server/access.conf" and use hgadmin to control everything. If -you find yourself locked out, you can get back in again by restoring some of the -entries you removed from these files - remember, +you find yourself locked out, you can get back in again by restoring some of +the entries you removed from these files - remember, "/etc/mercurial-server/access.conf" takes precedence over the "access.conf" in "hgadmin". @@ -128,8 +126,9 @@ Out of the box, there are just two kinds of users: the ones with keys in "keys/root" and those in "keys/users". However, you can change this by editing -"access.conf". There are two "access.conf" files, one in "/etc/mercurial-server" -and one in "hgadmin"; the two are simply concatenated before being read. +"access.conf". There are two "access.conf" files, one in +"/etc/mercurial-server" and one in "hgadmin"; the two are simply concatenated +before being read. Each line of access.conf has the following syntax: @@ -176,13 +175,13 @@ When the first two of these decisions are being made, nothing is known about what files might be changed, and so all file conditions automatically succeed -for the purpose of such decisions. This means that doing tricky things with file -conditions can have counterintuitive consequences: +for the purpose of such decisions. This means that doing tricky things with +file conditions can have counterintuitive consequences: - You cannot limit read access to a subset of a repository with a "read" rule -and a file condition: any user who has access to a repository can read all of it -and its full history. Such a rule can only have the effect of masking a later -"write" rule, as in this example: +and a file condition: any user who has access to a repository can read all of +it and its full history. Such a rule can only have the effect of masking a +later "write" rule, as in this example: read repo=specialrepo file=dontwritethis write repo=specialrepo @@ -192,11 +191,11 @@ - For similar reasons, don't give "init" rules file conditions. -- Don't try to deny write access to a particular file on a particular branch - a -developer can write to the file on another branch and then merge it in. Either -deny all writes to the branch from that user, or allow them to write to all the -files they can write to on any branch. In other words, something like this will -have the intended effect: +- Don't try to deny write access to a particular file on a particular branch - +a developer can write to the file on another branch and then merge it in. +Either deny all writes to the branch from that user, or allow them to write to +all the files they can write to on any branch. In other words, something like +this will have the intended effect: write user=docs/* branch=docs file=docs/* @@ -212,19 +211,20 @@ When a developer attempts to connect to a repository via ssh, the SSH daemon searches for a match for that user's key in ~hg/.ssh/authorized_keys. If the -developer is authorised to connect to the repository they will have an entry in -this file. The entry includes a "command" prefix which specifies that the +developer is authorised to connect to the repository they will have an entry +in this file. The entry includes a "command" prefix which specifies that the restricted shell should be used; this shell is passed an argument identifying -the developer. The shell parses the command the developer is trying to execute, -and consults a rules file to see if that developer is allowed to perform that -action on that repository. The bulk of the work of the restricted shell is done -by the Python program "hg-ssh", but the shell script "hg-ssh-wrapper" sets up -some configuration so that you can change it to suit your local installation. +the developer. The shell parses the command the developer is trying to +execute, and consults a rules file to see if that developer is allowed to +perform that action on that repository. The bulk of the work of the restricted +shell is done by the Python program "hg-ssh", but the shell script +"hg-ssh-wrapper" sets up some configuration so that you can change it to suit +your local installation. -The file ~hg/.ssh/authorized_keys is generated by "refresh-auth", which recurses -through two directories of files containing SSH keys and generates an entry in -authorized_keys for each one, using the name of the key file as the identifier -for the developer. These keys will live in the "keys" subdirectory +The file ~hg/.ssh/authorized_keys is generated by "refresh-auth", which +recurses through two directories of files containing SSH keys and generates an +entry in authorized_keys for each one, using the name of the key file as the +identifier for the developer. These keys will live in the "keys" subdirectory "/etc/mercurial-server" and the "keys" subdirectory of a repository called "hgadmin". A hook in this repository re-runs "refresh-auth" on the most recent version after every push. @@ -236,18 +236,18 @@ SECURITY OF MERCURIAL-SERVER mercurial-server relies entirely on sshd to grant access to remote users. As a -result, it runs no daemons, installs no setuid programs, and no part of it runs -as root except the install process: all programs run as the user hg. And any -attack on mercurial-server can only be started if the Bad Guys already have a -public key in ~hg/.ssh/authorized_keys, otherwise sshd will bar the way. No -matter what command the user tries to run on the remote system via ssh, -mercurial-server is run. +result, it runs no daemons, installs no setuid programs, and no part of it +runs as root except the install process: all programs run as the user hg. And +any attack on mercurial-server can only be started if the Bad Guys already +have a public key in ~hg/.ssh/authorized_keys, otherwise sshd will bar the +way. No matter what command the user tries to run on the remote system via +ssh, mercurial-server is run. It parses the command line the user asked for, and interprets and runs the corresponding hg operation itself if access is allowed, so users can only read -and add to history within repositories; they cannot run any other hg command. In -addition, every push and pull is logged with a datestamp, changeset ID and the -key that performed the operation. +and add to history within repositories; they cannot run any other hg command. +In addition, every push and pull is logged with a datestamp, changeset ID and +the key that performed the operation. However, while the first paragraph holds no matter what bugs mercurial-server contains, the second depends on the relevant code being correct; though the