From a103417da299e82b2f5073580e2763b73c1659c1 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 15 Nov 2011 17:17:16 +0530 Subject: [PATCH] (password access) backward compat breakage for gl-shell-setup; read below gl-shell-setup has a "run as hosting user" piece that basically automates the adding of the user's (new) key to the admin repo. This is now gone. (It's not that hard to automate yourself if you want to do it anyway, using gl-admin-push). I did this because I needed to allow someone in through a gateway, and realised that that has the exact same needs. So the whole scheme has been changed to treat the proxy and the gitolite host as being two different servers. At that point it became cumbersome to do the second bit, and I left it out. Other changes: - you can define exceptions for the default shell in gl-shell - the doc has been simplified. --- contrib/real-users/gl-shell | 69 ++++++---- contrib/real-users/gl-shell-setup | 80 ++++------- contrib/real-users/password-access.mkd | 176 +++++++++++-------------- 3 files changed, 153 insertions(+), 172 deletions(-) diff --git a/contrib/real-users/gl-shell b/contrib/real-users/gl-shell index 26fe2b4..2501c26 100755 --- a/contrib/real-users/gl-shell +++ b/contrib/real-users/gl-shell @@ -5,31 +5,49 @@ use warnings; # ------------------------------------------------------------------------------ -# site-local changes +# BEGIN site-local changes -# the original login shell your users had (or) the shell to forward -# non-gitolite commands to -my $shell = "/bin/bash"; -# suggested values if you really don't want them actually logging in: -# /sbin/nologin - obvious -# /usr/bin/passwd - same, but allows them to change their passwords + # the original login shell your users had (or) the shell to forward + # non-gitolite commands to + my $shell = "/usr/bin/passwd"; -# the gitolite hosting user you want to forward git commands to. Typically -# this will be 'git' or perhaps 'gitolite', but actually could be anything -my $hosting_user = "gitolite-test"; + # exceptions... + my %shells = ( + 'some.one' => '/bin/bash', + ); -# ADCs... -# either list all the ADCs you wish to allow forwarding to (SPACE-separated): -my $ADC_list = ""; -# -- OR -- -# if you upgraded to the new 'help' adc with the '-list' option, set this to 1: -my $detect_ADCs = 0; -# if you do neither, ADCs are not forwarded + # the gitolite host you want to forward git commands to. Typically this will + # be 'git' or perhaps 'gitolite', but actually could be anything. Don't + # forget to change the host part if needed and mind the quotes! + my $gl_host = 'git@server2'; + + # ADCs... + # either list all the ADCs you wish to allow forwarding to (SPACE-separated): + my $ADC_list = ""; + # -- OR -- + # if you upgraded to the new 'help' adc with the '-list' option, set this to 1: + my $detect_ADCs = 0; + # if you do neither, ADCs are not forwarded + +# END site-local changes # ------------------------------------------------------------------------------ +# change the user's default shell if he is an 'exception' +$shell= $shells{$ENV{USER}} if $shells{$ENV{USER}}; + # no arguments? nothing to forward -exec($shell) unless @ARGV; +exec($shell) if (not @ARGV and not $ENV{SSH_ORIGINAL_COMMAND}); + +# note: we attempt to work the same whether invoked via 'command=' of authkeys +# (in which case SSH_ORIGINAL_COMMAND is set) or via us being the login shell +# (chsh). Only the latter has been *tested* though. + +# massage SSHOC into @ARGV shape for ease of parsing +@ARGV = ("-c", $ENV{SSH_ORIGINAL_COMMAND}) if $ENV{SSH_ORIGINAL_COMMAND}; +# we ignore SSHOC from now on... + +# ------------------------------------------------------------------------------ # forward normal git ops forward(@ARGV) if @@ -37,12 +55,16 @@ forward(@ARGV) if $ARGV[1] =~ /^(git-receive-pack|git-upload-pack|git-upload-archive) '(\S+)'$/ and ( not -d "$2" ); +# ------------------------------------------------------------------------------ + # forward gitolite special commands forward(@ARGV) if $ARGV[0] eq '-c' and $ARGV[1] =~ /^(info|expand|((set|get)(perms|desc)))( |$)/; +# ------------------------------------------------------------------------------ + # forward ADCs if ($ADC_list or $detect_ADCs) { - $ADC_list ||= `ssh $hosting_user\@localhost help -list`; + $ADC_list ||= `ssh $gl_host help -list`; $ADC_list =~ s/\s+/ /g; # find the command he's running @@ -51,20 +73,23 @@ if ($ADC_list or $detect_ADCs) { forward(@ARGV) if $ARGV[0] eq '-c' and $cmd and $ADC_list =~ /(^| )$cmd( |$)/; } +# ------------------------------------------------------------------------------ + # at this point it's back to local processing exec($shell, @ARGV); +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ -# forward to the hosting user +# forward to the gitolite host sub forward { # this message is important in debugging and trouble shooting; see # documentation - print STDERR "[forwarding to $hosting_user\@localhost]\n"; + print STDERR "[forwarding to $gl_host]\n"; # but first we check for rsa key -f ".ssh/id_rsa" or die "ask your admin to add you to gitolite"; shift if $_[0] eq '-c'; - exec("ssh", "$hosting_user\@localhost", @_); + exec("ssh", "$gl_host", @_); } diff --git a/contrib/real-users/gl-shell-setup b/contrib/real-users/gl-shell-setup index 416790c..dcc925d 100755 --- a/contrib/real-users/gl-shell-setup +++ b/contrib/real-users/gl-shell-setup @@ -3,36 +3,26 @@ # WARNING 1: probably contains bashisms galore. If you don't have bash, # please install it. -# NOTE 1: this script is initially run as root, then it calls itself with an -# "su" so it can run as the hosting user. - -# NOTE 2: if you'd rather do this manually, just do the first part as root, -# and the second part as the hosting user, with only the name of the user -# (alice) and her pub key (~alice/.ssh/id_rsa.pub) needing to be passed from -# root to the hosting user id. +# NOTE 1: this script is run as root. +# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ -# site-local changes +# BEGIN site-local changes -# the gitolite hosting user you want to forward git commands to. Typically -# this will be 'git' or perhaps 'gitolite', but actually could be anything -hosting_user="gitolite-test" + # the full path to the new login shell to replace these users' existing shell + new_shell="/usr/local/bin/gl-shell" -# absolute path of the gitolite-admin repo -admin_repo="/home/gitolite-test/repositories/gitolite-admin.git" + my_chsh() { + # please replace with appropriate command for your OS/distro. This one is + # suitable at least for Fedora, maybe others also + chsh -s $new_shell $1 >&2 + } -# the full path to the new login shell to replace these users' existing shell -new_shell="/usr/local/bin/gl-shell" + # remove these 2 lines after you have done your customisation + [ -f /tmp/done.gl-shell-setup ] || { echo please customise $0 before using >&2; exit 1; } -my_chsh() { - # please replace with appropriate command for your OS/distro. This one is - # suitable at least for Fedora, maybe others also - chsh -s $new_shell $1 -} - -# remove these 2 lines after you have done your customisation -[ -f /tmp/done.gl-shell-setup ] || { echo please customise $0 before using; exit 1; } +# END site-local changes # ------------------------------------------------------------------------------ @@ -44,10 +34,6 @@ euid=$(perl -e 'print $>') if [ "$euid" = "0" ] then - # -------------------------------------------------------------------------- - # stuff to be done as root - # -------------------------------------------------------------------------- - [ -n "$1" ] || die "need a valid username" user=$1 id $user >/dev/null || die "need a valid username" @@ -55,51 +41,37 @@ then # now fix up the user's login shell my_chsh $user + pubkey="$PWD/$user.pub" + [ -f "$pubkey" ] && { + echo "$user.pub already exists. Shell changed, exiting..." >&2 + exit 0 + } + # drat... 'cd ~$user` doesn't work... cd $(bash -c "echo ~$user") || die "can't cd to $user's home directory" - # now set up her rsa key, creating it if needed + # now set up her rsa key, creating it if needed. This will get used if + # she comes in via password or without agent forwarding. [ -d .ssh ] || { mkdir .ssh chown $user .ssh chmod go-w .ssh } + [ -f .ssh/id_rsa.pub ] || { - ssh-keygen -q -N "" -f .ssh/id_rsa + ssh-keygen -q -N "" -f .ssh/id_rsa >&2 chown $user .ssh/id_rsa .ssh/id_rsa.pub chmod go-rw .ssh/id_rsa chmod go-w .ssh/id_rsa.pub } - # now run yourself as the hosting user, piping in the pubkey to STDIN, and - # passing the username whose key it is as argument 1. - cat .ssh/id_rsa.pub | su -l -c "$0 $user" $hosting_user + # create alice.pub + cat .ssh/id_rsa.pub > $pubkey exit 0 else - # -------------------------------------------------------------------------- - # stuff to be done as the hosting user - # -------------------------------------------------------------------------- - - user=$1 - - # make a temp dir and switch to it - export tmp=$(mktemp -d) - cd $tmp || die "could not cd to temp dir $tmp" - trap "rm -rf $tmp" 0 - - # clone the admin repo here - git clone $admin_repo . - # copy alice's pubkey, which was sent in via STDIN. We don't want to - # overwrite any *other* keys she may have, hence the @localhost part. - # (See "one user, many keys" in doc/3 for more on this @ part). - cat > keydir/$user@localhost.pub - # add commit push... - git add keydir/$user@localhost.pub - git diff --cached --quiet 2>/dev/null || git commit -am "$0: added/updated local key for $user" - gl-admin-push - # see doc for what/why this is + die "needs to run as root" fi diff --git a/contrib/real-users/password-access.mkd b/contrib/real-users/password-access.mkd index b3e71cc..48491ea 100644 --- a/contrib/real-users/password-access.mkd +++ b/contrib/real-users/password-access.mkd @@ -4,121 +4,105 @@ ## problems -*Problem 1*: Here's one type of problem some admins have: +This document solves several different problems. But first some names: - * Some of your users already have a real (unix) userid on the *same server* - as the gitolite hosting user. - * They don't all use ssh keys; some may still be using passwords and don't - want to change. - * They want to use this existing userid to access the gitolite served repos. + * `alice`: our user + * `server1`: a server on which alice has a shell account or the admin is + willing to give her one + * `git@server2`: the gitolite host (user@server). Server2 may be, but need + not be, the same as server1. -This document has a solution to this problem! +The problems it solves are: -*Problem 2*: And here's a somewhat different one: +1. Alice doesn't like ssh keys and wants to stick to password access (which + won't work with gitolite!), and she has or can get a real (unix) userid on + server1. - * Some of your users are not willing to use ssh keys; they're only - comfortable with passwords. - * But gitolite *requires* ssh key-based access; it can't work if you use a - password to get access (because then there is no way to distinguish one - user from another). +2. Alice is outside your corporate environment and needs to get in to server2 + via server1. -Well, as the math folks say, "reduce it to a known problem". Give them all -Unix userids on the same server as gitolite, with password access, so that -problem 2 reduces to problem 1 ;-) - -If you created these Unix accounts *only* to solve this -pesky password problem, and do not wish them to actually have shell access or -be able to do anything else on the server, don't worry -- that's easy to -handle too. - -## solution - -Briefly, the Unix userid is made to act like a "gitolite proxy". - -Here's a more detailed explanation. - -Normal gitolite flow, for a user called Alice, is like this: - - ssh key - alice ----------------------------------------> git - (workstation) (REQUIRED) (server) - -However, if Alice has her own real (unix) userid on the server, and the admin -sets things up according to this document, then Alice can do this: - - password - alice ------ OR -----> alice - (workstation) ssh key (server) - -The **important** thing to note here is that she doesn't need ssh keys; she -can use passwords if she wants to. - -Behind the scenes, the gitolite/git conversation is being transparently -forwarded to the gitolite hosting user, so it is *actually* like this: - - password ssh key - alice ------ OR -----> alice - - - - - - - > git - (workstation) ssh key (server) (REQUIRED) (localhost) - -The second connection is transparent to Alice; she still thinks she is talking -to her own userid. In git URL terms, she simply uses `alice@server:reponame`, -without realising that behind the scenes this is getting forwarded to -`git@server:reponame`. - -This second connection *does* require ssh keys, but since they're all on the -server, it's scriptable and automatable so the user doesn't have to deal with -these pesky ssh keys. - -## some hints, notes and caveats - - * This doesn't mean all your users have to be like this. You can have - normal users also. In fact, you can have users who give you a pub key - from their workstation the normal way, as well as use this method. +It does this by making `alice@server1` act like a "proxy" for `git@server2`. ## what the 2 scripts actually do - * `gl-shell` will become the new login shell for these users. This shell - will forward git clone/fetch/push requests to the gitolite server. + * `gl-shell` will become the login shell for these users on server1. This + shell will forward git clone/fetch/push requests to "git" on server2. This redirection is so transparent that I had to explicitly code a message ("forwarding to git@server") to make troubleshooting easier. - * `gl-shell-setup` is run by root, once for each user. (You can run it - multiple times; it's designed to be idempotent). As root, it changes the - user's shell to `gl-shell` (full path), then sets up an RSA key for the - user if one is not already present. Then it runs as `git` (or whatever - the hosting user is) and takes the pubkey and adds it as (to continue our - example) `alice@localhost.pub` in keydir of the admin repo, which is then - pushed. + * `gl-shell-setup` sets things up. It needs to be run on server1, where it + changes the user's shell to `gl-shell` (full path), then sets up an RSA + key if needed. - Notice the use of [this trick][oldmultikeys] to allow Alice to allow users - to have other (gitolite normal) keys as well, such as perhaps from a - laptop. +## instructions -## setting up password access +### server setup -Here's how to set this up. First, the **one-time** tasks: +**Server1**: - * Do this first, or you'll forget :-) Add the host key for 'localhost' to - `/etc/ssh/ssh_known_hosts`. And if it ever changes, update it. + * Add the host key for server2 to `/etc/ssh/ssh_known_hosts` on server1. + And if it ever changes, update it. - * Install gitolite as normal, if not already installed. This will require - you to use ssh keys for your (admin's) own access, but I assume that's ok. + ssh-keyscan -t rsa,dsa server2 >> /etc/ssh/ssh_known_hosts - * As root, copy the program `contrib/real-users/gl-shell` to - `/usr/local/bin`. + * You will need to copy the 2 scripts supplied (in contrib/real-users) to + "/usr/local/bin" on server1 and customise them -- i.e., edit the files and + change stuff in the section clearly-marked "site-local changes". - * As root, customise the program `/usr/local/bin/gl-shell`. You will need - to change some variables at the top in a section clearly marked - 'site-local changes'. + **NOTE** on fixing the "chsh" function: this is OS-dependent. Use + whatever command the OS on server1 requires for this to work. The + supplied command is good for Fedora. (Server2's OS does not matter for + this customisation, even though the script is needed there also). - * As root, copy `contrib/real-users/gl-shell-setup` to some place on root's - `$PATH` and customise it similarly to gl-shell. Note that there are many - more configurable values in this script. **NOTE** also that this includes - fixing the `chsh` command, which may be OS/distro dependent. The supplied - command is good for Fedora. +**Server2**: We assume gitolite is already installed on server2. -Now, for each user 'alice' that has her own real (unix) userid, and also needs -to access gitolite *via* her own id, run the command `gl-shell-setup alice`. +### per-user setup -And that's really all there is to it. +There are 2 types of users. + +1. Alice uses a password to access server1, or Alice uses a pubkey to access + server1 but does not use an agent or enable agent forwarding. + + * login as root on server 1. + * make sure a file called 'alice.pub' does NOT exist in the current + directory. + * run `gl-shell-setup alice`. This will create a file called + 'alice.pub' (since it does not exist). + +2. alice uses a pubkey to access server1, and does agent forwarding. + + * login as root on server 1. + * ask the user for the pubkey she uses or get it from the + `authorized_keys` file in her `$HOME/.ssh` on server1. Copy it as + 'alice.pub' in the current directory. + * run `gl-shell-setup alice`. (It will not create the pub file, since + it already exists). + +You can do this for several users in one shot, and collect all the the +pubkeys. + +Once you have collected all of them, send them to server2 or to someone who +has push rights to the admin repo. + +## some hints, notes and caveats + +This doesn't mean all your users have to be like this. You can have normal +users also. In fact, you can have users who give you a pub key from their +workstation the normal way, as well as use this method. (I strongly suggest +that all such keys be placed in `keydir/indirect/` instead of in `keydir/`). + +### security and trust discussion + +For type 1 users, a default key *pair* (i.e., *including* a private key) must +be generated on server1 and given to the gitolite admin for inclusion as the +user's key for gitolite. + +This means that the user must implicitly trust server1's administrators, since +they can impersonate her to server2. (If server1 and server2 are the same +machine or have the same administrators, this does not matter). + +For a type 2 user, no keys need to be generated, and this type of user need +not trust server1 at all. In fact, she's only using this method due to +firewall issues, and the only thing that gl-shell-setup is doing is to run +'chsh'.