Linux – Make all files under a directory read-only without changing permissions

linuxmountpermissions

First, some background:

  • /dev/md1 is a RAID-0 array serving as primary file store. It is mounted to /var/smb.
  • /dev/md2 is another RAID-0 array storing backup snapshots taken from /dev/md1. It is mounted to /var/smb/snapshots.
  • Three directories are made available via Samba: /var/smb/files (publicly-shared files), /var/smb/private (private files), and /var/smb/snapshots (providing read-only access to backup snapshots).

Only users in the smbusers group are allowed to access the files and snapshots shares; similarly, only users in the smbprivate group are allowed to access the files in private. Additionally, Linux permissions prohibit users not in the respective groups from accessing the files and private directories, both on the local system and within the snapshots Samba share.

This is great, because it means that we have a fully functional file server with a self-help "restore from backup" option (users can simply access the snapshots share and retrieve the file(s) they want to restore themselves), but so far I lack one key ingredient: Non-root access on the local system to the /var/smb/snapshots directory.

The snapshots must be strictly read-only to all regular users, however of course the file system must be mounted read-write to allow the backup operation to take place. The permissions on these directories are currently:

root@odin:/var/smb# ll
total 40
drwxrwxr-x  7 root   root        4096 2011-04-11 15:18 ./
drwxr-xr-x 14 root   root        4096 2011-04-10 19:07 ../
drwxrwx--- 15 kromey smbusers    4096 2010-12-07 13:09 files/
drwxrwx---  7 kromey smbprivate  4096 2010-04-07 07:08 private/
drwxrwx---  3 root   root        4096 2011-04-11 15:16 snapshots/

Now, what I want is to provide access to the snapshots directory to non-root users, but in a strictly read-only fashion. I can't mount /dev/md2 read-only, though, because I have to have it read-write to run backups; I can't simply re-mount it read-write for a backup and then re-mount it back to read-only, because that provides a window of time when the backups could be written to by another user.

Previously I did this by making my snapshots directory a read-only NFS export (only to localhost) and mounting that locally (the original secured under a directory lacking traversal rights for non-root users), but this feels like a hack and there seems like there should be a better way to accomplish this. I did try the mount --bind option, but it seems to lack the ability to have different access levels (i.e. read-only versus read-write) on the two directories (unless I'm missing something: mount -r --bind dir1 dir2).

Any ideas how I can accomplish this without NFS, or is that my best option?

TL;DR: How can I make the contents of a file system available read-write to a select user, but strictly read-only to everyone else, while maintaining original permissions and ownerships on the files backed up to this file system?

Best Answer

This answer works on Debian (tested on lenny and squeeze). After investigation, it seems to work only thanks to a Debian patch; users of other distributions such as Ubuntu may be out of luck.

You can use mount --bind. Mount the “real” filesystem under a directory that's not publicly accessible. Make a read-only bind mount that's more widely accessible. Make a read-write bind mount for the part you want to expose with read-write access.

mkdir /media/hidden /media/hidden/sdz99
chmod 700 /media/hidden
mount /dev/sdz99 /media/hidden/sdz99
mount -o bind,ro /media/hidden/sdz99/world-readable /media/world-readable
mount -o bind /media/hidden/sdz99/world-writable /media/world-writable

In your use case, I think you can do:

mkdir /var/smb/hidden
mv /var/smb/snapshot /var/smb/hidden
mkdir /var/smb/snapshot
chmod 700 /var/smb/hidden
chmod 755 /var/smb/hidden/snapshot
mount -o bind,ro /var/smb/hidden/snapshot /var/smb/hidden/snapshot

I.e. put the real snapshot directory under a restricted directory, but give snapshot read permissions for everyone. It won't be directly accessible because its parent has restricted access. Bind-mount it read-only in an accessible location, so that everyone can read it through that path.

(Read-only bind mounts only became possible several years after bind mounts were introduced, so you might remember a time when they didn't work. I don't know offhand since when they work, but they already worked in Debian lenny (i.e. now oldstable).)

Related Question