Make all files under a directory read-only without changing permissions?
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:
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9dbc6c6dde9c6cdc0c7">[email protected]</a>:/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?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
@Gilles was really close, just ever-so-slightly off the mark for Ubuntu 10.10 (I don’t have any reason to doubt he’s right for Debian Squeeze, and possibly others). By mounting my read-write snapshots directory under a folder that other users cannot access (e.g. /var/smb/hidden/snapshots, where /var/smb/hidden has permissions 770 and is owned by root:root), I can protect the read-write mount from other users. I can then use mount --bind
followed by mount -o remount,ro
to bind the mount to an accessible location, then make it read-only.
(The inverse (mount the original file system read-only, then bind it read-write) does not work; similarly, mounting the original read-only, then binding it read-only, then re-mounting the original read-write makes the bound directory also read-write.)
So to recap, here’s the solution:
mkdir /var/smb/hidden chown root:root /var/smb/hidden chmod 770 /var/smb/hidden mkdir /var/smb/hidden/snapshots mksdir /var/smb/snapshots mount /dev/md2 /var/smb/hidden/snapshots mount --bind /var/smb/hidden/snapshots /var/smb/snapshots mount -o remount,ro /var/smb/snapshots
So there is a brief window of time where the backups are read-write and generally accessible, but it’s small enough to be usable for my needs. Some trickery with the permissions on /var/smb could protect it during this brief window (i.e. make it non-traversable, then bind the mount, then make it traversable again), if those brief milliseconds are too big a window.
Now I just have to put this all together in a script. Slip it into the start-up process right after everything is mounted perhaps, which should avoid any conflict that might be caused by Samba trying to share the directory I’m binding to.
Note: If your distro supports the mount -o bind,ro
version as Gilles posted, I recommend that solution for you; my solution is here should only be used by folks on Ubuntu or other distros that won’t permit you to change mount options when binding to another directory.
Method 2
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).)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0