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'.