diff options
-rw-r--r-- | alternative-way/config.yaml | 11 | ||||
-rwxr-xr-x | alternative-way/gitserve | 61 | ||||
-rwxr-xr-x | create-repo | 6 | ||||
-rwxr-xr-x | gitcmd | 47 | ||||
-rw-r--r-- | readme.txt | 57 |
5 files changed, 182 insertions, 0 deletions
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 <reponame>" + exit 1 +fi +sudo -u git git init --bare "$1" @@ -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 <reponame> + +Example of directory structure: + +in /home/git: + +$ tree --dirsfirst -L 2 +. +├── <reponame> +│ ├── branches +│ ├── hooks +│ ├── info +│ ├── objects +│ ├── refs +│ ├── HEAD +│ ├── config +│ └── description +├── <username>.listrw +├── <username>.listro +├── create-repo +└── gitcmd + +6 directories, 8 files |