grim/hgkeeper

f4875b6bffa5
Add support for integrating with openssh-server
# hgkeeper
hgkeeper is an server for [mercurial](https://www.mercurial-scm.org/)
repositories. It provides access control for SSH access and public HTTP
access via hgweb.
Its original design is to be run in a container, but there are plans to make
it run stand-alone as well.
## License
hgkeeper is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE version 3.
## Status
This project is brand new and only lightly tested. If you find issues, or are
looking for ways to help, please check out our
[issue tracker](https://issues.imfreedom.org/issues/HGKEEPER).
## Building
This project needs to generate some source files, so you'll need to first
install the embedding tool [esc](https://github.com/mjibson/esc).
```
$ go get -u github.com/mjibson/esc
```
Once esc is installed, make sure it's available on your path.
Then you can build hgkeeper with the following commands:
```
$ go generate ./...
$ go build
```
## Getting Started
The initial setup of hgkeeper has a few steps. Since hgkeeper is an SSH server
you will need to generate host keys for it, as well as create the initial
hgkeeper repository which contains the configuration for your install.
### SSH Host Keys
You can generate SSH host keys for whatever type you like, but rsa will cover
just about everyone. That said, a lot of people prefer to use ed25519 as well.
By default the SSH host keys will be looked for in the directory `host-keys` in
the current working directory. This can be changed with the `--ssh-host-keys-path` or `-H` command line arguments to hgkeeper.
This directory will be read and files in it will attempt to be loaded into the server.
To generate a host key you can use the following command, note that you can
create other types via the `-t` option, but you should read the `ssh-keygen`
documentation as other options are avaiable for each type.
```
$ ssh-keygen -t rsa -b 4096 -o host-keys/ssh_host_rsa_key
```
### Create the hgkeeper repo
Before you can run the server we need to create the hgkeeper admin repository.
This can be done via `hgkeeper setup`. You will need to pass the arguments
`--admin-username` which is the name of the admin user, as well as
`--admin-pubkey` which is the path to the SSH public key for the new admin
user. By default this will create a new repository under `repos/hgkeeper`.
There are some additional options which you can discover via
`hgkeeper setup --help`.
## Usage
hgkeeper has a couple of modes of operation but `serve` is the main mode.
### setup
The `setup` command is used to bootstrap hgkeeper. It will create the
directory for the repositories as well as the hgkeeper repository.
After initial setup, please make sure to read the README.md in the hgkeeper
repository that was created, as it details how access control works.
### serve
The `serve` command is the main mode of operation which is to provide access to
the repositories.
## Access Control
Access control is defined in the `hgkeeper` repository that is created via the
`hgkeeper setup` command. It is implemented via [casbin](https://casbin.org)
using the RBAC with deny-override model as a base. More information can be
found in the [files](setup/resources/) that are placed in the `hgkeeper`
repository.
## Running in a Container
HGKeeper is available on docker hub under
[rwgrim/hgkeeper](https://hub.docker.com/r/rwgrim/hgkeeper) and is updated via
CI.
Just like running locally, running in the container is going to require atleast
one ssh host key and an hgkeeper administration repo.
For the rest of these instructions we are going to assume that you have your
ssh host keys in a directory named `host-keys` in the current working
directory.
Once you have your ssh host key generated you can create the administration
repo by running the container with an overridden command.
An extra step to this is that you'll need to volume mount in a file containing
the public key of the initial administration of this instance. In the
following example we assume that that key is in `~/.ssh/id_rsa.pub`.
Also, since this container is just used for initialization of files on the
host, we're passing the `--rm` flag to make sure it's deleted when done.
Finally, hgkeeper runs as an unprivileged user that means that you will have
to create the `repos` directory first and change the owner to the owner to the
user id `22271`. This user id most likely does not exist on your system and
that's fine. You can assign create an assign the directory with the following
commands:
```
mkdir repos
sudo chown 22271 repos
```
Also, that unprivileged user is going to need to be able to read your ssh host
keys so make sure it has access by assigning it as the owner to all files in
your `host-keys` directory.
```
sudo chown -R 22271 host-keys
```
Once that's done you can now run the initialization setup that follows.
```
docker run --rm \
-v $(pwd)/repos:/repos \
-v ~/.ssh/id_rsa.pub:/admin-pubkey:ro \
-e HGK_ADMIN_USERNAME=my_username \
-e HGK_ADMIN_PUBKEY=/admin-pubkey \
-e HGK_REPOS_PATH=/repos \
docker.io/rwgrim/hgkeeper:latest \
hgkeeper setup
```
Once this step is done you sould now have a `repos` directory in your working
directory and it should have a brand new `hgkeeper` repository in it.
Now that your admin repository is all ready to go you can run hgkeeper in its
normal `serve` mode.
The following example uses the same assumptions as the setup container above,
but it is also going to expose the container on the host's network interface.
The following example runs the container in the background, gives it a name of
hgkeeper, and sets it to always restart. If you're just doing testing, you
will probably want to remove the `-d` (background), `--name hgkeeper` (name),
and `--restart=always` options.
```
docker run -d --name hgkeeper \
--restart=always \
-v $(pwd)/host-keys:/host-keys:ro \
-v $(pwd)/repos:/repos \
-e HGK_SSH_HOST_KEYS=/host-keys \
-e HGK_REPOS_PATH=/repos \
-p 8080:8080 \
-p 22222:22222 \
docker.io/rwgrim/hgkeeper:latest \
hgkeeper serve
```
And that's it! You can no access your instance via the hosts IP address or
DNS and you're good to go!
Of course, you'll probably want to add some more users. To find out how to do
that, be sure to read the `README.md` in the `hgkeeper` administration repo.
## Running Locally
Once the SSH host keys and the hgkeeper repository are created, you can run
hgkeeper with `hgkeeper serve`. There are some other options that are
available so be sure to check out `hgkeeper serve --help`.
## Running locally with an OpenSSH Server
There are a number of steps to integrate HGKeeper with OpenSSH Server and some
of them vary across operating system. If you run into a case where these
instructions do not work for you, please reach out via the issue tracker so we
can fix the documentation.
### Creating the hg user
When it comes to integrating with OpenSSH server you need to create a user that
will run HGKeeper during SSH connections and own the repositories on disk. This
user can be named whatever you like, but for the purposes of this documentation
we will be naming the user `hg`.
For most Linux distributions, you can create the `hg` user with the following
command:
```
useradd --home-dir /var/lib/hg --create-home --system --shell /usr/sbin/nologin
```
### Setup HGKeeper
To get HGKeeper fully running, you will need to run `hgkeeper setup` to create
the `hgkeeper` repository as well as the initial admin user. Once this
repository is created, make sure it and it's parent directly are owned by the
`hg` user and that the `hg` user has write permission.
### Installing HGKeeper
OpenSSH server has some very specific requirements for calling applications
directly. These requirements are that the executable as well as all of the
directories leading to the executable must be owned by root and not writeable
by the group or other users. To deal with this, we will be installing HGKeeper
into `/usr/local/bin`. This directory should fulfill all of the those
requirements. So just `sudo cp hgkeeper /usr/local/bin` and make sure that
it is owned by root with a file mode of `755`.
### Configuring OpenSSH Server
The OpenSSH configuration is actually quite easy, you just need to drop the
following snippet into `/etc/ssh/sshd_config`. Of course, if you customized
the install location or user name you'll have to adjust that in the snippet
below. Note that the value for `--repos-path` needs to be the absolute path
to your repositories.
You may be able to use `/etc/ssh/sshd_config.d/hgkeeper.conf` but in our
testing on Debian unstable we were unable to get it working.
```
Match User hg
AuthorizedKeysCommand /usr/local/bin/hgkeeper --repos-path=<path to your repositories> authorized-keys %f
AuthorizedKeysCommandUser hg
```
Once you've created the file, you'll need to restart OpenSSH Server. This is
usually done via `service restart ssh` but may vary based on your operating
system.