Restricted shell for managing files and git repositories
Think about a web hosting company that wants to let users manage files and git repositories via ssh. This includes:
- secure copy (scp)
- creating, copying, moving/renaming and deleting files
- executing a narrow subset of commands for source control and text editing (git, vim, nano)
We would like to implement that and looked into the following options:
- rssh
- scponly
These would allow for the scp part, but using git doesn't seem to be possible. There is a patch in Launchpad, but I'm not sure what to make of it. There is git-shell, too, but it doesn't seem to allow editors. Maybe vim is even too much, because it could be used to execute more code, so we could drop that (vim, or text editors completely, if must be) if it is too much.
We basically want to lock down the shell, so the user can manage (and edit) files and git repositories, but the user should not be able to execute any other programs on the system. The biggest problem would be abuse of network and computing resources, but using the system as a proxy too. You name it. Is there a way to do this or do we maybe even have the wrong approach on this problem?
You have two complementary ways to implement this:
Granting users permissions to use git
repositories remotely
Use gitolite3
to provide a hub-live repositories schema (this is described in detail here), that basically requires you to have a bare
repository (a hub repo) to let your users to push/pull from and a checked-out version of the same repo (a live repo) located in the appropriate path, say /srv/www/html
, for example.
I like to use gitolite3
to handle the hub repo, but that is not a requirement, though it's rather convenient to have fine-grained access control bound to your LDAP of choice if needs be. gitolite3
can provide fine-grained control down to the branch level.
It is also a good practice to limit the capabilities of the gitolite3
user via sudo
, and handle the hooks by means of sudo
calls. This is a working example using gitolite3
hooks (feel free to adapt them -or enhance/fix them- to suit your needs):
-
The relevant content of the
/etc/sudoers
or/etc/sudoers.d/gitolite3
would be something along the lines of:Cmnd_Alias GITOLITE_CMDS = /usr/bin/git, /bin/chown, /bin/find, /usr/bin/xargs, /bin/chmod, /sbin/restorecon, /usr/local/sbin/publisher-hub2live Cmnd_Alias GITOLITE_APACHE_CMDS = /usr/sbin/apachectl graceful Defaults:gitolite3 !requiretty Defaults:gitolite3 lecture=never gitolite3 ALL = (root)NOPASSWD: GITOLITE_CMDS gitolite3 APACHE_HOSTS = (root)NOPASSWD: GITOLITE_APACHE_CMDS
-
hub repo
post-update
hook:#!/bin/sh echo "****" echo "**** Calling publisher-hub2live script [Hub's post-update hook]" echo "****" sudo /usr/local/sbin/publisher-hub2live "/srv/www/html" "root:apache" "2750" "640" exit 0
-
publisher-hub2live
script:#!/bin/sh echo "****" echo "**** Pulling changes into Live [publisher-hub2live]" echo "****" cd "$1" || exit umask 0022 unset GIT_DIR /usr/bin/git pull hub master # custom actions here # e.g call grunt tasks /bin/chown -R "$2" "$1" /bin/find "$1" -type d -exec chmod "$3" {} + /bin/find "$1" -type f -exec chmod "$4" {} + /bin/chmod u+x "$1"/.git/hooks/post-commit /sbin/restorecon -R -v "$1" exec /usr/bin/git update-server-info exit 0
Limiting the ability to execute non-authorized commands in a login shell
What you'd need to implement is a reproducible, auditable method of limiting the ability of the user to perform actions other than the strictly allowed.
It is not required but it helps if you have your users registered in LDAP, and you have already deployed the mechanisms to perform LDAP authentication, be it by means of a PAM module, or using freeIPA and sssd
.
To implement this scenario, what I currently do is the following (be aware that this kind of restrictions requires that several conditions are met, otherwise the restriction can be easily circumvented):
- The users do not belong to the
wheel
group, the only one authorized to usesu
(enforced via PAM). Usually, a non-LDAP user (sysadm
) exists to allow trusted administrators performing actions in cases of disaster recovery or LDAP unavailability. -
The users are given a properly secured
rbash
with a read-only PATH pointing to a private~/bin
, this~/bin/
directory contains links to all allowed commands, for example:$ ll ~/bin total 0 lrwxrwxrwx. 1 root dawud 14 Sep 17 08:58 clear -> /usr/bin/clear* lrwxrwxrwx. 1 root dawud 7 Sep 17 08:58 df -> /bin/df* lrwxrwxrwx. 1 root dawud 10 Sep 17 08:58 egrep -> /bin/egrep* lrwxrwxrwx. 1 root dawud 8 Sep 17 08:58 env -> /bin/env* lrwxrwxrwx. 1 root dawud 10 Sep 17 08:58 fgrep -> /bin/fgrep* lrwxrwxrwx. 1 root dawud 14 Sep 17 08:58 git -> /usr/bin/git* lrwxrwxrwx. 1 root dawud 9 Sep 17 08:58 grep -> /bin/grep* lrwxrwxrwx. 1 root dawud 10 Sep 17 08:58 rview -> /bin/rview* lrwxrwxrwx. 1 root dawud 13 Sep 17 08:58 sudo -> /usr/bin/sudo* lrwxrwxrwx. 1 root dawud 17 Sep 17 08:58 sudoedit -> /usr/bin/sudoedit* lrwxrwxrwx. 1 root dawud 13 Sep 17 08:58 tail -> /usr/bin/tail* lrwxrwxrwx. 1 root dawud 11 Sep 17 08:58 wc -> /usr/bin/wc*
the users are given a restricted, read-only environment (think of stuff like
LESSSECURE
,TMOUT
,HISTFILE
variables). This is to avoidshell
escapes from commands likeless
and ensure auditability.-
the only allowed editor is
rvim
, for the same reason. Users can only executesudoedit
, whic in configured to runrvim
in thesudo
configuration:Defaults editor=/usr/bin/rvim
if MAC restrictions are in place (the specific GNU/Linux distribution you are using has SELinux enabled), the users are mapped to the SELinux user
staff_u
and given rights to execute commands as other user as required viasudo
. The specificsudorules
allowed need to be carefully reviewed to prevent the user from circumventing these limitations, and can also be deployed in your existing LDAP infrastructure (this is one of freeIPA features).-
the users'
/home
,/tmp
and possibly/var/tmp
are polyinstantiated via/etc/security/namespace.conf
:/tmp /tmp/.inst/tmp.inst-$USER- tmpdir:create root /var/tmp /tmp/.inst/var-tmp.inst-$USER- tmpdir:create root $HOME $HOME/$USER.inst/ tmpdir:create root
Polyinstantiation of directories is not a new feature, it has been available for quite a long time now. As a reference, see this article from 2006. As a matter of fact, a lot of modules already use
pam_namespace
by default, but the default configuration at/etc/security/namespace.conf
does not enable polyinstantiation. Also,/etc/security/namespace.init
should make all skeletal files read-only for the users and owned byroot
.
This way you can choose whether the users can execute any command on their own behalf (via a link in the private ~/bin
directory, provisioned via /etc/skel
, as explained above), on behalf of other user (via sudo
) or none at all.