Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuring the unix socket owner and group #89

Open
PhrozenByte opened this issue Aug 4, 2022 · 3 comments
Open

Allow configuring the unix socket owner and group #89

PhrozenByte opened this issue Aug 4, 2022 · 3 comments
Assignees
Labels
enhancement New feature or request

Comments

@PhrozenByte
Copy link

Is your feature request related to a problem? Please describe.
Similar to #45 I'd like to implement finer access to the mta-sts-daemon's unix socket. Right now I must add Postfix to the primary group of the user running mta-sts-daemon to use more restricted permissions like 660 for the socket. However, this still gives Postfix more access than it actually needs, because Postfix can then not just access the socket, but any other group-accessible file - i.e. usually all files of the user running mta-sts-daemon.

Following the principle of least privilege (POLP), I'd like to change the unix socket's owner and group, not just its mode.

Describe the solution you'd like
Since chowning files isn't possible for unprivileged users, it must be possible to start mta-sts-daemon with root privileges and let the daemon drop its permissions to a configurable unprivileged user after creating the socket. As a side effect, this also allows users to bind to ports < 1024 without permanently running the daemon as root.

Accordingly there should be three more config options: Two options to set the unix socket's owner and group respectively, and another option to set the unprivileged user to run the daemon with. Since the naming of the config options will likely cause confusion (owner of the unix socket vs. unprivileged user running the daemon), I'd recommend to change the config structure as follows (also move host, port, and reuse_port to the listen_on section, but still support the old configs to preserve BC):

listen_on:
    path: /path/to/unix.sock
    user: mta-sts-sock
    group: mta-sts-sock
    mode: 0660
user: mta-sts

When running mta-sts-daemon as root, it will first create the socket /path/to/unix.sock (owned by mta-sts-sock:mta-sts-sock, mode 0600) and then drop its privileges to user mta-sts. When trying to start mta-sts-daemon as an unprivileged user, the daemon should bail, unless the executing user matches both user and listen_on.user.

Describe alternatives you've considered
In theory, one could add the mta-sts user to the mta-sts-sock group and then add ExecStartPost=/usr/bin/chown mta-sts-sock:mta-sts-sock /path/to/unix.sock to the Systemd unit file, but I didn't test it.

On a side note, when using the fork syscall for a native implementation as suggested before, the mta-sts user isn't required to be a member of the mta-sts-sock group, because the unprivileged child process would inherit the open socket from the privileged root process.

Additional context
A lot of ❤️ for your awesome project, keep up the great work, thank you! 👍

@PhrozenByte PhrozenByte added the enhancement New feature or request label Aug 4, 2022
@Snawoot
Copy link
Owner

Snawoot commented Aug 5, 2022

Hello, @PhrozenByte!

Thanks for a great idea!

I'm thinking about another way to solve this. Systemd has some feature called "socket activation". Basically, it opens socket and runs specified unit process. Daemon process inherits already open socket from systemd launcher process and reads from environment fd number to pick up. This way we can delegate creation of socket to system facilities.

I think it is a strictly superior approach for following reasons:

  • We don't need privileged access at all and don't need to drop permissions afterwards.
  • Less use of system specific APIs will be required. Actually we don't even need to depend on systemd in that mode of operation. All we need to do to support socket activation protocol is just read few environment variables, which can be implemented by some external wrapper instead of systemd.
  • Such init delegation allows administrator to set more options and transfers ownership of socket from us to system.
  • This approach can also work to allow to bind to lower TCP ports without any additional privileges.
  • On-demand startup of pmsr becomes viable option: systemd may start daemon when it's actually needed.

That should be quite easy to implement: just read few env vars and instantiate listener from fd. However, I don't think I'll be able to handle that soon because of quite tight workload. If you can contribute implementation of such approach, your PR will be welcome.

Please tell what do you think about this.

@PhrozenByte
Copy link
Author

I'm thinking about another way to solve this. Systemd has some feature called "socket activation". Basically, it opens socket and runs specified unit process. Daemon process inherits already open socket from systemd launcher process and reads from environment fd number to pick up.

I like the idea! 👍 However, IMHO there must be a Systemd-independent solution. I'm running mta-sts-daemon in a container, thus there's no Systemd available. However, we can probably mimic the behaviour without actually depending on Systemd: As an alternative to Systemd, we could add a little binary running as root that opens the socket, starts an unprivileged instance of mta-sts-daemon and then passes the fd to it.

@trentbuck
Copy link

Hi, I'm a nosy bystander.
Socket-activation is what I want, but I haven't time to code it today.

In the meantime, I confirm this does work (as suggested upthread):

# /etc/systemd/system/postfix-mta-sts-resolver.service.d/mta-sts-daemon-bugfix.conf
[Service]
ExecStartPost=chmod g+w /var/spool/postfix/run/mta-sts/mta-sts-daemon.sock

In the meantime, I confirm this does not work:

# /etc/tmpfiles.d/cyber-mail.conf
d /var/spool/postfix/run/mta-sts 2770 _mta-sts postfix - -
A /var/spool/postfix/run/mta-sts - - - - group:postfix:rwx

It works if systemd-tmpfiles runs after the daemon is running and the socket exists:

drwxrws---+ 2 _mta-sts postfix 3 Dec 14 13:04 .
drwxr-xr-x  3 root     root    3 Dec 14 12:09 ..
srwxrwxr-x+ 1 _mta-sts postfix 0 Dec 14 13:04 mta-sts-daemon.sock

It does not work if systemd-tmpfiles runs before the daemon:

drwxrws---+ 2 _mta-sts postfix 3 Dec 14 13:33 .
drwxr-xr-x  3 root     root    3 Dec 14 12:09 ..
srwxr-xr-x  1 _mta-sts postfix 0 Dec 14 13:33 mta-sts-daemon.sock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants