How single-user Git-over-SSH works
I had to read through so much source code to figure this out
Have you ever wondered how GitHub, GitLab, Gogs, Gitea, and so on allow multiple users to push and pull data from repos with only one unix user? Perhaps you want to know how this is done so you can write your own version of the aforementioned type of software that doesn't suck. That's how I got here. Anyway, this is how it's done:
OpenSSH gives you an option (ForceCommand
in /etc/ssh/sshd_config
) to force
the use of a particular command on connection, overriding the one the client
actually wants to run. When this option is set, the client's "intended command"
gets stored in an environment variable called $SSH_ORIGINAL_COMMAND
. This can
be used to force the execution of your own script (or binary) that allows and
disallows "intended commands" each time anyone tries to do anything with this
account over SSH.
Additionally, the ~/.ssh/authorized_keys
file allows you to specify
a per-key forced command. This means that you can set an option (say,
--with-key
) for the per-key override that isn't present in the global
override in /etc/ssh/sshd_config
. Now, in your forced command, you can
disallow write access to connections that are missing the --with-key
argument,
since it's only present if a user has uploaded an SSH key.
Even further, you can provide the --with-key
argument a key_id
value that
allows your software to know exactly which key was used for this connection.
With that information, you can associate the SSH key with a user account and,
for example, allow them extra read/write access to their private repositories
and extra write access to their public ones. It's up to your software to keep
a database of key_id
<-> SSH key <-> user associations, however.
While you're messing with the sshd_config
, you'll need to add
PermitEmptyPasswords yes
and you'll probably also want to add
DisableForwarding yes
. Thankfully, you can restrict the effects of those two
options to apply only to your software's user and not to everyone on the server
by using a Match
section. All together, your sshd_config
will have a new
section like this:
Match User your_software_user
PermitEmptyPasswords yes
DisableForwarding yes
ForceCommand /path/to/your/software
References
man 5 sshd_config
for/etc/ssh/sshd_config
optionsman 8 sshd
for~/.ssh/authorized_keys
file format and options- Both of the above for the uses of the
$SSH_ORIGINAL_COMMAND
environment variable - The Gogs codebase for reverse-engineering all of the above