Using web server reverse proxying to deal with file access permissions

February 19, 2023

Perhaps we're peculiar, but one of the challenges we keep running into over and over again in our web servers is that someone wants to expose access-restricted Unix files to selected local people via the web, rather than making people log in and slog through the filesystem. The actual access restrictions are not a problem because we have a well developed system using HTTP Basic Authentication (and someday it will be extended to be a single sign on environment). However this still leaves us with the challenge of giving the web server the permission to read those files. Our traditional approach has been group membership, which has created several Apache UIDs that have a steadily expanding set of privileges.

Today, in a blinding flash of the obvious, I realized that an alternate approach to solving this problem is reverse proxies. For each set of files with Unix access restrictions, we can use or set up a login that specifically has access to them, then have that login run a simple web server that serves those files. Then the main web server reverse proxies to all of those sub-servers, with appropriate HTTP Basic Authentication or other access controls in front. Each sub-server has strictly limited access to its own files, and the main Apache server doesn't need to have access to anything (beyond the ability to talk to the sub-servers). Much as with our regular user-run web servers, a sub-server could run potentially dangerous things like PHP without endangering anyone else.

(We wouldn't want these sub-servers to be regular user-run web servers, because there's no internal access controls on who can talk to user-run web servers. You would definitely want access to the sub-servers to be limited to the main Apache.)

There are a number of plausible approaches to making sure that only the main Apache can talk to the sub-servers. Since one concern is potential cross-compromise (especially with PHP in the mix), we'd definitely want to get this right. For localhost traffic, Linux iptables can restrict things by the UID that generated the packet, or we might be able to reverse proxy over Unix domain sockets (although things are tricky there unless we want a lot of two-login groups). If the frontend Apache is on a different machine, we can restrict inbound network traffic to the sub-servers to be from that machine (and then restrict who can do outbound traffic on that machine, if we allow any access to it at all).

We might not want to use Apache for most of these sub-servers, since all they need to do is serve files and Apache is still fairly heavy-weight for that. Something with a simple configuration and operation would probably be ideal for most cases. On the other hand, Apache is right there and we know how to set it up and operate it.

(What triggered this flash of the obvious was this Fediverse post by @anarcat.)

Comments on this page:

By Tom at 2023-02-20 16:46:40:

I'm guessing the two user groups are so that the main server can access the sub-server sockets and nothing else can. In which case, I thought could avoid that by using systemd provided sockets for the sub-servers. They can be made accessible to the main server and not the subservers, the later of which will access them via already opened FD.

By Nico at 2023-03-08 12:04:34:

You could do reverse proxy over an Unix socket, that remove the complexity of filtering localhost.

Nginx support listening on Unix socket & apache' mod_proxy can use it.

Making that work requires each sub-server to run under a separate UID, so it can be a member of a group with access to the files and a member of a group that also contains Apache’s UID, so that Apache can have sufficient permission to read the socket.

Doing it via a TCP socket requires more filtering, but avoids the UID-per-subserver situation.

Either way the use of sub-servers means trading the steadily expanding set of privileges for the Apache UID for a steadily expanding set of running processes hanging around in case Apache needs to talk to them.

I was going to wonder whether xinetd or something of the sort would be a realistic solution for that. But then I realized that xinetd would have to spawn each sub-server under a different UID, so this would just shift the superset of privileges to xinetd, and at that point I have to wonder if there isn’t some suexec-type model that would achieve the same thing without redundant moving parts.

So far none of these approaches sounds convincingly like a good solution to me…

(On second thought, I misidentified the extra cost of the socket solution. It’s not the separate UID per sub-server (that is of course necessary anyway) but the extra group needed so that each sub-server UID and the Apache UID can share a group that nobody else is in.)

Written on 19 February 2023.
« The size of a window is complicated in X (or can be)
A bit on unspecified unique objects in Python »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Feb 19 22:43:26 2023
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.