Atom Feed
Comments Atom Feed

Similar Articles

2009-11-14 13:46
Apache stats on Cacti (via SNMP)
2019-07-28 16:35
git http with Nginx via Flask wsgi application (git4nginx)

Recent Articles

2019-07-28 16:35
git http with Nginx via Flask wsgi application (git4nginx)
2018-05-15 16:48
Raspberry Pi Camera, IR Lights and more
2017-04-23 14:21
Raspberry Pi SD Card Test
2017-04-07 10:54
DNS Firewall (blackhole malicious, like Pi-hole) with bind9
2017-03-28 13:07
Kubernetes to learn Part 4

Glen Pitt-Pladdy :: Blog

Git on (Smart) HTTP with read/write authentication

Services like GitHub are a no-brainer for many use cases, but I've just hit a situation where I needed a tiny private repo and just can't justify paying for a Private GitHub repo, especially when I've already got a load of web servers with SSL I could use. Another scenario for this would be for very sensitive "internal only" data or systems that are isolated from the Internet.

Trouble is, I need my CICD systems to have read-only access, and development user(s) to have full access to checkin new code and I've only been able to find information on separating these when the read-only is public access. That's definitely not what I'm looking for. After a load of reading up on this I've created my own approach on Apache 2.4 on Debian Jessie, but likely to apply similarly to any recent distro.

Some good sources of info I've used for this:


Git (bare) repo for HTTP

First up you need to install the Git package and that contains everything to get started:

$ apt-get install git

A normal "git init" will create a .git/ in the current directory and that contains all the Git storage for the repo. When serving Git over HTTP you need a bare repo on the server. What this essentially means is that the storage is in the directory, rather than a .git/ directory within that. We'll be using /var/lib/git/ for our HTTP served repos, but you could put them any location that Apache can access.

To create a bare repo:

# cd /var/lib/git/
# git init --bare test.git
# chown www-data. test.git
# chmod o-rwx test.git

That will:

  • create the bare repo
  • change ownership to the Apache user to access the repo
  • change permissions to exclude any access from other local users

Making available via HTTP

At this point I'm assuming you have Apache 2.4 installed and a basic site configured with SSL and/or any other restrictions you need, but not authentication. At this stage we will just get the repo available via Smart HTTP. To do this we need to add some config variables and an the CGI component of Git used for Smart HTTP to the site config:

SetEnv GIT_PROJECT_ROOT /var/lib/git/
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

This assumes you are serving your repos below /git from your site. Ensure that you've got CGI configured else this won't work. Reload Apache and you should now be able to access the test repo we created:

$ git clone https://address.of.your.server/git/test.git
... make some changes, add, commit
$ git push origin master

If all that is working then we should be ready to add authentication and authorisation.

Controlling access (authentication)

First off we need to restrict this to authenticated users. We need to create a htpasswd file for this outside of any directories served (it's a security hazard). Let's assume we're putting the file in /etc/apache2/ where other config is.

To add the first user (and create the file), say rwuser, use:

# cd /etc/apache2/
# htpasswd -c htpasswd-git rwuser
.... enter passwords

Now this create a htpasswd-git file with our user in it. After this, don't use the -c option again as wit will create the file again, blowing away any existing users in the file.

We can now add authentication to the Apache site config. This could be done either with a <Files> or <Location> directive. I use <Location> which is URL based:

SetEnv GIT_PROJECT_ROOT /var/lib/git/
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

<Location /git/>
        AuthName "Restricted Git"
        AuthType Basic
        AuthUserFile /etc/apache2/htpasswd-git
        Require valid-user

Essentially this just requires an authenticated user in our htpasswd file. After reloading Apache you should now be required to authenticate if you do a remote Git operation against the repo like above.

If that's working then we should be ready to selectively restrict access.

Controlling access (authorization)

The next thing is to add restrictions on write (push) operations to only allow some users. For this we'll use a group file that sets the users that are allowed this access. For this you need to create a file (I use htgroup-git in /etc/apache2/) containing group name gitwrite and a space separated list of write users (for now just the one), something like:

gitwrite: rwuser

Then we can update the Apache config to start using this:

SetEnv GIT_PROJECT_ROOT /var/lib/git/
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

<Location /git/>
        AuthName "Restricted Git"
        AuthType Basic
        AuthUserFile /etc/apache2/htpasswd-git
        AuthGroupFile /etc/apache2/htgroup-git
        Require valid-user
        <If "%{QUERY_STRING} =~ m#service=git-receive-pack# || %{REQUEST_URI} =~ m#/git-receive-pack$#">
                Require group gitwrite
        Satisfy all

What this is doing is reading the group file, but only requiring an authenticated user for access. The <If> directive then applies a regex to identify write (push) operations and adds an additional requirement of being in the gitwrite group. Satisfy all simply requires that all the requirements be met for access and is implicit, but I've included it for clarity.

To test we should be able to do the Git operations above as user rwuser still, but now need to also have a restricted user, say rouser which we can add with:

# cd /etc/apache2/
# htpasswd -c htpasswd-git rouser
.... enter passwords

This user is not in the gitwrite group so should only be able to read (clone, pull), but authentication should fail for write (push) attempts. Test that to ensure that it's working as expected.

You can then clean up and add real repos and users as needed.

Going Further

This is a basic way of controlling access to a bunch of repos, but if you need per-repo access controls or similar then you can extend this by changing the <Location> directives to match specific repos and adding further groups and group requirements for each repo.

Another approach would be to add and modify the logic in the <If> directives to match repos, not just operations.

Another addition that you might want to consider is gitweb which provides a web repo viewer and in Debian requires little more than installing and enabling the configuration provided with appropriate access restrictions similar to above.



Note: Identity details will be stored in a cookie. Posts may not appear immediately