NOTA BENE: This manual is incomplete and describes the state of Gitano at its 1.0 release.
This document describes what a "Gitano admin" needs to know. Gitano admins are reponsible for setting the policy of a Gitano installation: who can access it, what they can do, what they can't do, and so on. The target audience of this document is those who are members of the gitano-admin
group in a Gitano installation. We assume they know how to use Gitano as a user already, and are comfortable editing plain text files and using git to manage files.
This document is not about installing Gitano or configuring it to work on a system. You can find information on how to do that on the Gitano Wiki at https://wiki.gitano.org.uk/ or in the manual for the gitano-setup
tool.
Gitano admins primarily enable people to do their jobs. This involves:
Access control to Gitano is defined using a language called Lace. Lace is a fairly simple textual language for expressing what actions Gitano users are, and are not, permitted to perform.
Gitano recognises users based on the ssh key they use to log in. (Gitano is also capable of using usernames and passwords though this is typically only used over HTTP(s) and is described further on the Gitano Wiki.) Each user may have multiple keys, but each key may only be used by one user.
Gitano administrators need to be in the gitano-admin
group. When a Gitano instance is first created by the sysadmin (by running gitano-setup
), as part of the process an admin user is created. This user belongs to the gitano-admin
group.
While it may be easiest if the administrators of a Gitano instance have one account that they both for normal Gitano use and for doing admin things, from a security point of view, it is probably better to have a dedicated admin account for doing admin stuff. Further, each admin should have their own admin account on the Gitano instance so that it's easier to see who did what. This requires the admins to have multiple keys, and to configure their ssh so that the right key is used for each account. This can be one with stanzas in ~/.ssh/config
such as these:
Host gitanoadmin
Hostname git.example.com
User git
IdentityFile /home/foo/.ssh/gitanoadmin.key
With a stanza like this, the Host
name need to be used instead of the usual name for the git server:
git clone ssh://gitanoadmin/gitano-admin.git
Managing users and groups is a primary role for Gitano administrators.
Use the commands in the table to manage user and groups. For more detail, give Gitano the command help user
or help group
.
command | description |
user list |
list existing users |
user add |
create a new user |
user del |
remove a user |
group list |
list existing groups |
group show |
show the details of a particular group |
group add |
create a new group |
group del |
remove a group |
group desciption |
set description of group |
group adduser |
add user to group |
group deluser |
remove user from group |
group addgroup |
add group to another group |
group delgroup |
remove group from group |
Typically, groups are used to bestow privileges to users. Gitano admins are added to the gitano-admin
group. A site might have a group devs
for all the users who are developers and thus need to be able to push changes to source code repositories. The site might also have a group ops
, whose members have read-only access to the source code repositories so that they can deploy the software, while having the permission to push changes to their operations repositories.
Creating a site policy such as the above is a job for that site's Gitano admins. Gitano comes with a very basic policy by default. The policy is specified (implemented) using Lace, which we'll look at later.
Repositories are managed using commands in the nearby table. Use the Gitano help
command to get details.
command | description |
ls |
list the repositories on the Gitano instance |
create |
create a new, empty repository |
destroy |
destroy a repository |
copy |
create a new repoistory by copying an existing one |
config |
inspect or set repository configuration |
Configuration variables for repositories are listed in a table.
variable | description |
project.archived |
Whether to hide from ls command and CGit output by default. |
project.description |
description of repo, shown by web interface |
project.head |
where the repository HEAD points, e.g., refs/heads/master |
project.owner |
Gitano user who owns the repository |
You can set any configuration varible, but the project.*
ones have special meaning to Gitano. In addition if you are using CGit as your web interface to your repositories, then cgitrc.*
end up forwarded to the repo stanza in the CGit config.
Lace is a language to describe access control rules for Gitano.
This chapter describes Lace in some detail. It is example driven: rather than starting from a syntax BNF and then describing the semantics of each construct, we'll skip the formalism and go through a series of examples. Note that not every example given here is complete and we recommend that you read the gitano-admin.git::rules/*.lace
files to get a good grip on the default ruleset.
When a Gitano instance is installed and configured by the sysadmin, a repository called gitano-admin
is automatically created. This repository contains administrative information for the Gitano instance:
The Lace ruleset is in the directory rules
in gitano-admin
. A default ruleset is inserted when the Gitano instance is created. Many Gitano sites can just use that, but it is simplistic, and so it may be worth adjusting it for your needs.
The root of the ruleset is in rules/core.lace
. We will have a walkthrough later, after we first cover some of the Lace language.
Starting with a fairly simple example, the below contains a rule to allow a user to do anything to a repository prefixed by their username.
define repo_is_usernamed repository prefix ${user}/
allow "Users can do anything to repos beginning with their username" repo_is_usernamed
Lace rules are used by Gitano whenever the user tries to do anything. Note that they only apply for access to the repositories via Gitano (i.e., over the ssh protocol), and do not apply when access is via other means (e.g., the git protocol itself). When they do apply, however, they apply to everything: pulling, pushing, creating repositories, etc.
Since Lace rules are evaluated from top to bottom, it is very important that you not only define your rules well, but also define them in the right place in the ruleset. The first deny
or allow
rule which succeeds will immediately terminate further rule processing.
When defining rules, you should bear in mind that a rule consists of a condition, and either allow or deny access if the condition is true. For example, the following two rules will allow access to cats, and deny access to dogs:
define user_is_cat user exact cat
define user_is_dog user exact dog
allow "Cats are cool" user_is_cat
deny "Dogs drool too much" user_is_dog
The define
statements define macros to simplify the conditions. This is useful for more complicated things. For simpler things, like the example above, you could write the condition directly into the allow/deny statements:
allow "Cats are cool" [user exact cat]
deny "Dogs drool too much" [user exact dog]
What happens if user is neither cat
nor dog
? Neither condition will be true, and so access is neither allowed nor denied by the above ruleset snippet. Gitano would continue evaluating further rules. If no rule triggers, Gitano uses the default, which is set with the the default
statement:
default deny "The ruleset didn't provide access. Denying by default."
If a default isn't set, the opposite of the last statement is used. If the last statement is allow
, but didn't trigger, the default is deny
, and vice versa. This can be confusing, but works OK for very short rulesets. For anything else, set an explicit default. In addition, once set, the default cannot be overridden later in the ruleset. The initial Gitano ruleset begins with the above default
statement.
The Lace language consists of the following constructs:
allow
and deny
statements, with conditionals.The allow/deny statements look like this:
allow "Everyone can see who they are" [operation exact whoami]
deny "No more repos" [operation exact createrepo]
In other words, the action (allow
or deny
), a message shown to the user if the action is taken, and a Boolean condition that decides if the action should be taken. In the example above, the conditions are operation exact whoami
and operation exact createrepo
. These use the predicate operation
; predicates takes two arguments:
A string comparison operator
This can be one of:
exact
if the operand must be exactly the same as the value. This makes the most sense for the operation
or user
operators. is
is an alias for exact
.prefix
if the value must begin with the operand. starts
and startswith
are aliases for prefix
. prefix
is useful for rules about branch namespaces, and may be used for repository namespaces.suffix
if the value must end with the operand. ends
and endswith
are aliases for suffix
. suffix
is useful for managing roles as suffixes to group names or defining rules which affect repos of the same name in different folders on the server.pattern
if the value must match a Lua string match expression.pcre
if the value must match a Perl-compatible regular expression.Or one of the above with !
prepended to invert the result.
The value to compare against.
In this case our condition evaluates to true if the user is trying to do that operation.
Gitano defines a number of predicates to be used in conditions. See table.
operation |
name of operation (gitano command) |
owner |
username of repository owner |
group |
any of the groups of invoker of gitano or target of as |
ref |
the ref (branch, tag) being operated on |
user |
username of user invoking gitano, or target of as |
repository |
path of repository being operated on |
start_tree |
any of the file names that are in the tree before the commit |
target_tree |
any of the file names that are in the tree after the commit |
treediff/targets |
any of the file names of changed files |
treediff/added |
any of the file names of added files |
treediff/deleted |
any of the file names of deleted files |
treediff/modified |
any of the file names of modified files |
treediff/renamed |
any of the file names of renamed files |
treediff/renamedto |
any of the file names of destinations of a rename |
treediff/kind/$FILE |
The type of object of a file named $FILE in the new version of the tree. |
treediff/oldkind/$FILE |
The type of object of a file named $FILE in the old version of the tree. |
newtype |
Object type of the new tip of the ref (e.g. "tag" or "commit"). |
oldtype |
Object type of the tip of the ref before the update. |
newsha |
SHA1 Object ID of the new tip of the ref |
oldsha |
SHA1 Object ID of the tip of the ref before the update. |
newtaggedtype |
If new tip of the ref is a tag, type of the object that is tagged. |
oldtaggedtype |
If old tip of the ref is a tag, type of the object that is tagged. |
newtaggedsha |
If new tip of the ref is a tag, object ID of the object that is tagged. |
oldtaggedsha |
If old tip of the ref is a tag, object ID of the object that is tagged. |
newsigned |
"yes" if the new tip of the ref is signed |
oldsigned |
"yes" if the old tip of the ref is signed |
config/* |
Value of the config option with "/" converted to ".". |
as_user |
username of user invoking as otheruser |
as_group |
any of the groups of user invoking as otheruser |
targetuser |
username in a user manipulation command |
targetgroup |
the group in a group manipulation command |
member |
the user or group to be added to targetgroup in group manipulation commands. |
keyringname |
Name of the keyring being modified or inspected. |
key |
Name of the configuration key being inspected or modified |
value |
Value to set in configuration. |
Predicates can be combined using the operators anyof
and allof
:
allow "Mammals are cool" anyof [user exact cat] [user exact dog]
These operators are followed by a list of conditions, and the result is true if any condition, or all conditions, respectively, are true. anyof
is Boolean OR, allof
is Boolean AND.
The result of an individual condition for allow
, deny
, anyof
or allof
, may be negated with the boolean NOT operation (!
):
deny "No cats" ![user exact cat]
Predicates may also have the negation of their operation specified, so the following is equivalent to the above.
deny "No cats" [user !exact cat]
Gitano defines a number of variables to be used in conditions. See table. These provide values that predicates test. The list of values depends on the operation being run.
Operations | Variable | Description |
all | operation | The current operation being run. |
all | source | Protocol used to interact with Gitano. ("git", "http" or "ssh"). |
all | user | Current Gitano user or "gitano/anonymous". |
all | config/* | Any set config key with "." replaced with "/". |
all | as_user | Username of user invoking as otheruser . |
all | keytag | Name of SSH key user authorised with, or "" via HTTP. |
most | repository | Which repository is being operated on. |
most | repository/$N | Component N of the repository path when split by "/". |
most | repository/basename | Last component of the repository split by "/". |
most | repository/dirname | Components of repository split by "/" except for the last one. |
config | key | The key being modified or inspected. |
config set | value | The value to assign to the key. |
user modify | targetuser | User being created, renamed, deleted or modified. |
group modify | targetgroup | Group being modified |
group modify | targetgroup/$N | Component N of group when name is split by "-". |
group modify | targetgroup/suffix | Last component of group when name is split by "-". |
group modify | targetgroup/prefix | All but the last component of group when name is split by "-". |
group modify | member | User or group being added or removed from targetgroup . |
group modify | member/$N | Component N of user or group when name is split by "-". |
group modify | member/suffix | Last component of user or group when name is split by "-". |
group modify | member/prefix | All but the last component of user or group when name is split by "-". |
graveyard | target | Name of destination when restoring. Name of entry when purging. |
keyring | keyringname | Name of keyring being manipluated or inspected. |
ref update | ref | Name of the ref being updated. |
ref update | newtype | Object type of the new tip of the ref (e.g. "tag" or "commit"). |
ref update | oldtype | Object type of the tip of the ref before the update. |
ref update | newsha | SHA1 Object ID of the new tip of the ref |
ref update | oldsha | SHA1 Object ID of the tip of the ref before the update. |
ref update | newtaggedtype | If new tip of the ref is a tag, type of the object that is tagged. |
ref update | oldtaggedtype | If old tip of the ref is a tag, type of the object that is tagged. |
ref update | newtaggedsha | If new tip of the ref is a tag, object ID of the object that is tagged. |
ref update | oldtaggedsha | If old tip of the ref is a tag, object ID of the object that is tagged. |
ref update | newsigned | "yes" if the new tip of the ref is signed |
ref update | oldsigned | "yes" if the old tip of the ref is signed |
Variables are used as interpolations for the value of a predicate.
Interpolations are written in the form ${variable}
. If the variable is not defined then it expands to the empty string.
So a rule that permits the owner of a repository to do whatever they want is:
define repo_is_set repository pcre .
define is_owner config/project/owner exact ${user}
allow "Owners may do anything to repositories they own" repo_is_set is_owner
Since user
and config/project/owner
are both predicates and variables is_owner
can be written the other way around too.
define is_owner user exact ${config/project/owner}
The only constraint to worry about when deciding if a term should be used as a variable or as a predicate is that when expanding, variables can't have multiple values. So group
can't be used as a variable, but can be a predicate.
If you had a config option which was a list of the contributors to a project you would be unable to check it with:
define is_contributor user exact ${config/project/contributors}
However it you could check for it with:
define is_contributor config/project/contributors exact ${user}
A Lace statement may include another rules file. The search path is as follows:
If the included filename starts with global:
it is included from the adminref (master
branch of gitano-admin.git
), directory rules
. Thus, include global:foo
means including rules/foo.lace
from the adminref.
Otherwise, without the global prefix, it is included from the per-project rules (refs/gitano-admin
branch of the repository being operated on).
Include statements can be made conditional by adding a predicate after the path, so you can split up your rules:
#main.lace
include update anyof [operation exact createref] [operation exact deleteref] [operation exact updaterefnonff] [operation exact updaterefff]
#update.lace
# Require fast-forward updates to refs/heads/master
deny "master may not be rebased" [ref exact refs/heads/master] [operation exact updaterefnonff]
# Branches must not be tags
deny "Branches may only be commits" [ref prefix refs/heads/] [newtype exact commit]
When gitano-setup is run, the admin needs to specify a Unix user in whose home directory the git repositories stored. In this section we'll assume the home directory is /home/git
.
To backup a Gitano instance, simply backup /home/git
. To restore, restore the directory and ensure the user exists in the system.
As an administrator, the stability of Gitano's interface is very important to understand.
During setup of a Gitano instance, as well as the initial administrator user, the gitano-setup
tool also created a user called gitano-bypass
. The bypass user is normally entirely unused, however it would behoove the sysadmin of the Gitano instance to understand that to use an SSH key associated with the bypass user will result in all rules, hooks, etc. being ignored. This can cause issues if hooks are used to manage effects of changing git repositories; however it can also be the only way to correct certain issues (such as if an instances' administrators lock themselves out).
Before using the bypass functionality, it is recommended that the sysadmin consult the Gitano wiki and also any administrators of the instance to ensure that they perform the minimum necessary change to restore access.
This administration manual is Copyright 2016-2017 Lars Wirzenius, Daniel Silverstone, and Richard Maw. In addition, the images are Copyright 2017 Maxine Green.
The manual content and images are provided under the terms of the Creative Commons Attribution Sharealike 4.0 licence. You can find the full terms of the CC-BY-SA-4.0 licence at https://creativecommons.org/licenses/by-sa/4.0/legalcode. The following is a summary of the licence:
You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
In addition, if you are reading the HTML version, then the CSS is under the Creative Commons Zero licence (see the header of the CSS document for details).