From ae1ffa7c7a6823423b6c9b961e7d1c28a86af9ef Mon Sep 17 00:00:00 2001 From: VG Date: Tue, 27 Sep 2016 20:39:55 +0200 Subject: first commit --- alternative-way/config.yaml | 11 ++++++++ alternative-way/gitserve | 61 +++++++++++++++++++++++++++++++++++++++++++++ create-repo | 6 +++++ gitcmd | 47 ++++++++++++++++++++++++++++++++++ readme.txt | 57 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 alternative-way/config.yaml create mode 100755 alternative-way/gitserve create mode 100755 create-repo create mode 100755 gitcmd create mode 100644 readme.txt diff --git a/alternative-way/config.yaml b/alternative-way/config.yaml new file mode 100644 index 0000000..1a27a66 --- /dev/null +++ b/alternative-way/config.yaml @@ -0,0 +1,11 @@ +username: + + # example of readwrite access + reponame: rw + + # public + reponame2: ro + +username2: + + reponame2: rw diff --git a/alternative-way/gitserve b/alternative-way/gitserve new file mode 100755 index 0000000..bfb9ea6 --- /dev/null +++ b/alternative-way/gitserve @@ -0,0 +1,61 @@ +#!/usr/bin/python3 + +import sys +import os +import re +import yaml +from sys import stderr + +repo_regex = re.compile(r'\'([a-zA-Z0-9-]+)(.git)?\'$') +command_regex = re.compile('^[a-zA-Z0-9-]+') + +valid_ro_commands=('git-upload-pack') +valid_rw_commands=('git-upload-pack', 'git-receive-pack') + +#print >>sys.stderr, "command d'org: %s" % os.environ['SSH_ORIGINAL_COMMAND'] + +if 'SSH_ORIGINAL_COMMAND' not in os.environ: + print('You are not authorized to login directly.', file=stderr) + sys.exit(1) + +ssh_original_command = os.environ['SSH_ORIGINAL_COMMAND'] +user = sys.argv[1] + +conf = yaml.load(open('/home/calendros/seele/git/config.yaml', 'r')) +#print('conf: ', conf) + +if user not in conf: + print('access not allowed for user {}.'.format(user), file=stderr) + sys.exit(1) + +if ssh_original_command == 'ls' or ssh_original_command == 'list': + print('\n'.join([repo for repo in conf[user].keys()])) + sys.exit(0) + +repo = repo_regex.findall(ssh_original_command)[0][0] +if repo.endswith('.git'): + repo = repo[:-4] + +if repo not in conf[user].keys(): + print('repository {} not allowed for {}.'.format(repo, user), file=stderr) + sys.exit(1) + +command = command_regex.findall(ssh_original_command)[0] + +if ((conf[user][repo] == 'rw' and command not in valid_rw_commands) + or (conf[user][repo] == 'ro' and command not in valid_ro_commands)): + print('command {} not allowed for {}.'.format(command, user), file=stderr) + sys.exit(1) + +os.chdir(os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'repositories')) + +command_map = { + 'git-upload-pack': lambda: os.execv('/usr/bin/git-upload-pack', + ['/usr/bin/git-upload-pack', '--strict', '--timeout=600', repo]), + 'git-receive-pack': lambda: os.execv('/usr/bin/git-receive-pack', + ['/usr/bin/git-receive-pack', repo]) + } + +command_map[command]() diff --git a/create-repo b/create-repo new file mode 100755 index 0000000..2883b58 --- /dev/null +++ b/create-repo @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -n "$1" ]; then + echo "Usage: create-repo " + exit 1 +fi +sudo -u git git init --bare "$1" diff --git a/gitcmd b/gitcmd new file mode 100755 index 0000000..53cd3d8 --- /dev/null +++ b/gitcmd @@ -0,0 +1,47 @@ +#!/usr/bin/python3 + +import sys +import os + +def printerr(*l, **d): return print(*l, **d, file=sys.stderr) +def fail(*l, **d): printerr(*l, **d); raise SystemExit(1) + +try: + user = sys.argv[1] +except IndexError: + fail('Bad adminsys, he forgot to set user associated with this key.') + +try: + with open(user + '.listro', 'r', encoding='utf8') as f: + repositories_ro = f.read().splitlines() +except FileNotFoundError: + repositories_ro = [] + +try: + with open(user + '.listrw', 'r', encoding='utf8') as f: + repositories_rw = f.read().splitlines() +except FileNotFoundError: + repositories_rw = [] + +try: + ssh_original_command = os.environ['SSH_ORIGINAL_COMMAND'].split() + command = ssh_original_command[0] + repository = ssh_original_command[1].split('.git')[0].strip("'") +except IndexError: + if command == 'ls': + print('\n'.join(repositories_ro + repositories_rw or ['Empty list'])) + raise SystemExit(0) + fail('Invalid repository name or git usage') +except KeyError: + fail('Bad boy, git only access authorized.') + +repositories_ro = repositories_ro + repositories_rw +if command == 'git-upload-pack' and repository in repositories_ro: + os.execv('/usr/bin/git-upload-pack', + ['/usr/bin/git-upload-pack', '--strict', '--timeout=600', + repository]) +elif command == 'git-receive-pack' and repository in repositories_rw: + os.execv('/usr/bin/git-receive-pack', + ['/usr/bin/git-receive-pack', repository]) +else: + fail('Bad git command or inexistant repository or access denied') diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..27039f5 --- /dev/null +++ b/readme.txt @@ -0,0 +1,57 @@ +This repository is a quick setup to allow readonly and readwrite access for +git-only through ssh. It is simple but should be secure. You can review the +script for security as it is really short. + + +sudo adduser --home /home/git --no-create-home --shell /bin/sh --gecos 'git version control' --disabled-password git +sudo mkdir /home/git +sudo chown git:git /home/git +sudo chmod 2770 /home/git +sudo cp path/gitcmd /home/git/ +sudo gpasswd -a calendros git + +in /etc/ssh/sshd_config: + +Match User git + X11Forwarding no + AllowTcpForwarding no + AllowAgentForwarding no + PermitTunnel no + GatewayPorts no + PermitTTY no + Banner "Only git access allowed" + AuthorizedKeysFile /etc/ssh/git_keys + +in /etc/ssh/git_keys + +# usage: restrict,command="./gitcmd username" key +# then create a ~git/username.listro for authorized repositories + +username.listro with username replaced with the username given at the gitcmd +argument at the front of the ssh key contains a list of repositories +directory for read-only access. username.listrw contains a list of read-write +access. + +git directories are created with git init --bare + +Example of directory structure: + +in /home/git: + +$ tree --dirsfirst -L 2 +. +├── +│   ├── branches +│   ├── hooks +│   ├── info +│   ├── objects +│   ├── refs +│   ├── HEAD +│   ├── config +│   └── description +├── .listrw +├── .listro +├── create-repo +└── gitcmd + +6 directories, 8 files -- cgit v1.2.3