Uberspace / lab

The Uberlab provides various tutorials - written by you! - on how to run software and tools on Uberspace 7.
https://lab.uberspace.de
Other
315 stars 414 forks source link

[gitea] scp not working due to regex used in the command in authorized_keys #1616

Closed sroemer closed 10 months ago

sroemer commented 11 months ago

A while ago I did set up a gitea instance on my uberspace and modified the authorized_keys file with following entry, as shown and described in the gitea guide:

command="if [ -t 0 ]; then bash; elif [[ ${SSH_ORIGINAL_COMMAND} =~ ^(scp|rsync|mysqldump).* ]]; then eval ${SSH_ORIGINAL_COMMAND}; else /home/isabell/gitea/gitea serv key-1 --config='/home/isabell/gitea/custom/conf/app.ini'; fi",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-...

In general this worked fine for me, with the exception that I could not copy files via scp to/from my uberspace. I now did analyze that problem by logging the SSH_ORIGINAL_COMMAND to a file.

It turned out, that in case of using scp for me the command is: /usr/libexec/openssh/sftp-server (since OpenSSH 9.0, the scp program has been updated to use SFTP). Therefore the regular expression ^(scp|rsync|mysqldump).* cannot match. My fix for now is to use ^.*(scp|sftp|rsync|mysqldump).*.

I think this should be fixed in the guide, but I am not sure yet what would be the best regex to use here. While my approach currently works, I added a .* at the beginning of the command as well, which makes this match quite easily - maybe too easy?. On the other hand I also didn't want to add the whole path within the regex.

cmacht commented 11 months ago

... I added a .* at the beginning of the command as well, which makes this match quite easily - maybe too easy?. On the other hand I also didn't want to add the whole path within the regex.

Thanks for posting, ran into the same issues and used your solution!

@sroemer could you help me understand, what the scp -> sftp command looks like so that it only works with .*? Also, why would it match "too easily"? You still need to have the correct ssh key, right?

sroemer commented 11 months ago

@cmacht

When you look at this whole entry, you see that this actually is a shell if condition, which handles 3 different cases. Actually I even did put that whole part in a separate script and used that script as the command in authorized_keys - but that's a detail.

#!/bin/bash
if [ -t 0 ]; then
        # I recently added the additional --login to make bash load .bash_profile on ssh connects
        bash --login
elif [[ ${SSH_ORIGINAL_COMMAND} =~ ^.*(scp|sftp|rsync|mysqldump).* ]]; then
        eval ${SSH_ORIGINAL_COMMAND}
else
        /home/isabell/gitea/gitea serv key-1 --config='/home/isabell/gitea/custom/conf/app.ini'
fi

So the condition checks the value of SSH_ORIGINAL_COMMAND via a regular expression. If it matches, then the command will be executed via the eval call. As I said in the original post already, for me this SSH_ORIGINAL_COMMAND was /usr/libexec/openssh/sftp-server in case of using scp and therefore the regular expression did not match.

With my regular expression as it is now, the first .* will match for the /usr/libexec/openssh/ part, the sftp will match the sftp string itself and the final .* matches on the -server part. But this regex also will match for any other command, which contains scp or sftp for example. That's what I meant with matching quite easily.

You still need to have the correct ssh key and so far I did not see any other issue with it too. In worst case (if ssh is called with a command different from the ones we want to match on, but our expression matches anyway), then we could end in the wrong path of the if condition again. Similar to what happened for us with scp before the modification. The result would just be that something would not work again, because the wrong command is called.

Overall I think that's a quite theoretical problem, but I am not that deeply into SSH and don't know when and how this SSH_ORIGINAL_COMMAND is set.

cmacht commented 11 months ago

Thanks for the fast and exhaustive reply, that makes sense! If you don't mind I would put this and my own issue #1578 into a PR.

Note, from painful experience: Be aware that key-1 is different for each new gitea user and your external script would need to take that into account.

sroemer commented 11 months ago

Good point, yes. My script currently does not work for any other value than key-1, but that could be changed easily by passing the key-X value as a parameter if needed. Thanks for pointing that out and feel free to create a PR if you like to.

cmacht commented 11 months ago

Obviously, you can also put that in the regex (just tried with success): ^(scp|/usr/libexec/openssh/sftp-server|rsync|mysqldump).* ...which is not the prettiest solution, but it gets rid of the problematic behaviour with the catch-all in front.

sroemer commented 11 months ago

Yes sure, that's a way too. The downside is, that it only works if the whole path of the command is exactly the same. If for whatever reason with an OS Update or so, the path changes, then this will not work anymore.

Probably a good compromise would be to do it like this (but I didn't try that yet) : ^(scp|.*sftp-server|rsync|mysqldump).*

It keeps the rule strict for everything except for sftp-server, which when used as a whole is quite unique as well.

cmacht commented 11 months ago

Yes, you're right and that solution is much nicer. Tested it and it works. Thank you!

cmacht commented 10 months ago

@sroemer As a follow-up, you might want to look at the much better solution proposed by @kimdiallo in #1627 - it's already running on my uberspaces.