(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.
This commit is contained in:
Sitaram Chamarty 2011-11-15 17:17:16 +05:30
parent 97bd5c5c96
commit a103417da2
3 changed files with 153 additions and 172 deletions

View file

@ -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 # the original login shell your users had (or) the shell to forward
# non-gitolite commands to # non-gitolite commands to
my $shell = "/bin/bash"; my $shell = "/usr/bin/passwd";
# 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 gitolite hosting user you want to forward git commands to. Typically # exceptions...
# this will be 'git' or perhaps 'gitolite', but actually could be anything my %shells = (
my $hosting_user = "gitolite-test"; 'some.one' => '/bin/bash',
);
# ADCs... # the gitolite host you want to forward git commands to. Typically this will
# either list all the ADCs you wish to allow forwarding to (SPACE-separated): # be 'git' or perhaps 'gitolite', but actually could be anything. Don't
my $ADC_list = ""; # forget to change the host part if needed and mind the quotes!
# -- OR -- my $gl_host = 'git@server2';
# if you upgraded to the new 'help' adc with the '-list' option, set this to 1:
my $detect_ADCs = 0; # ADCs...
# if you do neither, ADCs are not forwarded # 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 # 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 normal git ops
forward(@ARGV) if forward(@ARGV) if
@ -37,12 +55,16 @@ forward(@ARGV) if
$ARGV[1] =~ /^(git-receive-pack|git-upload-pack|git-upload-archive) '(\S+)'$/ and $ARGV[1] =~ /^(git-receive-pack|git-upload-pack|git-upload-archive) '(\S+)'$/ and
( not -d "$2" ); ( not -d "$2" );
# ------------------------------------------------------------------------------
# forward gitolite special commands # forward gitolite special commands
forward(@ARGV) if $ARGV[0] eq '-c' and $ARGV[1] =~ /^(info|expand|((set|get)(perms|desc)))( |$)/; forward(@ARGV) if $ARGV[0] eq '-c' and $ARGV[1] =~ /^(info|expand|((set|get)(perms|desc)))( |$)/;
# ------------------------------------------------------------------------------
# forward ADCs # forward ADCs
if ($ADC_list or $detect_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; $ADC_list =~ s/\s+/ /g;
# find the command he's running # 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( |$)/; forward(@ARGV) if $ARGV[0] eq '-c' and $cmd and $ADC_list =~ /(^| )$cmd( |$)/;
} }
# ------------------------------------------------------------------------------
# at this point it's back to local processing # at this point it's back to local processing
exec($shell, @ARGV); exec($shell, @ARGV);
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# forward to the hosting user # forward to the gitolite host
sub forward { sub forward {
# this message is important in debugging and trouble shooting; see # this message is important in debugging and trouble shooting; see
# documentation # documentation
print STDERR "[forwarding to $hosting_user\@localhost]\n"; print STDERR "[forwarding to $gl_host]\n";
# but first we check for rsa key # but first we check for rsa key
-f ".ssh/id_rsa" or die "ask your admin to add you to gitolite"; -f ".ssh/id_rsa" or die "ask your admin to add you to gitolite";
shift if $_[0] eq '-c'; shift if $_[0] eq '-c';
exec("ssh", "$hosting_user\@localhost", @_); exec("ssh", "$gl_host", @_);
} }

View file

@ -3,36 +3,26 @@
# WARNING 1: probably contains bashisms galore. If you don't have bash, # WARNING 1: probably contains bashisms galore. If you don't have bash,
# please install it. # please install it.
# NOTE 1: this script is initially run as root, then it calls itself with an # NOTE 1: this script is run as root.
# "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.
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# site-local changes # BEGIN site-local changes
# the gitolite hosting user you want to forward git commands to. Typically # the full path to the new login shell to replace these users' existing shell
# this will be 'git' or perhaps 'gitolite', but actually could be anything new_shell="/usr/local/bin/gl-shell"
hosting_user="gitolite-test"
# absolute path of the gitolite-admin repo my_chsh() {
admin_repo="/home/gitolite-test/repositories/gitolite-admin.git" # 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 # remove these 2 lines after you have done your customisation
new_shell="/usr/local/bin/gl-shell" [ -f /tmp/done.gl-shell-setup ] || { echo please customise $0 before using >&2; exit 1; }
my_chsh() { # END site-local changes
# 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; }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -44,10 +34,6 @@ euid=$(perl -e 'print $>')
if [ "$euid" = "0" ] if [ "$euid" = "0" ]
then then
# --------------------------------------------------------------------------
# stuff to be done as root
# --------------------------------------------------------------------------
[ -n "$1" ] || die "need a valid username" [ -n "$1" ] || die "need a valid username"
user=$1 user=$1
id $user >/dev/null || die "need a valid username" id $user >/dev/null || die "need a valid username"
@ -55,51 +41,37 @@ then
# now fix up the user's login shell # now fix up the user's login shell
my_chsh $user 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... # drat... 'cd ~$user` doesn't work...
cd $(bash -c "echo ~$user") || die "can't cd to $user's home directory" 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 ] || { [ -d .ssh ] || {
mkdir .ssh mkdir .ssh
chown $user .ssh chown $user .ssh
chmod go-w .ssh chmod go-w .ssh
} }
[ -f .ssh/id_rsa.pub ] || { [ -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 chown $user .ssh/id_rsa .ssh/id_rsa.pub
chmod go-rw .ssh/id_rsa chmod go-rw .ssh/id_rsa
chmod go-w .ssh/id_rsa.pub chmod go-w .ssh/id_rsa.pub
} }
# now run yourself as the hosting user, piping in the pubkey to STDIN, and # create alice.pub
# passing the username whose key it is as argument 1. cat .ssh/id_rsa.pub > $pubkey
cat .ssh/id_rsa.pub | su -l -c "$0 $user" $hosting_user
exit 0 exit 0
else else
# -------------------------------------------------------------------------- die "needs to run as root"
# 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
fi fi

View file

@ -4,121 +4,105 @@
## problems ## 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* * `alice`: our user
as the gitolite hosting user. * `server1`: a server on which alice has a shell account or the admin is
* They don't all use ssh keys; some may still be using passwords and don't willing to give her one
want to change. * `git@server2`: the gitolite host (user@server). Server2 may be, but need
* They want to use this existing userid to access the gitolite served repos. 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 2. Alice is outside your corporate environment and needs to get in to server2
comfortable with passwords. via server1.
* 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).
Well, as the math folks say, "reduce it to a known problem". Give them all It does this by making `alice@server1` act like a "proxy" for `git@server2`.
Unix userids on the same server as gitolite, with password access, so that
problem 2 reduces to problem 1 ;-)
<font color="gray">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.</font>
## 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.
## what the 2 scripts actually do ## what the 2 scripts actually do
* `gl-shell` will become the new login shell for these users. This shell * `gl-shell` will become the login shell for these users on server1. This
will forward git clone/fetch/push requests to the gitolite server. 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 This redirection is so transparent that I had to explicitly code a message
("forwarding to git@server") to make troubleshooting easier. ("forwarding to git@server") to make troubleshooting easier.
* `gl-shell-setup` is run by root, once for each user. (You can run it * `gl-shell-setup` sets things up. It needs to be run on server1, where it
multiple times; it's designed to be idempotent). As root, it changes the changes the user's shell to `gl-shell` (full path), then sets up an RSA
user's shell to `gl-shell` (full path), then sets up an RSA key for the key if needed.
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.
Notice the use of [this trick][oldmultikeys] to allow Alice to allow users ## instructions
to have other (gitolite normal) keys as well, such as perhaps from a
laptop.
## 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 * Add the host key for server2 to `/etc/ssh/ssh_known_hosts` on server1.
`/etc/ssh/ssh_known_hosts`. And if it ever changes, update it. And if it ever changes, update it.
* Install gitolite as normal, if not already installed. This will require ssh-keyscan -t rsa,dsa server2 >> /etc/ssh/ssh_known_hosts
you to use ssh keys for your (admin's) own access, but I assume that's ok.
* As root, copy the program `contrib/real-users/gl-shell` to * You will need to copy the 2 scripts supplied (in contrib/real-users) to
`/usr/local/bin`. "/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 **NOTE** on fixing the "chsh" function: this is OS-dependent. Use
to change some variables at the top in a section clearly marked whatever command the OS on server1 requires for this to work. The
'site-local changes'. 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 **Server2**: We assume gitolite is already installed on server2.
`$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.
Now, for each user 'alice' that has her own real (unix) userid, and also needs ### per-user setup
to access gitolite *via* her own id, run the command `gl-shell-setup alice`.
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'.