Thread (17 messages) flat view 17 messages, 10 authors, 2016-06-15

Re: Git and securing a repository

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:44:02

Gonzalo Garramuo [off-list ref] wrote:
Shawn O. Pearce wrote:
quoted
If you read the documentation carefully you will note that the
pre-receive hook receives input on stdin; 1 line of data per ref
that is being pushed with the old/new SHA-1 values and the ref
name.  The hook exits 0 to allow all changes to take place and
can exit > 0 to abort and disallow all updates.
Sure, but I cannot pass any sort of authentication to the script other 
than rely on environment variables or system calls, as git will not 
provide anything else.
Correct.
 
To do proper authentication on a file or directory basis, I have to mix 
two things then:

A user/group base authentication/login based likely on unix permissions 
and ssh AND a pre-receive hook script that finds the user/group name and 
then checks whether the user can change that particular file/directory.

I hope the ref name is the (relative) path name to the file and not just 
the file's basename.
No, the ref name is the name of the branch being modified.  If there
is only one branch in your repository its probably always going to
be the default name of "refs/heads/master".

If you want to know what files the user has changed you need to
diff the two SHA-1s (old against new) to come up with the names of
the files being changed; e.g.:

	git diff-tree -r $old $new

The update-paranoid hook in contrib has support for doing this
built-in and can allow A/M/D type changes on specific file paths,
entire directories, or any regex pattern that matches the above.
I use this at day-job to prevent users from doing stupid things to
directories they shouldn't be changing on particular branches.
To distinguish a bad commit due to tabs for example from an actual 
permission trouble.  I'm assuming that the stderr/stdout of git hooks is 
redirected back to the client?
You need to diff the old against the new (or use rev-list to list
all of the commits between old and new and then get the patch for
each of those commits) to determine if the commit is "bad" or not.
Remember that a single git-push can upload hundreds of commits in
one shot to the receiving repository.

But yes, both stdout and stderr of the hook are tied to the stderr
of the client running git-push.  So error messages produced by
the hook to explain why the push is being denied are visible to
the end-user who is executing git-push.  Again, update-paranoid
uses this to tell you if the "committer" line in commit objects is
invalid, or if you are changing a file you shouldn't be.
 
Even with all of that, it seems it is still not possible to limit pulls 
to a certain directory only, right?
No.  Git pretty much requires that when you have access to fetch/pull
a repository you have access to *all* of that repository.  Limiting to
a subdirectory would actually require moving that entire subdirectory
into its own repository and using git-submodule instead to manage it.
Anyway, I think I more or less have the answer I (sadly) expected. 
Git's authorization mechanism is pretty much a roll your own type thing. 
 I'll check out the python authorization script that Linus mentioned to 
see if that alleviates setup troubles a bit.
Its a distributed version control system.  All peers are equal.
Most security in Git is handled by only pulling from sources you
trust, and never allowing someone to push stuff into a repository
you own.

As such it also usually boils down to UNIX filesystem security; what
I let you see is what you can see, what I firewall and hide from
you is what you cannot see.  Quite simple when you think about it,
but then you are moving away from a centralized development model
and going to a distributed one... which is what Git was built for.

-- 
Shawn.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help