Custom shell+trigger to proxy ssh connection to gitolite [email protected] through a proxy/bastion host securely and transparently.
In a setup like this one:
+---------------+ | | [email protected]:myrepo | dev-machine ---------------------------+ | | | +---------------+ | +------------v------+ [email protected]:myrepo | | +---------------------------- myhost.net (gw) | | | | +-v-------------------+ +-------------------+ | | | gitolite (gl) | | host/container/vm | | | +---------------------+
...where "dev-machine" can't access "gl" (gitolite) host directly, allows fully-transparent access to gitolite via specific user on a "gw" (myhost.net) host.
E.g. simply do git add remote origin [email protected]:myrepo
and all the
things gitolite will work, without any extra ssh or forwarding configuration on
git client machine.
gitolite on gl machine has POST_COMPILE "push-authkeys" trigger installed, which
sends public keys from gitolite-admin keydir to gw host (via simple ssh [email protected] < keys
).
[email protected], upon receiving keys (to gitolite-proxy --auth-update
command),
builds authorized_keys in same exact way as gitolite's ssh-authkeys trigger
does, only instead of command="gitolite-shell" it has command="gitolite-proxy"
and authorized_keys file is built on gw host.
Also has one extra key there for [email protected] that runs this
gitolite-proxy --auth-update
command.
Aforementioned push-authkeys trigger (from first step), after sending keys to
[email protected], makes sure that [email protected] key is in ~/.ssh/authorized_keys (in addition
to all gitolite-admin keys, if ssh-authkeys is enabled) with a 3-liner
"gw-proxy" script to run gitolite-shell <key-id>
(reading "key-id" from
command passed by gitolite-proxy).
Every access to [email protected] (using client key) then:
os.execlp(ssh -qT gl_host_login key-id git-cmd...)
.exec gitolite-shell "$key-id"
, i.e. runs gitolite-shell in the same way
as direct ssh to gitolite host would do it.Install /usr/local/bin/gitolite-proxy
on a gw host, updating gl_host_login
line in there and useradd -m git
there.
Run ssh-keygen -t ed25519
as both [email protected] and [email protected], add each host to
~/.ssh/known_hosts on the other one.
Put following line to ~git/.ssh/authorized_keys.base on gw host, replacing pubkey with ~/.ssh/id_ed25519.pub from [email protected] (split here for readability, must be one line):
command="/usr/local/bin/gitolite-proxy --auth-update",no-port-forwarding ,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAA...4u3FI [email protected]
Copy that file to authorized_keys and allow [email protected] write-access to it (will be updated with keys from [email protected]).
As [email protected], run ssh -qT [email protected] < ~/.ssh/authorized_keys
to push gitolite
keys to [email protected]
Add this to ~git/.gitolite.rc on gl host right before ENABLE line:
LOCAL_CODE => "$rc{GL_ADMIN_BASE}/local", POST_COMPILE => ['push-authkeys'],
Commit/push push-authkeys.sh trigger into gitolite-admin repo as
local/triggers/push-authkeys
, updating gw_proxy_login line in there.
Done!
More info on the setup can found in a blog entry at one of these URLs:
Assuming setup from "What it does" section above:
Use separate public host/IP for gitolite, e.g. git.myhost.net (!= myhost.net).
TCP port forwarding or similar tricks.
Forward ssh port connections in a "gw:22 -> gl:22" fashion, and have gw-specific sshd listen on some other port, if necessary.
This can be fairly easy to use with something like this for odd-port sshd in ~/.ssh/config:
Host myhost.net Port 1234 Host git.myhost.net Port 1235
Can also be configured in git via remote urls like
ssh://[email protected]:1235/myrepo
.
Use ssh port forwarding to essentially do same thing as above, but with resulting git port accessible on localhost.
Configure ssh to use ProxyCommand, which will login to gw host and setup forwarding through it.
One advantage of such lower-level forwarding is that ssh authentication to gitolite is only handled on gitolite host, gw host has no clue about that.