Give user read/write access to only one directory

89,050

Solution 1

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.

Solution 2

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
Share:
89,050

Related videos on Youtube

Manishearth
Author by

Manishearth

Updated on September 18, 2022

Comments

  • Manishearth
    Manishearth over 1 year

    I'm running a server, and I need to give read/write access to a particular directory to a single user. I've tried the following:

    sudo adduser abcd
    sudo groupadd abcdefg
    chown -R .abcdefg /var/www/allowfolder
    chmod -R g+rw /var/www/allowfolder
    usermod -a -G comments abcd
    

    The above seems to work, however it gives the user read-only access to the rest of the server.

    How can I set up permissions so that the user can only read and write to a particular folder? The user should also be able to run programs like mysql.

    • Admin
      Admin over 10 years
      The short answer: use a chroot.
    • Admin
      Admin over 10 years
      @Chris Care to elaborate on that in an answer? Manish and I have been struggling with this and can't seem to make it work.
    • Admin
      Admin over 10 years
      Where would the mysql program be located? The user has to be able to read it, and all the libraries and data files it needs.
    • Admin
      Admin over 10 years
      @Gilles Hmm. It's a standard mysql install from apt-get, as far as I can tell (not my system, it's Undo's).
  • Manishearth
    Manishearth over 10 years
    Basically, is there any way (via chmod) of making a user lose read access to the rest of the fs without affecting the access of other users?
  • user2914606
    user2914606 over 10 years
    @Manishearth there's no simple way with chmod. when you say "wouldn't it be easier to run a command...do not lose access to them", that command is chroot. if you explain what you mean by "an entire chroot environment", or why this would be a problem, maybe I'll understand better. (note that you can give access to all executables with a oneliner: ln /bin/* /path/to/chroot/target)
  • user2914606
    user2914606 over 10 years
    @Manishearth if my example didn't make sense I'd encourage you to play with chroot yourself or let me know what didn't make sense. even better, do both. (and read the manpages.)
  • printf
    printf almost 5 years
    Couldnt a much easier way of giving read and write permissions to a particular directory is via making groups? For example he could create a new group and use chown to make the directory group owner the group which was made and add the user to the group. Lastly give the directory read and write permissions to groups.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 5 years
    @Qasim That requires that all the files have their permissions and ownership set as desired. There are so many things that can go wrong (files copied from elsewhere or extracted from an archive with their permissions preserved, files that need to belong to another group, files that shouldn't be group-readable, users who make mistakes or can't be bothered to make sure the group accessibility stays as desired…) that groups don't really solve this problem.
  • printf
    printf almost 5 years
    I mean i dont see how files would have to have their own permissions if the group permissions on the directory were set in a way where no user could "cd" into the directory or "ls"the directory.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 5 years
    @Qasim Every file under /var/www/allowfolder and its subdirectories has to be accessible, not just /var/www/allowfolder itself. And conversely other files must not be accessible. In fact a solution based solely on file permissions and ACL cannot completely fulfill the requirements: it would at least allow the user to test whether a given name exists under /var/www, since they need to have x permission on /var/www to access /var/www/allowfolder.
  • printf
    printf almost 5 years
    Oh ok i see but if we exclude the /var directory from this and lets say we are talking about a normal directory in the /home/user directory?
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 5 years
    @Qasim /var/www is just as “normal“ as /home/user.
  • printf
    printf almost 5 years
    You said that everyfile under /var/www has to be accessable, with groups this can be done as well as making the directory non accessable to particular users and accessable to particular users.
  • Kusalananda
    Kusalananda almost 3 years
    @user3521180 If you have a separate issue, you may want to ask a new question. Comments are for seeking or suggesting clarifications to answers.
  • RicarHincapie
    RicarHincapie almost 3 years
    On Ubuntu 18.04, the correct path is /etc/ssh/sshd_config