doc/manual.docbook
changeset 120 16056a9015f3
parent 119 40a287c95661
child 121 62185dc7d0c9
equal deleted inserted replaced
119:40a287c95661 120:16056a9015f3
     1 <?xml version="1.0" encoding="utf-8"?>
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <article xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en">
     2 <article xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="en"
       
     3   xmlns:xlink="http://www.w3.org/1999/xlink">
     3 <info>
     4 <info>
     4   <title>Sharing Mercurial repositories with mercurial-server</title>
     5   <title>Sharing Mercurial repositories with mercurial-server</title>
     5   <author><firstname>Paul</firstname><surname>Crowley</surname></author>
     6   <author><firstname>Paul</firstname><surname>Crowley</surname></author>
     6   <copyright><year>2009</year><holder>Paul Crowley</holder></copyright>
     7   <copyright><year>2009</year><holder>Paul Crowley, LShift Ltd</holder></copyright>
     7 </info>
     8 </info>
     8 <section>
     9 <section>
     9 <title>About mercurial-server</title>
    10 <title>About mercurial-server</title>
    10 <para>
    11 <para>
       
    12 Home page: <link xlink:href="http://www.lshift.net/mercurial-server.html"/>
       
    13 </para>
       
    14 <para>
    11 mercurial-server is software for Debian and Ubuntu systems which gives your
    15 mercurial-server is software for Debian and Ubuntu systems which gives your
    12 developers remote read/write access to <ulink
    16 developers remote read/write access to <link
    13 url="http://hg-scm.org/">Mercurial</ulink> repositories using SSH public
    17 xlink:href="http://hg-scm.org/">Mercurial</link> repositories using SSH public
    14 key authentication; it provides convenient and fine-grained key management
    18 key authentication; it provides convenient and fine-grained key management
    15 and access control.
    19 and access control.
    16 </para>
    20 </para>
    17 <para>
    21 <para>
    18 mercurial-server is the easiest and most secure way for several developers
    22 mercurial-server is the easiest and most secure way for several developers
    19 to have read/write access to a central repository, but that's not the only
    23 to have read/write access to a central repository, but that's not the only
    20 way for several people to work on the same project using Mercurial; you
    24 way for several people to work on the same project using Mercurial; you
    21 should be familiar with the <ulink
    25 should be familiar with the <link
    22 url="http://mercurial.selenic.com/wiki/MultipleCommitters">other ways of
    26 xlink:href="http://mercurial.selenic.com/wiki/MultipleCommitters">other ways of
    23 handling multiple commiters</ulink> before deciding to use this.
    27 handling multiple commiters</link> before deciding to use this.
    24 </para>
    28 </para>
    25 <para>
    29 <para>
    26 Though mercurial-server is currently targeted at Debian-based systems such
    30 Though mercurial-server is currently targeted at Debian-based systems such
    27 as Ubuntu, other users have reported success getting it running on other
    31 as Ubuntu, other users have reported success getting it running on other
    28 Unix-based systems such as Red Hat. Running it on a non-Unix system such as
    32 Unix-based systems such as Red Hat. Running it on a non-Unix system such as
    50 </section>
    54 </section>
    51 </section>
    55 </section>
    52 <section>
    56 <section>
    53 <title>Step by step</title>
    57 <title>Step by step</title>
    54 <para>
    58 <para>
    55 mercurial-server authenticates users not using passwords but using <ulink url="http://sial.org/howto/openssh/publickey-auth/">SSH public keys</ulink>; everyone who wants access to a mercurial-server repository will need such a key, so you'll need to familiarize yourself with them before proceeding.  In combination with <command>ssh-agent</command> (or equivalents such as the Windows program <ulink url="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter9.html#pageant">Pageant</ulink>), this means that users will not need to type in a password to access the repository.
    59 mercurial-server authenticates users not using passwords but using <link
    56 </para>
    60 xlink:href="http://sial.org/howto/openssh/publickey-auth/">SSH public
    57 <para>
    61 keys</link>; everyone who wants access to a mercurial-server repository
    58 In what follows, we assume that you usually sit at a machine called <systemitem class="systemname">my-workstation</systemitem> and you wish to install mercurial-server on <systemitem class="systemname">repository-host</systemitem>.  First, you'll need to create an SSH public key if you haven't already.  You should consult your system documentation on how to do this, but it should look something like this.
    62 will need such a key, so you'll need to familiarize yourself with them
       
    63 before proceeding. In combination with <command>ssh-agent</command> (or
       
    64 equivalents such as the Windows program <link
       
    65 xlink:href="http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter9.html#pageant">Pageant</link>),
       
    66 this means that users will not need to type in a password to access the
       
    67 repository.
       
    68 </para>
       
    69 <section>
       
    70 <title>Creating a repository host</title>
       
    71 <para>
       
    72 In what follows, we assume that you usually sit at a machine called
       
    73 <systemitem class="systemname">my-workstation</systemitem> and you wish to
       
    74 install mercurial-server on <systemitem
       
    75 class="systemname">repository-host</systemitem>. First, you'll need to
       
    76 create an SSH public key if you haven't already. You should consult your
       
    77 system documentation on how to do this, but it should look something like
       
    78 this.
    59 </para>
    79 </para>
    60 <screen>
    80 <screen>
    61 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>ssh-keygen</userinput>
    81 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>ssh-keygen</userinput>
    62 <computeroutput>Generating public/private rsa key pair.
    82 <computeroutput>Generating public/private rsa key pair.
    63 Enter passphrase (empty for no passphrase): 
    83 Enter passphrase (empty for no passphrase): 
    88 (Reading database ... 144805 files and directories currently installed.)
   108 (Reading database ... 144805 files and directories currently installed.)
    89 Unpacking mercurial-server (from .../mercurial-server_0.6.1_amd64.deb) ...
   109 Unpacking mercurial-server (from .../mercurial-server_0.6.1_amd64.deb) ...
    90 Setting up mercurial-server (0.6.1) ...
   110 Setting up mercurial-server (0.6.1) ...
    91 user@repository-host:~$ </computeroutput></screen>
   111 user@repository-host:~$ </computeroutput></screen>
    92 <para>
   112 <para>
    93 mercurial-server is now installed on the repository host.  Next, we need to give you permission to see its repositories.
   113 mercurial-server is now installed on the repository host.  Next, we need to give you permission to access its repositories.
    94 </para>
   114 </para>
    95 <screen>
   115 <screen>
    96 <computeroutput>user@repository-host:~$ </computeroutput><userinput>ssh-add -L > my-key</userinput>
   116 <computeroutput>user@repository-host:~$ </computeroutput><userinput>ssh-add -L > my-key</userinput>
    97 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo mkdir -p /etc/mercurial-server/keys/root/user</userinput>
   117 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo mkdir -p /etc/mercurial-server/keys/root/user</userinput>
    98 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo cp my-key /etc/mercurial-server/keys/root/user/my-workstation</userinput>
   118 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo cp my-key /etc/mercurial-server/keys/root/user/my-workstation</userinput>
    99 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo -u hg /usr/share/mercurial-server/refresh-auth</userinput>
   119 <computeroutput>user@repository-host:~$ </computeroutput><userinput>sudo -u hg /usr/share/mercurial-server/refresh-auth</userinput>
   100 <computeroutput>user@repository-host:~$ </computeroutput><userinput>exit</userinput>
   120 <computeroutput>user@repository-host:~$ </computeroutput><userinput>exit</userinput>
   101 <computeroutput>Connection to shell closed.
   121 <computeroutput>Connection to shell closed.
   102 user@my-workstation:~$ </computeroutput></screen>
   122 user@my-workstation:~$ </computeroutput></screen>
   103 <para>
   123 <para>
   104 You can now create repositories on the remote machine and have complete read-write access to all of them; you need never log on to <systemitem class="systemname">repository-host</systemitem> again.
   124 You can now create repositories on the remote machine and have complete
   105 </para>
   125 read-write access to all of them; you need never log on to <systemitem
       
   126 class="systemname">repository-host</systemitem> again.
       
   127 </para>
       
   128 </section>
       
   129 <section>
       
   130 <title>Creating repositories</title>
   106 <screen>
   131 <screen>
   107 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>cd my-mercurial-project</userinput>
   132 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>cd my-mercurial-project</userinput>
   108 <computeroutput>user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>hg clone . ssh://hg@repository-host/repository/name</userinput>
   133 <computeroutput>user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>hg clone . ssh://hg@repository-host/repository/name</userinput>
   109 <computeroutput>searching for changes
   134 <computeroutput>searching for changes
   110 remote: adding changesets
   135 remote: adding changesets
   114 user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>hg pull ssh://hg@repository-host/repository/name</userinput>
   139 user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>hg pull ssh://hg@repository-host/repository/name</userinput>
   115 <computeroutput>pulling from ssh://hg@repository-host/repository/name
   140 <computeroutput>pulling from ssh://hg@repository-host/repository/name
   116 searching for changes
   141 searching for changes
   117 no changes found
   142 no changes found
   118 user@my-workstation:~/my-mercurial-project$ </computeroutput></screen>
   143 user@my-workstation:~/my-mercurial-project$ </computeroutput></screen>
   119 <para>
   144 </section>
   120 As things stand, no-one but you has any access to any repositories you create on this system.  In order to give anyone else access, you'll need a copy of their SSH public key.  Once you have that key, you could give them access by logging into <systemitem class="systemname">repository-host</systemitem>, putting their keys in the right place under <filename class='directory'>/etc/mercurial-server/keys</filename>, and re-running <userinput>sudo -u hg /usr/share/mercurial-server/refresh-auth</userinput>.  However, there's a more convenient way.
   145 <section>
       
   146 <title>Adding other users</title>
       
   147 <para>
       
   148 As things stand, no-one but you has any access to any repositories you
       
   149 create on this system. In order to give anyone else access, you'll need a
       
   150 copy of their SSH public key; we'll assume you have that key in
       
   151 <filename>~/other-users-key.pub</filename>. You could give them access by
       
   152 logging into <systemitem class="systemname">repository-host</systemitem>,
       
   153 putting the key in the right place under <filename
       
   154 class='directory'>/etc/mercurial-server/keys</filename>, and re-running
       
   155 <userinput>sudo -u hg /usr/share/mercurial-server/refresh-auth</userinput>.
       
   156 However, there's a more convenient way.
   121 </para>
   157 </para>
   122 <screen>
   158 <screen>
   123 <computeroutput>user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>cd ..</userinput>
   159 <computeroutput>user@my-workstation:~/my-mercurial-project$ </computeroutput><userinput>cd ..</userinput>
   124 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>hg clone ssh://hg@repository-host/hgadmin</userinput>
   160 <computeroutput>user@my-workstation:~$ </computeroutput><userinput>hg clone ssh://hg@repository-host/hgadmin</userinput>
   125 <computeroutput>destination directory: hgadmin
   161 <computeroutput>destination directory: hgadmin
   139 remote: adding manifests
   175 remote: adding manifests
   140 remote: adding file changes
   176 remote: adding file changes
   141 remote: added 1 changesets with 1 changes to 1 files
   177 remote: added 1 changesets with 1 changes to 1 files
   142 user@my-workstation:~/hgadmin$ </computeroutput></screen>
   178 user@my-workstation:~/hgadmin$ </computeroutput></screen>
   143 <para>
   179 <para>
   144 The new user can now read and write to your <literal>ssh://hg@repository-host/repository/name</literal> repository.
   180 The new user can now read and write to your
       
   181 <literal>ssh://hg@repository-host/repository/name</literal> repository.
       
   182 Most other changes to access control can be made simply by making and
       
   183 pushing changes to <literal>hgadmin</literal>, and you can use Mercurial to
       
   184 cooperate with other root users in the normal way.
       
   185 </para>
       
   186 </section>
       
   187 <section>
       
   188 <title>Basic access control</title>
       
   189 <para>
       
   190 Out of the box, mercurial-server supports two kinds of users: "root" users and normal users.  If you followed the steps above, you are a "root" user because your key is under <filename class='directory'>keys/root</filename>, while the other user you gave access to is a normal user since their key is under <filename class='directory'>keys/users</filename>.  Keys that are not in either of these directories will by default have no access to anything.
       
   191 </para>
       
   192 <para>
       
   193 Root users can edit <literal>hgadmin</literal>, create new repositories and read and write to existing ones.  Normal users cannot access <literal>hgadmin</literal> or create new repositories, but they can read and write to any other repository.  This is only the default configuration; for more advanced configuration read <xref linkend="accesscontrol"/>.
       
   194 </para>
       
   195 </section>
       
   196 </section>
       
   197 <section>
       
   198 <title>How mercurial-server works</title>
       
   199 <para>
       
   200 All of the repositories controlled by mercurial-server are owned by a
       
   201 single user, the <literal>hg</literal> user, which is why all URLs for
       
   202 mercurial-server repositories start with <literal>ssh://hg@...</literal>.
       
   203 Each SSH key that has access to the repository has an entry in
       
   204 <filename>~hg/.ssh/authorized_keys</filename>; this is how the SSH daemon
       
   205 knows to give that key access. When the user connects over SSH, their
       
   206 commands are run in a specially crafted restricted shell; this shell knows
       
   207 which key was used to connect, determines what the user is trying to do,
       
   208 and checks the access rules to decide whether to allow it.  
       
   209 </para>
       
   210 <para>
       
   211 This restricted shell also ensures that certain Mercurial extensions are
       
   212 loaded when the user acts on a repository; these extensions check the
       
   213 access control rules for any changeset that the user tries to commit, and
       
   214 log all pushes and pulls into a per-repository access log.
       
   215 </para>
       
   216 <para>
       
   217 <command>refresh-auth</command> recurses through the <filename
       
   218 class='directory'>/etc/mercurial-server/keys</filename> and the <filename
       
   219 class='directory'>keys</filename> directory in the
       
   220 <literal>hgadmin</literal> repository, creating an entry in
       
   221 <filename>~hg/.ssh/authorized_keys</filename> for each one. This is redone
       
   222 automatically whenever a change is pushed to <literal>hgadmin</literal>.
       
   223 </para>
       
   224 </section>
       
   225 <section id="accesscontrol">
       
   226 <title>Access control</title>
       
   227 <para>
       
   228 mercurial-server offers much more fine-grained access control than this division into two classes of users.  Let's suppose you wish to give Pat access to the <literal>widget</literal> repository, but no other.  We first copy Pat's SSH public key into the <filename
       
   229 class='directory'>keys/widget/pat</filename> directory in <literal>hgadmin</literal>.  Now mercurial-server knows about Pat's key, but will give Pat no access to anything because the key is not under either <filename
       
   230 class='directory'>keys/root</filename> or <filename
       
   231 class='directory'>keys/users</filename>.  To grant this key access, we must give mercurial-server a new access rule, so we create a file in <literal>hgadmin</literal> called <filename>access.conf</filename>, with the following contents:</para>
       
   232 <programlisting>
       
   233     write repo=widget user=widget/**
       
   234 </programlisting>
       
   235 <para>
       
   236 Pat will have read and write access as soon as we add, commit, and push these files.
       
   237 </para>
       
   238 <para>
       
   239 Each line of access.conf has the following syntax:
       
   240 </para>
       
   241 <programlisting>
       
   242 <replaceable>rule</replaceable> <replaceable>condition</replaceable> <replaceable>condition...</replaceable>
       
   243 </programlisting>
       
   244 <para>
       
   245 Blank lines and lines that start with <literal>#</literal> are ignored. Rule is one of
       
   246 </para>
       
   247 <itemizedlist>
       
   248 <listitem>
       
   249 <literal>init</literal>: allow reads, writes, and the creation of new repositories
       
   250 </listitem>
       
   251 <listitem>
       
   252 <literal>write</literal>: allow reads and writes
       
   253 </listitem>
       
   254 <listitem>
       
   255 <literal>read</literal>: allow only read operations
       
   256 </listitem>
       
   257 <listitem>
       
   258 <literal>deny</literal>: deny all requests
       
   259 </listitem>
       
   260 </itemizedlist>
       
   261 <para>
       
   262 When considering a request, mercurial-server steps through all the rules in <filename>/etc/mercurial-server/access.conf</filename> and then all the rules in <filename>access.conf</filename> in <literal>hgadmin</literal> looking for a rule which matches on every condition.  If it does not find such a rule, it denies the request; otherwise it checks whether the rule grants sufficient privilege to allow it.
       
   263 </para>
       
   264 <para>
       
   265 By default, <filename>/etc/mercurial-server/access.conf</filename> has the following rules:
       
   266 </para>
       
   267 <programlisting>
       
   268     init user=root/**
       
   269     deny repo=hgadmin
       
   270     write user=users/**
       
   271 </programlisting>
       
   272 <para>
       
   273 These rules ensure that root users can do any operation on any repository, that no other users can access the <literal>hgadmin</literal> repository, and that those with keys in <filename class='directory'>keys/users</filename> can read or write to any repository but not create repositories.
       
   274 </para>
       
   275 <para>
       
   276 A condition is a globpattern matched against a relative path. The two most
       
   277 important conditions are
       
   278 </para>
       
   279 <itemizedlist>
       
   280 <listitem>
       
   281 <code><literal>user=</literal><replaceable>globpattern</replaceable></code>: path to the user's key
       
   282 </listitem>
       
   283 <listitem>
       
   284 <code><literal>repo=</literal><replaceable>globpattern</replaceable></code>: path to the repository
       
   285 </listitem>
       
   286 </itemizedlist>
       
   287 <para>
       
   288 "*" only matches one directory level, where "**" matches as many as you
       
   289 want. More precisely, "*" matches zero or more characters not including "/"
       
   290 while "**" matches zero or more characters including "/".
       
   291 </para>
       
   292 <section>
       
   293 <title>File conditions</title>
       
   294 <para>
       
   295 Here be dragons...
       
   296 </para>
       
   297 </section>
       
   298 </section>
       
   299 <section>
       
   300 <title>Security</title>
       
   301 <para>
       
   302 mercurial-server relies entirely on sshd to grant access to remote users.
       
   303 As a result, it runs no daemons, installs no setuid programs, and no part
       
   304 of it runs as root except the install process: all programs run as the user
       
   305 hg. And any attack on mercurial-server can only be started if the Bad Guys
       
   306 already have a public key in <filename>~hg/.ssh/authorized_keys</filename>,
       
   307 otherwise sshd will bar the way.
       
   308 </para>
       
   309 <para>
       
   310 No matter what command the user tries to run on the remote system via SSH,
       
   311 mercurial-server is run. It parses the command line the user asked for, and
       
   312 interprets and runs the corresponding hg operation itself if access is
       
   313 allowed, so users can only read and add to history within repositories;
       
   314 they cannot run any other hg command. In addition, every push and pull is
       
   315 logged with a datestamp, changeset ID and the key that performed the
       
   316 operation.
       
   317 </para>
       
   318 <para>
       
   319 However, while the first paragraph holds no matter what bugs
       
   320 mercurial-server contains, the second depends on the relevant code being
       
   321 correct; though the entire codebase is short, mercurial-server is a fairly
       
   322 new program and may harbour bugs. Backups are essential!
       
   323 </para>
       
   324 </section>
       
   325 <section>
       
   326 <title>Thanks</title>
       
   327 <para>
       
   328 Thanks for reading this far. If you use mercurial-server, please tell me about
       
   329 it.
       
   330 </para>
       
   331 <para>
       
   332 Paul Crowley, <email>paul@lshift.net</email>, 2009
   145 </para>
   333 </para>
   146 </section>
   334 </section>
   147 </article>
   335 </article>
   148 
   336