Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restrict git SSH access based on ssh key given

Tags:

git

ssh

ssh-keys

I have a private git server with one user git and ssh key authentication. Currently, I am the only one using it, but I want to add more people and I want everyone to use user git to connect to the server and perform git clone, git push, etc. If all the repositories are "public", then I know how to solve this. But for example I want to have a private repository, that I will still clone via git clone git@server:repo with my SSH key, however I do not want other users to be able to clone it using their SSH keys.

I checked git-scm documentation on setting up the server (which was helpful for public repositories), and this post, however this post seems to only solve the problem for only private repositories.

TLDR: When you clone a repository on GitHub, you say git clone [email protected]:user/repo and your git username and ssh key are being sent over. Now, depending on whether you have the permissions to this repository, you can clone it, otherwise not. So basically, everyone is using git user on the surface, but under the hood some authorisation is taking place. How does GitHub handle this for example?

like image 890
campovski Avatar asked Jun 26 '26 23:06

campovski


2 Answers

gitolite seems to be exactly what you are looking for managing access to repositories/branches based on the ssh key.

But if you want to build something like this from scratch you need to look into the options in the authorized_keys file, especially command and environment. With these you can force a specific command/script or add/overwrite environment variables based on which ssh key was used.

For example you could write a script that reads the allowed repositories for the user as its arguments and force it to be run for selected ssh keys:

# file ~/.ssh/authorized_keys
command="/home/git/bin/git-only-shell /home/git/repos/repo1" ssh-rsa AAAAB2...
command="/home/git/bin/git-only-shell /home/git/repos/repo1 /home/git/repos/repo2" ssh-rsa AAAAB3...

The script can now read the requested repo from $SSH_ORIGINAL_COMMAND and check that it is contained in the passed list. A complete - but crude - example implementation of this script git-only-shell could be like this:

#!/bin/bash

# verify that $SSH_ORIGINAL_COMMAND starts with git-upload-pack, git-upload-archive or
# git-receive-pack, followed by a space
if ! [[ "$SSH_ORIGINAL_COMMAND" == git-upload-pack\ * || "$SSH_ORIGINAL_COMMAND" == git-upload-archive\ * || "$SSH_ORIGINAL_COMMAND" == git-receive-pack\ * ]]; then
    echo "unsupported command" >&2
    exit 1
fi

# remove first word (git command)
ARGUMENTS="${SSH_ORIGINAL_COMMAND#git-* }"

# use eval to un-quote repo path (it is passed in single-quotes)
REPO_PATH="$(eval "echo $ARGUMENTS")"

# allowed repos are passed as arguments to this script
ALLOWED_REPOS=("$@")

# check if repo was whitelisted
IS_ALLOWED=false
for repo in "${ALLOWED_REPOS[@]}"; do
    if [[ "$REPO_PATH" == "$repo" ]]; then
        IS_ALLOWED=true
    fi
done

if [[ $IS_ALLOWED == "false" ]]; then
    echo "access to this repo not allowed" >&2
    exit 1
fi

# execute the original command
eval "$SSH_ORIGINAL_COMMAND"
like image 81
acran Avatar answered Jun 28 '26 13:06

acran


To implement a similar feature, you could rely on a dedicated tool such as gitolite.

Otherwise, you could install a full-blown GitLab server which would also provide fine-grained access control to the repositories, with "Git URLs" such as [email protected]:user/repo.git

(BTW it seems GitLab formerly relied on gitolite, before version 5.0.0)

like image 42
ErikMD Avatar answered Jun 28 '26 13:06

ErikMD