Securing circumlunar.space with bind mounts


Lately I have been spending some time preparing for "opening up"

circumlunar.space a bit, by which I mean actively soliciting new users

from the general Gopher-using public. I will probably announce the

Zaibatsu's existence on the gopher-project mailing list in the near

future. So, I have been writing scripts to automate the task of

setting up accounts, setting quotas, etc.

The general plan is that people will be offered sftp-only access to

their gopherspace, with authentication via public key only, without

shell access. Disallowing password authentication means I don't have

to worry about weak passwords getting brute forced. OpenSSH has very

nice options for enforcing sftp only access. Modern versions of sshd

have an internally-implemented version of the sftp server, which means

you can chroot users into their home directory without having to

populate it with libraries and things. I trust the OpenSSH guys to

have got this right, so I feel safe granting this kind of access to

strangers and trusting that they won't be able to get shell access

until I explicitly grant it to them (and I do plan to offer shell

access to anybody who maintains their gopherspace regularly and gives

the impression of being somebody I would like to share a server with).

The one wrinkle on this is Gophernicus' extensive CGI support. I have

never used Gopher CGI myself and am not really interest in it, but I

know a lot of phloggers use it for various things, so I don't want to

just turn it off. However, offering sftp-only access rather than

shell access is kind of pointless if somebody can upload any shell

script they like to their gopher hole, point their gopher client at it

and get Gophernicus to execute it. It's kind of like a very

circuitous shell access of its own. And, okay, Gophernicus will run

it as a low-privilege user, but I'm still not happy about this loop

hole.

At first glance, this is easy to fix. General CGI executables have to

live in a "cgi_bin" directory inside a user's gopherspace for

Gophernicus to execute them, so when I set up a user account I can

create this directory myself, chown it to root and make sure the user

has no access. My "make new user" script does this, and this

straightforwardly means people can't upload anything in there. When

they prove trustworthy and I give them shell access, I can just chown

that directory back to them and we're all good. CGI problem solved,

right?

Well, not quite. Because Gophernicus also supports executable

gophermaps. Any file named "gophermap" with the executable bit set

will be treated as a CGI file. I can't stop people doing this with

simple file permissions, because I have to let them be able to

create their own directories in their gopherhole, and as soon as they

create a directory of their own, they can put a gophermap file in it.

This stumped me for a bit. All I could think was that if each user's

gopherspace was on its own partition, I could mount them with the

noexec option and then CGI would be totally useless for them. But

giving each user their own partition would be a nightmare, and

besides, the cheap-as-chips OpenVZ VPS technology doesn't give you the

freedom to partition your own dedicated virtual disk.

I did some searching and it turned out I was thinking along the right

lines, but I was just a little bit out of date. It turns out that

these days, on Linux at least, you don't need to put stuff in its own

partition to facilitate using mount options. There's this new-fangled

thing called a "bind mount" that I'd never heard of before. I am

really thrilled that this little project is teaching me new stuff

about system administration.

A bind mount is conceptually pretty simple, it just lets you re-mount

an existing part of your filesystem at a new mountpoint. Do:

mount -o bind /home/bob /home/alice

and the contents of /home/bob will be mirrored in /home/alice. It's

kind of like a symbolic link, except that it's more transient (it

won't survive a reboot, unless you put it in /etc/fstab) and a little

more powerful because you can apply all the standard mounting options

like ro, relatime, noexec, nosuid, nodev, etc. The following:

mount -o bind,ro /home/bob /home/alice

would make /home/alice a read-only mirror of /home/bob (/home/bob

remains writable as always). Most interestingly, for the current

application, is that you can bind mount some existing location *over

the top of itself*, which basically means that you can apply those

mounting options anywhere you like on your filesystem. This:

mount -o bind,ro /home/bob /home/bob

simply makes /home/bob read-only, until umount is used to reverse

this. So, even if your entire system is installed in one big

monolithic "/" partition, as is the style these days, you can still

make any individual directory read-only or no-exec or whatever you

like. That's pretty nice!

So not only do my scripts now mount new users' gopherspaces noexec

(and remount as such after reach reboot), but I can also do standard

server hardening tricks like mounting /tmp noexec or mounting /usr ro,

despite the fact that at first glance OpenVZ doesn't give me enough

control to facilitate this.

Proxy Information
Original URL
gemini://zaibatsu.circumlunar.space/~solderpunk/phlog/securing-circumlunar-space-with-bind-mounts.txt
Status Code
Success (20)
Meta
text/plain; charset=utf-8
Capsule Response Time
393.107417 milliseconds
Gemini-to-HTML Time
1.211744 milliseconds

This content has been proxied by September (ba2dc).