Different way to do fossil over ssh with RBAC
(1) By John Rouillard (rouilj) on 2021-09-26 05:03:09 [link] [source]
This is an alternate way to access fossils over ssh. It does away with the wrapper and changes to sshd_config. Also local user accounts aren't needed. If a user does have local shell access, they have no access to the repos. They have to use fossil to access the repos.
It uses the ~fossil/.ssh/authorized_keys
file to specify the forced command
and tighten up restrictions.
- set up a fossil user and museum same as documented in
https://fossil-scm.org/home/doc/trunk/www/server/any/http-over-ssh.md.
However, set up the museum to be accessible only to the fossil user.
- there is no need to create accounts on the server for the users
- nor is there a need to create a common group for them.
- for each user who should use fossil create an entry in
~fossil/.ssh/authorized_keys
like:command="REMOTE_USER=rou fossil http museum/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-x11-forwarding,restrict ssh-rsa AAAAB3NzaC1yc2EAA<more key here>9BoaS0U= rou-fossil
- note in the command the
REMOTE_USER
is hardcoded so you can use any name for the fossil user. I haven't tried it but it could be used to define the REMOTE_USER using an email address as a universal identifier. I have only used Unix compatible identifiers. - Only the directory (or a single fossil repo) is specified. If a directory is used, the fossil repo is taken from the http protocol POST command. Note that the trailing / on museum is removed. This is discussed later.
- The
restrict
option alone does the same things that all the otherno-
options do explicitly. However some sshd servers don't support restrict and the explicit options are needed. So either useno-
options or restrict. This set of restrictions prevents:- ssh-agent forwarding (same as in the http-over-ssh.md doc)
- tcp port forwarding (again covered in the doc)
- requesting a pty. This is not possible using sshd-config and makes sure there is a clean 8-bit path. It can also prevent shenanigans by a user trying to use the ssh key outside of a fossil command
- running the ~fossil ssh rc file. There shouldn't be one anyway so this is a belt and suspenders no-op
- X11 forwarding (as covered in the doc)
Also it would be nice to be able to specify:
fossil http museum/ --allow-remote-user
to eliminate the requirement that the remote-user be enabled on the repo.
This would allow ssh access (say for users that can check in code).
As well as HTTP access to the forum/wiki pages for users/anonymous
without enabling REMOTE_USER over the HTTP server path.
As I mentioned above the trailing / on the directory museum/
is stripped.
This means that the fossil clone call has to change a bit to:
fossil clonefossil@ ssh://fossil_host//fossil_repo
to clone museum/fossil_repo.fossil
(note the double / after the hostname).
It would be nice if it wasn't stripped so the double // before fossil_repo
could be just a single /. Without the double /, the HTTP traffic starts with:
POST demo_roundup_child_test HTTP/1.0
that leads to a repo not found. With the double / I get:
POST /demo_roundup_child_test HTTP/1.0
and successful access.
A client side .ssh/config for the ssh://fossil/
URL could be:
host fossil
hostname my_fossil.server.com
IdentityFile ~/.ssh/fossil_scm
IdentitiesOnly yes
IdentityAgent none
User fossil
which:
- sets the ssh identity key file to use for fossil access
- prevents taking an identity from an ssh-agent or using the default id_rsa etc keys. I assume that the user has other ssh keys used for access to shell accounts, so I want to disable those for efficiency since they won't work.
Alternate forms of the clone:
fossil clone ssh://user@fossil_host//fossil_repo
can also
be used if the user isn't coded into a config.
(2) By Warren Young (wyoung) on 2021-09-26 10:35:13 in reply to 1 [link] [source]
It's an interesting alternative. I'm on another project, so I won't get back to that article for a time, but it does seem worth splitting the article into two alternative solutions.
(3) By John Rouillard (rouilj) on 2021-09-26 13:01:14 in reply to 2 [link] [source]
Hi Warren:
Thanks. Also I was expecting the -U
, --user
common option would work
but in testing it appears only the REMOTE_USER is used. if -U worked
it would be even cleaner:
command="fossil -U rouilj http museum/"
- No need to enable REMOTE_USER so no need for
--allow-remote-user
or to enable REMOTE_USER in this context.
Not sure why -U isn't used. I used this same mechanism for remote SSH access
to svn repos many years ago (the option for svnserv is --tunnel-user
).
Maybe a bug in --user
support?
(4) By Andy Bradford (andybradford) on 2021-09-26 17:12:21 in reply to 1 [link] [source]
> This is an alternate way to access fossils over ssh. Yes, in fact, my original suggestions for using Fossil over SSH was very similar if not identical, and in fact, I've suggested just about every variation on the theme (one with wrappers, one without, single account using keys (ala git), multiple accounts, one with changes to sshd_config, requiring Fossil Capabilities using ForceCommand, etc.): https://marc.info/?l=fossil-users&m=144565808636962&w=2 The point is that Fossil and SSH are fairly flexible in what can be accomplished---just depends on the needs and goals. Also, with respect to double slash vs single slash, the Fossil client when talking SSH, doesn't think of it as "single slash vs double slash", but instead parses a URL. It parses the host followed by single slash. Anything that remains is the "path", hence: ssh://remotehost//path Fossil removes everything, including a slash (as part of the URL) "ssh://remotehost/" and what remains is simply "/path". For SSH specifically, this becomes the difference between an absolute path, and a relative path. A relative path obviously permits the remote server to interpret the path to a file as relative to whatever the working directory of the remote shell is. This is why you observe that when there is no slash in the path portion of the URL that it fails---the SSH client thinks you want a relative path on the server. However, the client isn't aware that "fossil http directory" is being run and so it doesn't know to treat the SSH request as if it were really an HTTP request, and consquently requests a "relative" repository path. I'm not sure that this should be changed (just tell people to clone using /repo as the path), but any change would probably need to happen on the server side because the Fossil client operating in SSH mode cannot easily know that the remote side is forcing commands. Andy
(5) By John Rouillard (rouilj) on 2021-09-27 00:46:45 in reply to 4 [link] [source]
Hi Andy:
This is an alternate way to access fossils over ssh.
Yes, in fact, my original suggestions for using Fossil over SSH was very similar if not identical,
Doesn't surprise me. My svnserve stuff was done in 2006/2007 or so. I remember reading something similar to what I had done with svnserv for fossil in the mail archives. I tried to find it to give credit but my google-fu wasn't up to the task. Thanks for the URL, that was probably what I remember.
Also, with respect to double slash vs single slash, the Fossil client when talking SSH, doesn't think of it as "single slash vs double slash", but instead parses a URL. It parses the host followed by single slash. Anything that remains is the "path",
However when a browser opens the URL:
https://fossil-scm.org/forum/forumpost/9fd78b751d
the http request starts:
GET /forum/forumpost/9fd78b751d HTTP/1.1
note the leading /. No need to double it in the URL.
Also fossil pull for https://www.fossil-scm.org/home
starts with (captured using --httptrace):
POST /home HTTP/1.0
again a leading /. I think the path is supposed to include the / that
separates the path and that host part of the URL.
Does this look like a bug in the http rendering inside the ssh support code?
-- rouilj
(6) By Andy Bradford (andybradford) on 2021-09-27 02:33:09 in reply to 5 [link] [source]
> Does this look like a bug in the http rendering inside the ssh support code? I'm not yet convinced that it is a bug in the SSH support code, precisely because SSH is not HTTP, even though Fossil tunnels HTTP over SSH. As it was originally designed, SSH uses "fossil test-http" as the remote command and it never uses directories as the target, but has always been a direct path (relative or absolute) to a repository, not a collection of repositories. However, I could certainly see an enhancement request on the "fossil http" side of things to enable it to handle relative paths as if they are absolute so that this works: fossil clone ssh://remoteserver/path Again, I'm not sure it's necessary since it's just as easy to give cloning instructions either way. > However when a browser opens the URL: > > https://fossil-scm.org/forum/forumpost/9fd78b751d > > the http request starts: > > GET /forum/forumpost/9fd78b751d HTTP/1.1 That's because that's how browsers talking HTTP work. They always specify an absolute path. SSH, on the other hand, can and does distinguish between "/path" and "path", the former being absolute and the latter relative. This is similar to the difference between: scp remoteserver:/path vs scp remoteserver:path Also, keep in mind that Fossil is using a different URL scheme than SCP does. When one uses SCP one does not prefix the URL with ssh:// typically, however, if one did, how would SCP (using a typical HTTP scheme for URLs) distinguish between absolute and relative paths? I submit that SSH, if using a full URL scheme like HTTP would in fact have double slashes as well just to distinguish between absolute and relative paths. Something like: scp ssh://remoteserver//path /tmp #absolute scp ssh://remoteserver/path /tmp #relative Unless there were some other mechanism for communicating relative vs absolute. Andy
(7) By Andy Bradford (andybradford) on 2021-09-27 02:59:59 in reply to 5 [source]
> Also fossil pull for https://www.fossil-scm.org/home starts with > (captured using --httptrace): > > POST /home HTTP/1.0 This is because the Fossil client, when talking HTTP, always uses absolute paths. It will never send "POST home HTTP/1.0" and I would bet that it would result in an error if it tried: POST home HTTP/1.0 HTTP/1.0 404 Not Found However, Fossil, when using SSH as the transport does understand relative vs absolute paths. Please look at the httptrace when doing a "fossil pull" using SSH. In the following example, I have created 2 Fossil repositories. The first is a relative path in my user's home directory ($HOME/tmp/relative.fossil) and the second is an absolute path in /tmp (/tmp/absolute.fossil). First the relative (with 0 slashes at beginning of path): $ fossil pull --httptrace -R clone.fossil Pull from ssh://localhost/tmp/relative.fossil Round-trips: 1 Artifacts sent: 0 received: 0 Pull done, wire bytes sent: 376 received: 296 ip: localhost /***** Subprocess 98205 exit(0) *****/ $ head -1 http-request-1.txt POST tmp/relative.fossil HTTP/1.0 Next the absolute (with 1 slash at beginning of path): $ fossil pull --httptrace -R clone.fossil Pull from ssh://localhost//tmp/absolute.fossil Round-trips: 1 Artifacts sent: 0 received: 0 Pull done, wire bytes sent: 377 received: 296 ip: localhost /***** Subprocess 23848 exit(0) *****/ $ head -1 http-request-1.txt POST /tmp/absolute.fossil HTTP/1.0 So again, what you're observing is really the difference between an SSH client that can and does pass in absolute vs relative paths, and an HTTP server that normally only understands absolute paths. And the final question is... should "fossil http" have an option to instruct it to treat all paths as absolute whether or not there is a leading slash? Andy