grim/hgkeeper

Parents 21e7408ca1a0
Children 33b5ec0c4636
Overhaul the setup command so that we don't need to manually modify the repo
--- a/README.md Tue Sep 10 22:10:18 2019 -0500
+++ b/README.md Tue Sep 10 23:41:43 2019 -0500
@@ -3,31 +3,74 @@
hgkeeper is an server for [mercurial](https://www.mercurial-scm.org/)
repositories. It provides access control for SSH access.
-# License
+It's 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
+## Status
This project is brand new and not even functional yet... But if you're
interested in helping, please do!!
-# Usage
+## 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 we create a new repository under `repos/hgkeeper`.
+There are some additional options which you can discover via
+`hgkeeper setup --help`.
+
+### Running
+
+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`.
+
+## Usage
hgkeeper has a couple modes of operation but `serve` is the main mode.
-## setup
+### setup
The `setup` command is used to bootstrap hgkeeper. It will create the
directory for the repositores, the hgkeeper repository, and create an initial
`access.yml`.
-## serve
+### serve
The `serve` command is the main mode of operation which is to provide access to
the repositories.
-# Access Control
+## 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)
--- a/setup/command.go Tue Sep 10 22:10:18 2019 -0500
+++ b/setup/command.go Tue Sep 10 23:41:43 2019 -0500
@@ -7,12 +7,16 @@
"os"
"path/filepath"
"strings"
+ "text/template"
"bitbucket.org/rw_grim/hgkeeper/globals"
"bitbucket.org/rw_grim/hgkeeper/hg"
)
-type Command struct{}
+type Command struct {
+ AdminUsername string `kong:"flag,name='admin-username',help='the name of the initial admin user',required='true'"`
+ AdminSSHPubkey string `kong:"flag,name='admin-pubkey',help='the path to the ssh pubkey to use for the admin',required='true',type='existingfile'"`
+}
var (
hgUsername = "hgkeeper"
@@ -69,8 +73,36 @@
}
}
- if err := ioutil.WriteFile(absname, FSMustByte(false, name), 0644); err != nil {
- return err
+ // If this is a template file, execute it
+ if filepath.Ext(name) == ".template" {
+ absname = absname[:len(absname)-len(".template")]
+
+ tplate, err := template.New(name).Parse(FSMustString(false, name))
+ if err != nil {
+ return err
+ }
+
+ file, err := os.Create(absname)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ tplateData := struct {
+ AdminUsername string
+ }{
+ AdminUsername: c.AdminUsername,
+ }
+
+ if err := tplate.Execute(file, tplateData); err != nil {
+ fmt.Printf("error: %v\n", err)
+ return err
+ }
+ } else {
+ // If it's not a template just write it out
+ if err := ioutil.WriteFile(absname, FSMustByte(false, name), 0644); err != nil {
+ return err
+ }
}
rel, err := filepath.Rel(path, absname)
@@ -83,6 +115,29 @@
}
}
+ // create our keys directory
+ keysDir := filepath.Join(path, "keys")
+ if err := os.MkdirAll(keysDir, 0755); err != nil {
+ return err
+ }
+
+ // now copy the admin key into the keys directory
+ pubkey, err := ioutil.ReadFile(c.AdminSSHPubkey)
+ if err != nil {
+ return err
+ }
+
+ adminPubkey := filepath.Join(keysDir, c.AdminUsername)
+ relAdminPubkey, err := filepath.Rel(path, adminPubkey)
+ if err != nil {
+ return err
+ }
+
+ filenames = append(filenames, relAdminPubkey)
+ if err := ioutil.WriteFile(adminPubkey, pubkey, 0644); err != nil {
+ return err
+ }
+
// add our files
if err := runCmd(hg.Add(path, filenames...)); err != nil {
return err
--- a/setup/resources/policy.csv Tue Sep 10 22:10:18 2019 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-# This is the default hgkeeper access policy. If you have not yet read
-# README.md in this directory, please read it first.
-#
-# This file contains the access policies as well as groups for all access
-# control via hgkeeper.
-#
-# The format of each policy is:
-#
-# p, user/group, pathspec, permission, effect
-#
-# * p is required to define that this is a policy.
-# * user/group is the name of the user or group that this policy is affecting.
-# * pathspec is glob like pattern of repositories to affect.
-# * permission is one of read, write, or init. If a user has write access, they
-# also have read access. Likewise, init access grants read and write access
-# as well.
-# * effect is one of allow or deny.
-#
-# More than one policy can match, but if any of the matching policies is a deny,
-# then the deny is honored and the user is denied permission.
-
-# allow all authenticated users to read everything
-p, public, /*, read, allow
-
-# give users in the admins group the ability to create repositories everywhere.
-p, admins, /*, init, allow
-
-# deny authenticated, but not explicitly defined users read access to the
-# hgkeeper repo
-p, public, /hgkeeper, read, deny
-
-
-# Groups:
-#
-# The format of a group is as follows:
-#
-# g, user, group
-#
-# * g is required to define that this is a group.
-# * user is the username that is being added to the group.
-# * group is the name of the group.
-#
-# To add your user to the admins group you would replace my-username with your
-# username in the following example:
-#
-# g, my-username, admins
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/setup/resources/policy.csv.template Tue Sep 10 23:41:43 2019 -0500
@@ -0,0 +1,45 @@
+# This is the default hgkeeper access policy. If you have not yet read
+# README.md in this directory, please read it first.
+#
+# This file contains the access policies as well as groups for all access
+# control via hgkeeper.
+#
+# The format of each policy is:
+#
+# p, user/group, pathspec, permission, effect
+#
+# * p is required to define that this is a policy.
+# * user/group is the name of the user or group that this policy is affecting.
+# * pathspec is glob like pattern of repositories to affect.
+# * permission is one of read, write, or init. If a user has write access, they
+# also have read access. Likewise, init access grants read and write access
+# as well.
+# * effect is one of allow or deny.
+#
+# More than one policy can match, but if any of the matching policies is a deny,
+# then the deny is honored and the user is denied permission.
+
+# allow all authenticated users to read everything
+p, public, /*, read, allow
+
+# give users in the admins group the ability to create repositories everywhere.
+p, admins, /*, init, allow
+
+# deny authenticated, but not explicitly defined users read access to the
+# hgkeeper repo
+p, public, /hgkeeper, read, deny
+
+
+# Groups:
+#
+# The format of a group is as follows:
+#
+# g, user, group
+#
+# * g is required to define that this is a group.
+# * user is the username that is being added to the group.
+# * group is the name of the group.
+#
+# This value was adding during when the setup command was run to add
+# {{.AdminUsername}} to the admins group.
+g, {{.AdminUsername}}, admins