README
author Paul Crowley <paul@ciphergoth.org>
Thu Apr 24 08:27:30 2008 +0100 (2008-04-24)
changeset 28 583ed103e021
parent 26 2c4f499ea12f
child 30 98dbde5b13a1
permissions -rw-r--r--
update README to reflect new scripted installer
paul@13
     1
hg-admin-tools
paul@2
     2
paul@2
     3
A set of tools for managing authorization and access control for
paul@12
     4
ssh-based Mercurial repositories
paul@2
     5
paul@12
     6
Paul Crowley, paul@lshift.net, 2008
paul@2
     7
paul@2
     8
This software may be used and distributed according to the terms
paul@2
     9
of the GNU General Public License, incorporated herein by reference.
paul@2
    10
paul@12
    11
WHAT IT GIVES YOU
paul@12
    12
paul@14
    13
These tools make it easier to provide a centralized repository host
paul@14
    14
with read/write access to many repositories for many developers.
paul@14
    15
Access control is managed with a special repository on the server
paul@14
    16
called "hgadmin"; pushes to this repository immediately change the
paul@14
    17
rules that are in effect.
paul@14
    18
paul@14
    19
Inside "hgadmin" is a "keys" directory containing the SSH keys of all
paul@14
    20
developers who have access, and a file "hg-ssh-access.conf" which
paul@14
    21
gives a set of rules defining who can do what to what.
paul@12
    22
paul@14
    23
All of the repositories controlled by these tools are owned by a
paul@14
    24
single user (the "hg" user in what follows), but many remote users can
paul@14
    25
act on them.  We don't use file permissions to achieve that - instead,
paul@14
    26
developers log in as the "hg" user when they connect to the repository
paul@14
    27
host using ssh, using ssh URLs of the form
paul@14
    28
"ssh://hg@repository-host/repository-name".  A restricted shell
paul@14
    29
prevents them from using this access for unauthorized purposes.
paul@28
    30
Developers are authenticated only using SSH keys; no other form of
paul@28
    31
authentication is supported.
paul@12
    32
paul@28
    33
QUICK START
paul@12
    34
paul@28
    35
You will need 
paul@12
    36
paul@28
    37
- "sudo" installed
paul@28
    38
- "sudo" root privileges
paul@28
    39
- an ssh-key set up with ssh-agent
paul@18
    40
paul@28
    41
Ensure there is no user called "hg" on the repository host, and run
paul@28
    42
"./install" to create them. You are now the sole user able to change
paul@28
    43
and create repositories on this repository host.  To give access to
paul@28
    44
others, check out hgadmin - as yourself, and on whichever host is most
paul@28
    45
convenient, but using the ssh-key with which you set up the
paul@28
    46
repository:
paul@2
    47
paul@12
    48
   mkdir ~/hg
paul@12
    49
   cd ~/hg
paul@14
    50
   hg clone ssh://hg@repository-host/hgadmin
paul@12
    51
   cd hgadmin
paul@2
    52
paul@10
    53
You can now add other users by putting their keys in an appropriate
paul@10
    54
subdirectory of the "keys" directory, and control their access by
paul@10
    55
editing hg-ssh-access.conf.  Changes will take effect as soon as you
paul@14
    56
push them to "ssh://hg@repository-host/hgadmin".
paul@14
    57
paul@18
    58
Users authorized to do so can now also create new repositories on this
paul@18
    59
host with "clone":
paul@14
    60
paul@14
    61
  hg clone . ssh://hg@repository-host/my-project-name
paul@13
    62
paul@13
    63
HG-SSH-ACCESS.CONF
paul@2
    64
paul@10
    65
Each line of hg-ssh-access.conf has the following syntax:
paul@2
    66
paul@18
    67
<rule> <condition> <condition> ...
paul@2
    68
paul@18
    69
Rule is one of
paul@18
    70
paul@18
    71
init - allow any operation, including the creation of new repositories
paul@18
    72
write - allow reads and writes to this file in this repository
paul@18
    73
read - allow the repo to be read but reject matching writes
paul@18
    74
deny - deny all requests
paul@18
    75
paul@18
    76
A condition is a globpattern matched against a relative path, one of:
paul@18
    77
paul@18
    78
user=<globpattern> - user's key
paul@18
    79
repo=<globpattern> - repo (as the user supplies it)
paul@18
    80
file=<globpattern> - file in the repo
paul@20
    81
branch=<globpattern> - name of the branch
paul@18
    82
paul@18
    83
The first rule in the file which has all its conditions satisfied is
paul@18
    84
used to determine whether an action is allowed.
paul@18
    85
paul@18
    86
Paths cannot contain any special characters except "/"; glob patterns
paul@18
    87
cannot contain any special characters except "/" and "*".  "*" matches
paul@18
    88
zero or more characters not including "/" while "**" matches zero or
paul@18
    89
more characters including "/".
paul@18
    90
paul@18
    91
Blank lines and lines that start with "#" are ignored.
paul@18
    92
paul@18
    93
FILE CONDITIONS
paul@18
    94
paul@20
    95
The rules file is used to make four decisions:
paul@18
    96
paul@18
    97
- Whether to allow a repository to be created
paul@18
    98
- Whether to allow access to a repository
paul@20
    99
- Whether to allow a changeset on a particular branch at all
paul@18
   100
- Whether to allow a changeset to change a particular file
paul@18
   101
paul@18
   102
When the first two of these decisions are being made, nothing is known
paul@18
   103
about what files might be changed, and so all file conditions
paul@18
   104
automatically succeed for the purpose of such decisions.  This means
paul@18
   105
that doing tricky things with file conditions can have
paul@18
   106
counterintuitive consequences:
paul@18
   107
paul@18
   108
- You cannot limit read access to a subset of a repository with a
paul@18
   109
"read" rule and a file condition: any user who has access to a
paul@18
   110
repository can read all of it and its full history.  Such a rule can
paul@18
   111
only have the effect of masking a later "write" rule, as in this
paul@18
   112
example:
paul@18
   113
paul@18
   114
   read repo=specialrepo file=dontwritethis
paul@18
   115
   write repo=specialrepo
paul@18
   116
paul@18
   117
allows all users to read specialrepo, and to write to all files
paul@18
   118
*except* that any changeset which writes to "dontwritethis" will be
paul@18
   119
rejected.
paul@18
   120
paul@18
   121
- For similar reasons, don't give "init" rules file conditions.
paul@18
   122
paul@26
   123
- Don't try to deny write access to a particular file on a particular
paul@26
   124
branch - a developer can write to the file on another branch and then
paul@26
   125
merge it in.  Either deny all writes to the branch from that user, or
paul@26
   126
allow them to write to all the files they can write to on any branch.
paul@26
   127
In other words, something like this will have the intended effect
paul@26
   128
paul@26
   129
  write user=docs/* branch=docs file=docs/*
paul@26
   130
paul@26
   131
But something like this will not have the intended effect; it will
paul@26
   132
effectively allow these users to write to any file on any branch, by
paul@26
   133
writing it to "docs" first:
paul@26
   134
paul@26
   135
  write user=docs/* branch=docs
paul@26
   136
  write user=docs/* file=docs/*
paul@26
   137
  read user=docs/*
paul@26
   138
paul@28
   139
HOW IT WORKS
paul@28
   140
paul@28
   141
When a developer attempts to connect to a repository via ssh, the SSH
paul@28
   142
daemon searches for a match for that user's key in
paul@28
   143
~hg/.ssh/authorized_keys.  If the developer is authorised to connect
paul@28
   144
to the repository they will have an entry in this file.  The entry
paul@28
   145
includes a "command" prefix which specifies that the restricted shell
paul@28
   146
should be used; this shell is passed an argument identifying the
paul@28
   147
developer.  The shell parses the command the developer is trying to
paul@28
   148
execute, and consults a rules file to see if that developer is allowed
paul@28
   149
to perform that action on that repository.  The bulk of the work of
paul@28
   150
the restricted shell is done by the Python program "hg-ssh", but the
paul@28
   151
shell script "hg-ssh-wrapper" sets up some configuration so that you
paul@28
   152
can change it to suit your local installation.
paul@28
   153
paul@28
   154
The file ~hg/.ssh/authorized_keys is generated by "refresh-auth",
paul@28
   155
which recurses through a directory of files containing SSH keys and
paul@28
   156
generates an entry in authorized_keys for each one, using the name of
paul@28
   157
the key file as the identifier for the developer.  These keys will
paul@28
   158
live in the "keys" subdirectory of a repository called "hgadmin".  A
paul@28
   159
hook in this repository re-runs "refresh-auth" on the most recent
paul@28
   160
version after every push.
paul@28
   161
paul@28
   162
Finally, a hook in an extension is run for each changeset that is
paul@28
   163
remotely committed, which uses the rules file to determine whether to
paul@28
   164
allow the changeset.
paul@28
   165
paul@20
   166
LOCKING YOURSELF OUT
paul@20
   167
paul@20
   168
If you find yourself "locked out" - that is, that you no longer have
paul@20
   169
the permissions needed in hgadmin - you can break back in again if
paul@20
   170
you're able to become the "hg" user on the repository host.  Once you
paul@20
   171
are that user, delete ~hg/.ssh/authorized_keys (to stop any user who
paul@20
   172
might have access but shouldn't from using the repository while you
paul@20
   173
fix things).  Then go into ~hg/repos/hgadmin, do an "hg update", edit
paul@20
   174
things to your satisfaction, and commit the change.  Finally, run
paul@20
   175
~/admin/hg-admin-tools/refresh-auth to regenerate
paul@20
   176
~hg/.ssh/authorized_keys. 
paul@20
   177
paul@18
   178
THANKS
paul@18
   179
paul@18
   180
Thanks for reading this far.  If you use hg-admin-tools, please tell
paul@18
   181
me about it.
paul@18
   182
paul@18
   183
Paul Crowley, 2008