Give user read/write access to only one directory
Negative ACLs
You can prevent a user from accessing certain parts of the filesystem by setting access control lists. For example, to ensure that the user abcd
cannot access any file under /home
:
setfacl -m user:abcd:0 /home
This approach is simple, but you must remember to block access to everything that you don't want abcd
to be able to access.
Chroot
To get positive control over what abcd
can see, set up a chroot, i.e. restrict the user to a subtree of the filesystem.
You need to make all the files that the user needs (e.g. mysql
and all its dependencies, if you want the user to be able to run mysql
) under the chroot. Say the path to the chroot is /home/restricted/abcd
; the mysql
program needs to be available under /home/restricted/abcd
. A symbolic link pointing outside the chroot is no good because symbolic link lookup is affected by the chroot jail. Under Linux, you can make good use of bind mounts:
mount --rbind /bin /home/restricted/abcd/bin
mount --rbind /dev /home/restricted/abcd/dev
mount --rbind /etc /home/restricted/abcd/dev
mount --rbind /lib /home/restricted/abcd/lib
mount --rbind /proc /home/restricted/abcd/proc
mount --rbind /sbin /home/restricted/abcd/sbin
mount --rbind /sys /home/restricted/abcd/sys
mount --rbind /usr /home/restricted/abcd/usr
You can also copy files (but then you'll need to take care that they're up to date).
To restrict the user to the chroot, add a ChrootDirectory
directive to /etc/sshd_config
.
Match User abcd
ChrootDirectory /home/restricted/abcd
You can test it with:
chroot --userspec=abcd /home/restricted/abcd/ /bin/bash
Security framework
You can also use security frameworks such as SELinux or AppArmor. In both cases, you need to write a fairly delicate configuration, to make sure you aren't leaving any holes.
You should use chroot
. The chroot
command changes the root directory that all child processes see. I'll give an example to demonstrate how it works.
This was written on the spot; I'm not actually in front of a UNIX machine right now. In this example, there's a directory called dir
with three files: a
, b
, c
, and ls
. The first three are regular files. ls
is a hardlink to the real ls
binary so that we can list files while in the chroot.
I'm going to chroot
into dir
. (Note that I'm probably forgetting some directories in the root directory.)
Here's the setup, in shell output form:
$ pwd
/home/alex/test
$ l
dir
$ ls dir
a b c ls
$ ./ls dir # does the same thing
a b c ls
$ ls /
bin boot dev etc home mnt media proc sbin sys usr var
Now I'll chroot
into dir
. The /bin/bash
argument chooses what process should be run with the new root directory. It defaults to /bin/sh
.
$ chroot /bin/bash dir
$ # this prompt is now from a subprocess running in the new root directory
$ PATH=/ ls
a b c ls
$ pwd
/
Now we exit from the chroot
:
$ exit
$ # this prompt is now from the original bash process, from before the chroot
$ pwd
/home/alex/test
I hope this illustrates how the chroot
command works. Basically what you have to do to solve your problem is to run a chroot
command as that user every time they log in. Perhaps put it in a startup script?
A hardlink to a file will continue to work inside a chroot
, even if that file cannot be accessed by other means (this works because hardlinks point to inodes, not paths). So, in order to allow the user to access e.g. the mysql
command, you would execute:
ln /usr/bin/mysql /path/to/chroot/target