This presentation uses HTML Slidy, a simple presentation software from the W3C. Although there’s a help button in the footer of each presentation, it’s missing some important stuff, so here’s a smaller but more complete summary of the keyboard controls.
Navigation Next slide: right arrow, page
down, space
Prev slide: left arrow, page up Down within slide: down
arrow
Up within slide: up arrow First slide: home
Last slide: end |
Display Smaller font: “S” or “<”
key
Larger font: “B” or “>” key Toggle Current versus All
slides: “A” key
Toggle Table of Contents popup: “C” key Toggle footer: “F” key |
To search for stuff in the full document using your browser’s Ctrl-F, first view all slides (press the “A” key).
Before we start, we need to be clear about the difference between authentication and authorisation.
Authentication
|
Authorisation
|
First, we’ll recap how git works over plain ssh.
The client user authenticates herself to the server using any method supported by ssh – password or ssh public key. It does not matter to either the git client or the git server how that happens; that’s entirely between ssh and sshd (the ssh daemon or server).
There is no authorisation in this mode, other than any file system permissions that the OS may enforce.
Gitolite adds an extra layer in between the sshd and the
git-receive-pack (or git-upload-pack, for read operations), to check if
the access is allowed and abort if needed. Gitolite also installs its
own update hook (see man githooks
) in every repository to
check branches being pushed.
This means gitolite does two authorisation checks, as you will see.
Gitolite also requires that the authentication must happen using an ssh public key. We’ll see why as we go along.
Here’s a series of pictures that show how gitolite works. We’re using
a “git push” example; the only difference for a fetch or clone is that
instead of git-receive-pack
it’d call
git-upload-pack
, and the last check (update hook) does not
apply.
Terminology reminder: “ref” in git parlance means “branch or tag”. At least in this page that’s what we mean :-)
The diagrams were originally drawn to be self-contained. On a first pass you can simply ignore the text on each page, and come back to it later for the finer points.
Experts: yes, I know I simplified the ssh part a lot. If you can find fault with these pictures, you’re not the target audience :-)
When the user runs a “git push” command, the git client calls ssh, passing it a command like
git-receive-pack 'reponame'
The git client, before it starts talking to the server, looks for the user’s ssh keys so it can use public key authentication (and not ask for a password).
As you know, for gitolite to work, the user must already have an ssh
key pair and the pub key already sent to the gitolite administrator who
should have added it to gitolite (which in turn means it’s part of
~/.ssh/authorized_keys
on the server).
The ssh client sends the public key to the server to identify itself.
The server looks for the public key in its “list of people who’re
allowed in” (~/.ssh/authorized_keys
). If it finds it,
things are good.
If it doesn’t find it, it tells the client and the client asks the user for a password. Which is BAD, because Gitolite doesn’t work with passwords!
If authentication succeeds, the ssh server calls gitolite-shell, with the username as the first argument. Here’s how that happens.
When the administrator adds Alice’s pubkey to gitolite, he names it “alice.pub”, puts it in the “keydir” directory of a clone of the gitolite-admin repository, and pushes the new file to the server.
When the Gitolite server receives that push, one of the things it
does is add this key to ~/.ssh/authorized_keys
file, but
prefixed with a bunch of options, one of which is a “command” option
that looks like this:
command="/home/git/bin/gitolite-shell alice"
It is this “command” that the ssh daemon executes when the offered public key matches the public key in this line. For a different public key, from a different user, the command will have that user’s name instead of “alice”.
This is how Gitolite distinguishes users from each other, even though
they’re all accessing the same (git@host
) account.
This is also why passwords won’t work. When a user supplies a password, there’s no additional information to help the ssh server distinguish one user from another.
When the ssh daemon decided to execute
/home/git/bin/gitolite-shell alice
instead of the
git-receive-pack 'reponame'
command that the user’s git
client sent to the user’s ssh client, it didn’t simply discard the
git-receive-pack command. It put it in an environment variable called
SSH_ORIGINAL_COMMAND
.
Since that variable contains the repository name, and the username is the first argument passed to it, gitolite-shell now has enough information to decide “is this user allowed to write to this repo” (or “read”, if the command was git-upload-pack).
Assuming access is allowed, gitolite-shell then calls git-receive-pack (or git-upload-pack, as the case may be).
This is the first authorisation check that gitolite does.
Notice that git-receive-pack and git-upload-pack have NO idea that someone snuck in between them and the client calling them. Neither does the git client know. Gitolite is totally transparent to git clients unless access is denied for some reason.
For a read (git-upload-pack), that is the end of the story.
For a write, git will invoke the update hook for each branch or tag
pushed. (See man githooks
for details).
This update hook, of course, has been installed by gitolite, and it proceeds to check if
This is the second authorisation check that gitolite does.
If it is not allowed, the update hooks exits with an error, and git will abort the push (for that ref; other refs sent in the same push may be OK).