# HG changeset patch # User Paul Crowley # Date 1236418266 0 # Node ID 86ec1268d306b7ac5349ba727763d6edfd57ee95 # Parent 7369ff73768413bbc57913e043a9d4e73e6c7376 Move some docs out of the README to make it less daunting diff -r 7369ff737684 -r 86ec1268d306 README --- a/README Sat Mar 07 08:58:30 2009 +0000 +++ b/README Sat Mar 07 09:31:06 2009 +0000 @@ -116,158 +116,35 @@ hg clone ssh://hg@repository-server/hgadmin cd hgadmin - mkdir keys/user/thatuser - cp /tmp/theirkey keys/user/thatuser/theirhostname + mkdir keys/users/thatuser + cp /tmp/theirkey keys/users/thatuser/theirhostname hg add hg commit -m "Added key for thatuser" hg push 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 -repositories just as you can. +"/etc/mercurial-server", and changes to it take effect immediately - +"refresh-auth" is run after every push. -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 +With the default access.conf file (see doc/configuring-access for more +details) only users in "keys/root" can act on "hgadmin" - those with keys in +"keys/users" cannot even read this repository. So multiple admins can use +Mercurial's version control to cooperate on controlling access to the +repository server in a natural way. + +You can also create an "access.conf" file in hgadmin, and this is appended to +/etc/mercurial-server/access.conf whenever this is read - in other words, +rules in the latter take precedence over those in the former. So 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, -"/etc/mercurial-server/access.conf" takes precedence over the "access.conf" in -"hgadmin". - -ACCESS.CONF - -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. - -Each line of access.conf has the following syntax: - - ... - -Rule is one of - -init - allow any operation, including the creation of new repositories -write - allow reads and writes to this file in this repository -read - allow the repo to be read but reject matching writes -deny - deny all requests - -A condition is a globpattern matched against a relative path, one of: - -user= - user's key -repo= - repo (as the user supplies it) -file= - file in the repo -branch= - name of the branch - -The first rule in the file which has all its conditions satisfied is used to -determine whether an action is allowed. - -Paths cannot contain any special characters except "/"; glob patterns cannot -contain any special characters except "/" and "*". "*" matches zero or more -characters not including "/" while "**" matches zero or more characters -including "/". - -Blank lines and lines that start with "#" are ignored. - -FILE CONDITIONS - -mercurial-server supports file and branch conditions, which restrict an -operation depending on what files it modifies and what branch the work is on. -However, the way these conditions work is subtle and can be counterintuitive - -if you want to keep things simple, stick to user and repo conditions, and then -things are likely to work the way you would expect. - -The rules file is used to make four decisions: - -- Whether to allow a repository to be created -- Whether to allow access to a repository -- Whether to allow a changeset on a particular branch at all -- Whether to allow a changeset to change a particular file - -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: - -- 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: +the entries you removed from these files. - read repo=specialrepo file=dontwritethis - write repo=specialrepo - -allows all users to read specialrepo, and to write to all files *except* that -any changeset which writes to "dontwritethis" will be rejected. - -- 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: - - write user=docs/* branch=docs file=docs/* - -But something like this will not have the intended effect; it will effectively -allow these users to write to any file on any branch, by writing it to "docs" -first: - - write user=docs/* branch=docs - write user=docs/* file=docs/* - read user=docs/* - -HOW IT WORKS +MORE INFORMATION -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 -restricted shell "/usr/local/lib/mercurial-server/hg-ssh" 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 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. - -Finally, hook in an extension is run for each changeset that is remotely -committed, which uses the rules file to determine whether to allow the -changeset. - -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. - -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. - -However, while the first paragraph holds no matter what bugs mercurial-server -contains, the second depends on the relevant code being correct; though the -entire codebase is currently only about twice as long as this README, -mercurial-server is a fairly new program and may harbour bugs. Backups are -essential! +For more on how to use mercurial-server and configure access, see the files in +the doc directory. THANKS diff -r 7369ff737684 -r 86ec1268d306 doc/configuring-access --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/configuring-access Sat Mar 07 09:31:06 2009 +0000 @@ -0,0 +1,47 @@ +ACCESS.CONF + +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. + +Each line of access.conf has the following syntax: + + ... + +Rule is one of + +init - allow any operation, including the creation of new repositories +write - allow reads and writes to this file in this repository +read - allow the repo to be read but reject matching writes +deny - deny all requests + +A condition is a globpattern matched against a relative path. The two most +important conditions are + + user= - user's key + repo= - repo (as the user supplies it) + +The first rule in the file which has all its conditions satisfied is used to +determine whether an action is allowed. + +Paths cannot contain any special characters except "/"; glob patterns cannot +contain any special characters except "/" and "*". "*" matches zero or more +characters not including "/" while "**" matches zero or more characters +including "/". + +Blank lines and lines that start with "#" are ignored. + +access.conf ships with the following contents: + + init user=root/** + deny repo=hgadmin + write user=users/** + +This means: keys in "root" can do anything; keys in "users" cannot create +repositories, cannot even read the hgadmin repository, but can read and write +any other repository; no other key has any access. + +More advanced access configuration is covered in file-conditions. + diff -r 7369ff737684 -r 86ec1268d306 doc/file-conditions --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/file-conditions Sat Mar 07 09:31:06 2009 +0000 @@ -0,0 +1,61 @@ +FILE CONDITIONS + +Read configuring-access before you read this. + +mercurial-server supports file and branch conditions, which restrict an +operation depending on what files it modifies and what branch the work is on. +However, the way these conditions work is subtle and can be counterintuitive - +if you want to keep things simple, stick to user and repo conditions, and then +things are likely to work the way you would expect. + +File and branch conditions are added to the conditions against which a rule +matches, just like user and repo conditions; they have this form: + + file= - file in the repo + branch= - name of the branch + +However, in order to understand what effect adding these conditions will have, +it helps to understand how and when these rules are applied. + +The rules file is used to make four decisions: + +- Whether to allow a repository to be created +- Whether to allow access to a repository +- Whether to allow a changeset on a particular branch at all +- Whether to allow a changeset to change a particular file + +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: + +- 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: + + read repo=specialrepo file=dontwritethis + write repo=specialrepo + +allows all users to read specialrepo, and to write to all files *except* that +any changeset which writes to "dontwritethis" will be rejected. + +- 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: + + write user=docs/* branch=docs file=docs/* + +But something like this will not have the intended effect; it will effectively +allow these users to write to any file on any branch, by writing it to "docs" +first: + + write user=docs/* branch=docs + write user=docs/* file=docs/* + read user=docs/* + + diff -r 7369ff737684 -r 86ec1268d306 doc/how-it-works --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/how-it-works Sat Mar 07 09:31:06 2009 +0000 @@ -0,0 +1,22 @@ +HOW IT WORKS + +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 +restricted shell "/usr/local/lib/mercurial-server/hg-ssh" 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 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. + +Finally, hook in an extension is run for each changeset that is remotely +committed, which uses the rules file to determine whether to allow the +changeset. diff -r 7369ff737684 -r 86ec1268d306 doc/security --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/security Sat Mar 07 09:31:06 2009 +0000 @@ -0,0 +1,21 @@ +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. + +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. + +However, while the first paragraph holds no matter what bugs mercurial-server +contains, the second depends on the relevant code being correct; though the +entire codebase is currently only about twice as long as this README, +mercurial-server is a fairly new program and may harbour bugs. Backups are +essential!