Git ssh

From wikinotes

You can host your git repos on your own servers using SSH.

Setup

Create Repo

On the remote server that you wish to store repo, create it.

cd /path/projectname
git init --bare

On your computer, create an empty repo, and push to remote server

git remote add origin ssh://git@gitbox:8610/home/git/my_project
git --set-upstream origin --all
git push

Clone Repo

From this point onwards, you can clone the repo like this:

git clone ssh://user@10.10.10.10:/path/to/repo

You can also shorten it with an ssh config

# ~/.ssh/config
Host myhost
  Hostname 10.10.10.10
  IdentityFile ~/.ssh/mykey
  User user
git clone ssh://myhost:/path/to/repo

# you can also change the SSH command used
GIT_SSH_COMMAND="ssh -i ~/.ssh/foo" git clone ssh://myhost:/path/to/repo

# you can also specify it in the git config, but you'll need to configure it for each clone

Configuration

Git Shell

If you'd like to restrict this user's SSH access to git operations,
you can configure it's shell to be git-shell (included with git).

For example

adduser foo
chsh foo /usr/local/libexec/git-core/git-shell

You should further restrict git-shell to disallow the anything other than git commands.
You can do this when adding public keys to your server's ~/.ssh/authorized_keys.

# ~/.ssh/authorized_keys
restrict ${YOUR_PUBKEY}

See man git-shell for details.

Read-Only Access

SSH Permissions

You can restrict the commands that can be performed by a user authenticated with a particular SSH key in ~/.ssh/authorized_keys
by assigning the command= and restrict keys.

According to man git-shell, these are the only commands used by git-shell (unless you add your own).

git-receive-pack git push
git-upload-pack git fetch
git-upload-archive git archive

This is probably a bit simplistic, but here's the general idea:

#!/usr/bin/env bash
#
# /usr/local/bin/git-readonly
#
# SSH_ORIGINAL_COMMAND stores the original command,
# it's a string (not an argument array)

set -ef
set -- $SSH_ORIGINAL_COMMAND  # NO QUOTES!


case $1 in
    git-upload-pack|git-upload-archive)
        eval "$SSH_ORIGINAL_COMMAND"
        ;;
    *)
        exit 1
        ;;
esac

Finally, configure your authorized_keys file to force this command on SSH.

# ~/.ssh/authorized_keys
command="/usr/local/bin/git-readonly,restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH8bvsTLbNF7uk3keTz1qZFgKpexLH0pF2V2zjUJBpas

Some nice features with this workflow are:

  • use same user account, but different keys for read-write/read-only (ex: use same vim-plug urls, change key in SSHConfig)
  • allow write access, but only to allowlisted directories

The disadvantages of this workflow are:

  • incompatible with git-shell -- be mindful of exploits!

Filesystem Permissions

You can setup read-only access, by creating users and changing user/file permissions.
The safest route is probably creating a separate unix group for each repo,
then you can manage repo access by adding unix users to groups.

The downside here is that creating new repos is more time consuming,
and when replacing the server you'll need to recreate all of these users/groups.