README
changeset 66 2f0ea1163b9e
parent 63 b75177d307e5
child 81 f23736ad66bc
equal deleted inserted replaced
65:d5c3bb61607b 66:2f0ea1163b9e
     1 mercurial-server
     1 mercurial-server
     2 
     2 
     3 A set of tools for managing authorization and access control for
     3 mercurial-server makes a group of repositories available to the developers
     4 ssh-based Mercurial repositories
     4 you choose, identified by ssh keys, with easy key and access management
       
     5 based on hg.
     5 
     6 
     6 Paul Crowley, paul@lshift.net, 2008-2009
     7 Paul Crowley, paul@lshift.net, 2008-2009
     7 
     8 
     8 This software may be used and distributed according to the terms
     9 This software may be used and distributed according to the terms
     9 of the GNU General Public License, incorporated herein by reference.
    10 of the GNU General Public License, incorporated herein by reference.
    10 
    11 
    11 http://hg.opensource.lshift.net/mercurial-server/
    12 http://hg.opensource.lshift.net/mercurial-server/
    12 
    13 
    13 WHAT IT GIVES YOU
    14 All of the repositories controlled by mercurial-server are owned by a
    14 
    15 single user (the "hg" user in what follows), but many remote users can act
    15 These tools make it easier to provide a centralized repository host
    16 on them, and different users can have different permissions. We don't use
    16 with read/write access to many repositories for many developers.
    17 file permissions to achieve that - instead, developers log in as the "hg"
    17 
    18 user when they connect to the repository host using ssh, using ssh URLs of
    18 All of the repositories controlled by these tools are owned by a single user
    19 the form "ssh://hg@repository-host/repository-name". A restricted shell
    19 (the "hg" user in what follows), but many remote users can act on them, and
    20 prevents them from using this access for unauthorized purposes. Developers
    20 different users can have different permissions. We don't use file permissions to
    21 are authenticated only using SSH keys; no other form of authentication is
    21 achieve that - instead, developers log in as the "hg" user when they connect to
    22 supported. 
    22 the repository host using ssh, using ssh URLs of the form
       
    23 "ssh://hg@repository-host/repository-name". A restricted shell prevents them
       
    24 from using this access for unauthorized purposes. Developers are authenticated
       
    25 only using SSH keys; no other form of authentication is supported. 
       
    26 
    23 
    27 To give a user access to the repository, place their key in an
    24 To give a user access to the repository, place their key in an
    28 appropriately-named subdirectory of "/etc/mercurial-server/keys" and run
    25 appropriately-named subdirectory of "/etc/mercurial-server/keys" and run
    29 "/etc/mercurial-server/refresh-auth". You can then control what access they have
    26 "/etc/mercurial-server/refresh-auth". You can then control what access they
    30 to what repositories by editing the control file
    27 have to what repositories by editing the control file
    31 "/etc/mercurial-server/access.conf", which can match the names of these keys
    28 "/etc/mercurial-server/access.conf", which can match the names of these
    32 against a glob pattern. 
    29 keys against a glob pattern. 
    33 
    30 
    34 For convenient remote control of access, you can instead (if you have the
    31 For convenient remote control of access, you can instead (if you have the
    35 privileges) make changes to a special repository called "hgadmin", which
    32 privileges) make changes to a special repository called "hgadmin", which
    36 contains its own "access.conf" file and "keys" directory. Changes pushed to this
    33 contains its own "access.conf" file and "keys" directory. Changes pushed to
    37 repository take effect immediately. The two "access.conf" files are
    34 this repository take effect immediately. The two "access.conf" files are
    38 concatenated, and the keys directories merged.
    35 concatenated, and the keys directories merged.
    39 
    36 
    40 QUICK START
    37 QUICK START
    41 
    38 
    42 You and all developers using this system will need an SSH public key, and will
    39 You and all developers using this system will need an SSH public key, and
    43 almost certainly want to be running ssh-agent (or its equivalent, eg Pageant
    40 will almost certainly want to be running ssh-agent (or its equivalent, eg
    44 under Windows). If you're not familiar with ssh-agent, you should learn about
    41 Pageant under Windows). If you're not familiar with ssh-agent, you should
    45 that before using this.
    42 learn about that before using this.
    46 
    43 
    47 In what follows, certain operations (eg installing mercurial-server itself) have
    44 In what follows, certain operations (eg installing mercurial-server itself)
    48 to be done on the repository server (which we call "repository-host"), but any
    45 have to be done on the repository server (which we call "repository-host"),
    49 operation that involves checking in or out of Mercurial can be done wherever is
    46 but any operation that involves checking in or out of Mercurial can be done
    50 most convenient to you; the most usual arrangment would be that you'd do these
    47 wherever is most convenient to you; the most usual arrangment would be that
    51 things at the machine you sit at, and on which you run ssh-agent, which is what
    48 you'd do these things at the machine you sit at, and on which you run
    52 authenticates you when you talk to the repository server.
    49 ssh-agent, which is what authenticates you when you talk to the repository
    53 
    50 server.
    54 Ensure there is no user called "hg" on the repository host, and run "./install".
    51 
    55 This installs the mercurial-server files and control files, and creates and sets
    52 Ensure there is no user called "hg" on the repository host, and run
    56 up the "hg" user.
    53 "./install". This installs the mercurial-server files and control files, and
    57 
    54 creates and sets up the "hg" user.
    58 Place your SSH public key in the directory "/etc/mercurial-server/keys/root". I
    55 
    59 suggest creating yourself a directory and naming the key after your hostname (ie
    56 Place your SSH public key in the directory "/etc/mercurial-server/keys/root".
    60 the file is called something like
    57 I suggest creating yourself a directory and naming the key after your hostname
    61 "/etc/mercurial-server/keys/root/yourname/yourhostname") so that you can easily
    58 (ie the file is called something like
    62 manage users who have a different key on each host they use. Then run
    59 "/etc/mercurial-server/keys/root/yourname/yourhostname") so that you can
       
    60 easily manage users who have a different key on each host they use. Then run
    63 "/etc/mercurial-server/refresh-auth".
    61 "/etc/mercurial-server/refresh-auth".
    64 
    62 
    65 The repository is now ready to use, and you are now the sole user able to change
    63 The repository is now ready to use, and you are now the sole user able to
    66 and create repositories on this repository host.  
    64 change and create repositories on this repository host.  
    67 
    65 
    68 CREATING REPOSITORIES
    66 CREATING REPOSITORIES
    69 
    67 
    70 To create a new repository, you clone a local repository onto the remote server.
    68 To create a new repository, you clone a local repository onto the remote
    71 So if you want a new empty repository called "myproject", you can do (as
    69 server. So if you want a new empty repository called "myproject", you can do
    72 yourself):
    70 (as yourself):
    73 
    71 
    74     hg init myproject
    72     hg init myproject
    75     hg clone myproject ssh://hg@repository-host/myproject
    73     hg clone myproject ssh://hg@repository-host/myproject
    76 
    74 
    77 ADDING OTHER USERS
    75 ADDING OTHER USERS
    78 
    76 
    79 Because your key is in the "keys/root" subdirectory, you have the equivalent of
    77 Because your key is in the "keys/root" subdirectory, you have the equivalent
    80 "root privileges" over mercurial-server (not the whole computer, just
    78 of "root privileges" over mercurial-server (not the whole computer, just
    81 mercurial-server). You can add other root users by putting their keys next to
    79 mercurial-server). You can add other root users by putting their keys next to
    82 yours, or you can make less privileged users by putting their keys in the
    80 yours, or you can make less privileged users by putting their keys in the
    83 "keys/users" subdirectory - these users will be able to read and write to any
    81 "keys/users" subdirectory - these users will be able to read and write to any
    84 repository (except one - see below) but will not be able to create new
    82 repository (except one - see below) but will not be able to create new
    85 repositories. As always, when you change "/etc/mercurial-server/keys" you need
    83 repositories. As always, when you change "/etc/mercurial-server/keys" you need
   108     hg push
   106     hg push
   109 
   107 
   110 In other words, hgadmin is a version controlled version of
   108 In other words, hgadmin is a version controlled version of
   111 "/etc/mercurial-server/keys", and changes to it take effect immediately. Only
   109 "/etc/mercurial-server/keys", and changes to it take effect immediately. Only
   112 "keys/root" users can act on "hgadmin" - those with keys in "keys/users" are
   110 "keys/root" users can act on "hgadmin" - those with keys in "keys/users" are
   113 locked out. Multiple admins can use Mercurial's version control to cooperate on
   111 locked out. Multiple admins can use Mercurial's version control to cooperate
   114 controlling access to the repository server in a natural way. You can also add
   112 on controlling access to the repository server in a natural way. You can also
   115 "root" users by putting their key in the "keys/root" directory in just the same
   113 add "root" users by putting their key in the "keys/root" directory in just the
   116 way - these users will now be able to control hgadmin and create new
   114 same way - these users will now be able to control hgadmin and create new
   117 repositories just as you can.
   115 repositories just as you can.
   118 
   116 
   119 Once you're working with "hgadmin", it can be convenient to remove all the keys
   117 Once you're working with "hgadmin", it can be convenient to remove all the
   120 in "/etc/mercurial-server/keys" and all the entries in
   118 keys in "/etc/mercurial-server/keys" and all the entries in
   121 "/etc/mercurial-server/access.conf" and use hgadmin to control everything. If
   119 "/etc/mercurial-server/access.conf" and use hgadmin to control everything. If
   122 you find yourself locked out, you can get back in again by restoring some of the
   120 you find yourself locked out, you can get back in again by restoring some of
   123 entries you removed from these files - remember,
   121 the entries you removed from these files - remember,
   124 "/etc/mercurial-server/access.conf" takes precedence over the "access.conf" in
   122 "/etc/mercurial-server/access.conf" takes precedence over the "access.conf" in
   125 "hgadmin".
   123 "hgadmin".
   126 
   124 
   127 ACCESS.CONF
   125 ACCESS.CONF
   128 
   126 
   129 Out of the box, there are just two kinds of users: the ones with keys in
   127 Out of the box, there are just two kinds of users: the ones with keys in
   130 "keys/root" and those in "keys/users". However, you can change this by editing
   128 "keys/root" and those in "keys/users". However, you can change this by editing
   131 "access.conf". There are two "access.conf" files, one in "/etc/mercurial-server"
   129 "access.conf". There are two "access.conf" files, one in
   132 and one in "hgadmin"; the two are simply concatenated before being read.
   130 "/etc/mercurial-server" and one in "hgadmin"; the two are simply concatenated
       
   131 before being read.
   133 
   132 
   134 Each line of access.conf has the following syntax:
   133 Each line of access.conf has the following syntax:
   135 
   134 
   136 <rule> <condition> <condition> ...
   135 <rule> <condition> <condition> ...
   137 
   136 
   174 - Whether to allow a changeset on a particular branch at all
   173 - Whether to allow a changeset on a particular branch at all
   175 - Whether to allow a changeset to change a particular file
   174 - Whether to allow a changeset to change a particular file
   176 
   175 
   177 When the first two of these decisions are being made, nothing is known about
   176 When the first two of these decisions are being made, nothing is known about
   178 what files might be changed, and so all file conditions automatically succeed
   177 what files might be changed, and so all file conditions automatically succeed
   179 for the purpose of such decisions. This means that doing tricky things with file
   178 for the purpose of such decisions. This means that doing tricky things with
   180 conditions can have counterintuitive consequences:
   179 file conditions can have counterintuitive consequences:
   181 
   180 
   182 - You cannot limit read access to a subset of a repository with a "read" rule
   181 - You cannot limit read access to a subset of a repository with a "read" rule
   183 and a file condition: any user who has access to a repository can read all of it
   182 and a file condition: any user who has access to a repository can read all of
   184 and its full history. Such a rule can only have the effect of masking a later
   183 it and its full history. Such a rule can only have the effect of masking a
   185 "write" rule, as in this example:
   184 later "write" rule, as in this example:
   186 
   185 
   187    read repo=specialrepo file=dontwritethis
   186    read repo=specialrepo file=dontwritethis
   188    write repo=specialrepo
   187    write repo=specialrepo
   189 
   188 
   190 allows all users to read specialrepo, and to write to all files *except* that
   189 allows all users to read specialrepo, and to write to all files *except* that
   191 any changeset which writes to "dontwritethis" will be rejected.
   190 any changeset which writes to "dontwritethis" will be rejected.
   192 
   191 
   193 - For similar reasons, don't give "init" rules file conditions.
   192 - For similar reasons, don't give "init" rules file conditions.
   194 
   193 
   195 - Don't try to deny write access to a particular file on a particular branch - a
   194 - Don't try to deny write access to a particular file on a particular branch -
   196 developer can write to the file on another branch and then merge it in. Either
   195 a developer can write to the file on another branch and then merge it in.
   197 deny all writes to the branch from that user, or allow them to write to all the
   196 Either deny all writes to the branch from that user, or allow them to write to
   198 files they can write to on any branch. In other words, something like this will
   197 all the files they can write to on any branch. In other words, something like
   199 have the intended effect:
   198 this will have the intended effect:
   200 
   199 
   201   write user=docs/* branch=docs file=docs/*
   200   write user=docs/* branch=docs file=docs/*
   202 
   201 
   203 But something like this will not have the intended effect; it will effectively
   202 But something like this will not have the intended effect; it will effectively
   204 allow these users to write to any file on any branch, by writing it to "docs"
   203 allow these users to write to any file on any branch, by writing it to "docs"
   210 
   209 
   211 HOW IT WORKS
   210 HOW IT WORKS
   212 
   211 
   213 When a developer attempts to connect to a repository via ssh, the SSH daemon
   212 When a developer attempts to connect to a repository via ssh, the SSH daemon
   214 searches for a match for that user's key in ~hg/.ssh/authorized_keys. If the
   213 searches for a match for that user's key in ~hg/.ssh/authorized_keys. If the
   215 developer is authorised to connect to the repository they will have an entry in
   214 developer is authorised to connect to the repository they will have an entry
   216 this file. The entry includes a "command" prefix which specifies that the
   215 in this file. The entry includes a "command" prefix which specifies that the
   217 restricted shell should be used; this shell is passed an argument identifying
   216 restricted shell should be used; this shell is passed an argument identifying
   218 the developer. The shell parses the command the developer is trying to execute,
   217 the developer. The shell parses the command the developer is trying to
   219 and consults a rules file to see if that developer is allowed to perform that
   218 execute, and consults a rules file to see if that developer is allowed to
   220 action on that repository. The bulk of the work of the restricted shell is done
   219 perform that action on that repository. The bulk of the work of the restricted
   221 by the Python program "hg-ssh", but the shell script "hg-ssh-wrapper" sets up
   220 shell is done by the Python program "hg-ssh", but the shell script
   222 some configuration so that you can change it to suit your local installation.
   221 "hg-ssh-wrapper" sets up some configuration so that you can change it to suit
   223 
   222 your local installation.
   224 The file ~hg/.ssh/authorized_keys is generated by "refresh-auth", which recurses
   223 
   225 through two directories of files containing SSH keys and generates an entry in
   224 The file ~hg/.ssh/authorized_keys is generated by "refresh-auth", which
   226 authorized_keys for each one, using the name of the key file as the identifier
   225 recurses through two directories of files containing SSH keys and generates an
   227 for the developer. These keys will live in the "keys" subdirectory
   226 entry in authorized_keys for each one, using the name of the key file as the
       
   227 identifier for the developer. These keys will live in the "keys" subdirectory
   228 "/etc/mercurial-server" and the "keys" subdirectory of a repository called
   228 "/etc/mercurial-server" and the "keys" subdirectory of a repository called
   229 "hgadmin". A hook in this repository re-runs "refresh-auth" on the most recent
   229 "hgadmin". A hook in this repository re-runs "refresh-auth" on the most recent
   230 version after every push.
   230 version after every push.
   231 
   231 
   232 Finally, hook in an extension is run for each changeset that is remotely
   232 Finally, hook in an extension is run for each changeset that is remotely
   234 changeset.
   234 changeset.
   235 
   235 
   236 SECURITY OF MERCURIAL-SERVER
   236 SECURITY OF MERCURIAL-SERVER
   237 
   237 
   238 mercurial-server relies entirely on sshd to grant access to remote users. As a
   238 mercurial-server relies entirely on sshd to grant access to remote users. As a
   239 result, it runs no daemons, installs no setuid programs, and no part of it runs
   239 result, it runs no daemons, installs no setuid programs, and no part of it
   240 as root except the install process: all programs run as the user hg. And any
   240 runs as root except the install process: all programs run as the user hg. And
   241 attack on mercurial-server can only be started if the Bad Guys already have a
   241 any attack on mercurial-server can only be started if the Bad Guys already
   242 public key in ~hg/.ssh/authorized_keys, otherwise sshd will bar the way. No
   242 have a public key in ~hg/.ssh/authorized_keys, otherwise sshd will bar the
   243 matter what command the user tries to run on the remote system via ssh,
   243 way. No matter what command the user tries to run on the remote system via
   244 mercurial-server is run. 
   244 ssh, mercurial-server is run. 
   245 
   245 
   246 It parses the command line the user asked for, and interprets and runs the
   246 It parses the command line the user asked for, and interprets and runs the
   247 corresponding hg operation itself if access is allowed, so users can only read
   247 corresponding hg operation itself if access is allowed, so users can only read
   248 and add to history within repositories; they cannot run any other hg command. In
   248 and add to history within repositories; they cannot run any other hg command.
   249 addition, every push and pull is logged with a datestamp, changeset ID and the
   249 In addition, every push and pull is logged with a datestamp, changeset ID and
   250 key that performed the operation.
   250 the key that performed the operation.
   251 
   251 
   252 However, while the first paragraph holds no matter what bugs mercurial-server
   252 However, while the first paragraph holds no matter what bugs mercurial-server
   253 contains, the second depends on the relevant code being correct; though the
   253 contains, the second depends on the relevant code being correct; though the
   254 entire codebase is currently only about twice as long as this README,
   254 entire codebase is currently only about twice as long as this README,
   255 mercurial-server is a fairly new program and may harbour bugs. Backups are
   255 mercurial-server is a fairly new program and may harbour bugs. Backups are