|
1
|
# Forcing Use of Fossil’s RBAC over SSH |
|
2
|
|
|
3
|
Andy Bradford posted a [clever solution][sshfc] to the problem of |
|
4
|
Fossil’s RBAC system [being ignored](../../caps/#webonly) over `ssh://` |
|
5
|
URLs: use OpenSSH’s `ForceCommand` feature to route the sync transfer |
|
6
|
protocol data over `fossil http` rather than `fossil test-http`. |
|
7
|
|
|
8
|
The setup for this is complicated, but it’s a worthy option when you |
|
9
|
need encrypted communications between the client and server, you already |
|
10
|
have SSH set up, and [the HTTPS alternative](../../ssl.wiki) is |
|
11
|
unworkable for some reason. |
|
12
|
|
|
13
|
|
|
14
|
## 1. Force remote Fossil access through a wrapper script <a id="sshd"></a> |
|
15
|
|
|
16
|
Put something like the following into the `sshd_config` file on the |
|
17
|
Fossil repository server: |
|
18
|
|
|
19
|
``` ssh-config |
|
20
|
Match Group fossil |
|
21
|
X11Forwarding no |
|
22
|
AllowTcpForwarding no |
|
23
|
AllowAgentForwarding no |
|
24
|
ForceCommand /home/fossil/bin/wrapper |
|
25
|
``` |
|
26
|
|
|
27
|
This file is usually found in `/etc/ssh`, but some OSes put it |
|
28
|
elsewhere. |
|
29
|
|
|
30
|
The first line presumes that we will put all users who need to use our |
|
31
|
Fossil repositories into the `fossil` group, as we will do |
|
32
|
[below](#perms). You could instead say something like: |
|
33
|
|
|
34
|
``` ssh-config |
|
35
|
Match User alice,bob,carol,dave |
|
36
|
``` |
|
37
|
|
|
38
|
You have to list the users allowed to use Fossil in this case because |
|
39
|
your system likely has a system administrator that uses SSH for remote |
|
40
|
shell access, so you want to *exclude* that user from the list. For the |
|
41
|
same reason, you don’t want to put the `ForceCommand` directive outside |
|
42
|
a `Match` block of some sort. |
|
43
|
|
|
44
|
You could instead list the exceptions: |
|
45
|
|
|
46
|
``` ssh-config |
|
47
|
Match User !evi |
|
48
|
``` |
|
49
|
|
|
50
|
This would permit only [Evi the System Administrator][evi] to bypass this |
|
51
|
mechanism. |
|
52
|
|
|
53
|
[evi]: https://en.wikipedia.org/wiki/Evi_Nemeth |
|
54
|
|
|
55
|
If you have a user that needs both interactive SSH shell access *and* |
|
56
|
Fossil access, exclude that user from the `Match` rule and use Fossil’s |
|
57
|
normal `ssh://` URL scheme for those cases. This user will bypass the |
|
58
|
Fossil RBAC, but they effectively have Setup capability on those |
|
59
|
repositories anyway by having full read/write access to the DB files via |
|
60
|
the shell. |
|
61
|
|
|
62
|
|
|
63
|
## 2. Rewrite the sync command with that wrapper <a id="wrapper"></a> |
|
64
|
|
|
65
|
When Fossil syncs over SSH, it attempts to launch a remote Fossil |
|
66
|
instance with certain parameters in order to set up the HTTP-based sync |
|
67
|
protocol over that SSH tunnel. We need to preserve some of this command |
|
68
|
and rewrite other parts to make this work. |
|
69
|
|
|
70
|
Here is a simpler variant of Andy’s original wrapper script: |
|
71
|
|
|
72
|
``` sh |
|
73
|
#!/bin/bash |
|
74
|
set -- $SSH_ORIGINAL_COMMAND |
|
75
|
while [ $# -gt 1 ] ; do shift ; done |
|
76
|
export REMOTE_USER="$USER" |
|
77
|
ROOT=/home/fossil |
|
78
|
exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" |
|
79
|
``` |
|
80
|
|
|
81
|
The substantive changes are: |
|
82
|
|
|
83
|
1. Move the command rewriting bits to the start. |
|
84
|
|
|
85
|
2. Be explicit about executable paths. You might extend this idea by |
|
86
|
using chroot, BSD jails, Linux containers, etc. |
|
87
|
|
|
88
|
3. Restrict the Fossil repositories to a single flat subdirectory under |
|
89
|
the `fossil` user’s home directory. This scheme is easier to secure |
|
90
|
than one allowing subdirectories, since you’d need to take care of |
|
91
|
`../` and such to prevent a sandbox escape. |
|
92
|
|
|
93
|
4. Don’t take the user name via the SSH command; to this author’s mind, |
|
94
|
the user should not get to override their Fossil user name on the |
|
95
|
remote server, as that permits impersonation. The identity you |
|
96
|
present to the SSH server must be the same identity that the Fossil |
|
97
|
repository you’re working with knows you by. Since the users |
|
98
|
selected by “`Match`” block above are dedicated to using only Fossil |
|
99
|
in this setup, this restriction shouldn’t present a practical problem. |
|
100
|
|
|
101
|
The script’s shebang line assumes `/bin/sh` is POSIX-compliant, but that |
|
102
|
is not the case everywhere. If the script fails to run on your system, |
|
103
|
try changing this line to point at `bash`, `dash`, `ksh`, or `zsh`. Also |
|
104
|
check the absolute paths for local correctness: is `/bin/basename` |
|
105
|
installed on your system, for example? |
|
106
|
|
|
107
|
Under this scheme, you clone with a command like: |
|
108
|
|
|
109
|
$ fossil clone ssh://HOST/repo.fossil |
|
110
|
|
|
111
|
This will clone the remote `/home/fossil/museum/repo.fossil` repository |
|
112
|
to your local machine under the same name and open it into a “`repo/`” |
|
113
|
subdirectory. Notice that we didn’t have to give the `museum/` part of |
|
114
|
the path: it’s implicit per point #3 above. |
|
115
|
|
|
116
|
This presumes your local user name matches the remote user name. Unlike |
|
117
|
with `http[s]://` URLs, you don’t have to provide the `USER@` part to |
|
118
|
get authenticated access |
|
119
|
since this scheme doesn’t permit anonymous cloning. Only |
|
120
|
if these two user names are different do you need to add the `USER@` bit to the |
|
121
|
URL. |
|
122
|
|
|
123
|
|
|
124
|
## 3. Set permissions <a id="perms"></a> |
|
125
|
|
|
126
|
This scheme assumes that the users covered by the `Match` rule can read |
|
127
|
the wrapper script from where you placed it and execute it, and that |
|
128
|
they have read/write access on the directory where the Fossil |
|
129
|
repositories are stored. |
|
130
|
|
|
131
|
You can achieve all of this on a Linux box with: |
|
132
|
|
|
133
|
``` shell |
|
134
|
sudo adduser fossil |
|
135
|
for u in alice bob carol dave ; do |
|
136
|
sudo adduser $u |
|
137
|
sudo gpasswd -a fossil $u |
|
138
|
done |
|
139
|
sudo -i -u fossil |
|
140
|
chmod 710 . |
|
141
|
mkdir -m 750 bin |
|
142
|
mkdir -m 770 museum |
|
143
|
ln -s /usr/local/bin/fossil bin |
|
144
|
``` |
|
145
|
|
|
146
|
You then need to copy the Fossil repositories into `~fossil/museum` and |
|
147
|
make them readable and writable by group `fossil`. These repositories |
|
148
|
presumably already have Fossil users configured, with the necessary |
|
149
|
[user capabilities](../../caps/), the point of this article being to |
|
150
|
show you how to make Fossil-over-SSH pay attention to those caps. |
|
151
|
|
|
152
|
You must also permit use of `REMOTE_USER` on each shared repository. |
|
153
|
Fossil only pays attention to this environment variable in certain |
|
154
|
contexts, of which “`fossil http`” is not one. Run this command against |
|
155
|
each repo to allow that: |
|
156
|
|
|
157
|
``` shell |
|
158
|
echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | |
|
159
|
fossil sql -R museum/repo.fossil |
|
160
|
``` |
|
161
|
|
|
162
|
Now you can configure SSH authentication for each user. Since Fossil’s |
|
163
|
password-saving feature doesn’t work in this case, I suggest setting up |
|
164
|
SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication |
|
165
|
occurs on each sync, which Fossil’s default-enabled autosync setting |
|
166
|
makes frequent. |
|
167
|
|
|
168
|
Equivalent commands for other OSes should be readily discerned from the |
|
169
|
script above. |
|
170
|
|
|
171
|
[sshfc]: forum:/forumpost/0d7d6c3df41fcdfd |
|
172
|
|
|
173
|
<div style="height:50em" id="this-space-intentionally-left-blank"></div> |
|
174
|
|