`DynamicUser` and socket permission

MWE: Reference files and directories. There are (number of commits that come from $GIT_DIR environment.

In the test, openbao service creates a unix socket at /run/openbao/openbao.sock, and caddy reverse proxies to it. For security reasons, the openbao service uses DynamicUser = true.

I configured the service to have supplementary groups including openbao and instructed openbao to set the socket group to caddy, but this leads to

dial unix /run/openbao/openbao.sock: connect: permission denied

A solution here is to set RuntimeDirectoryMode = "0777" or something permissive, but it would allow other users to access the /run/openbao directory. Another solution is to not use a dynamic user.

Is there a solution that does not require a runtime directory of 0777/0755, has DynamicUser = true, and where caddy can reverse proxy to the socket?

The systemd way is to use a systemd.socket to create the socket, and give it the group permission via its configuration: DynamicUser= support for AF_UNIX socket units for ownership of the inode · Issue #23067 · systemd/systemd · GitHub

This requires that openbao is capable of receiving a socket either as a file descriptor or via the systemd API; unfortunately good support for unix sockets is pretty rare these days, it’s a rather niche use case since for the most part everything is hosted via https in kubernetes clusters, or at least in docker containers, so few projects care about monolithic hosts.

Enabling services with DynamicUser to access sockets without setting groups is still an issue, too, as that issue says.

You can of course also just create the socket manually in a different location that is group accessible.

I tried this kind of structure and it doesn’t work either (same error):

    systemd.sockets.openbao = {
      before = [ "caddy.service" "openbao.service" ];
      wantedBy = [ "sockets.target" ];
      socketConfig = {
        ListenStream = "/run/openbao/openbao.sock";
        SocketGroup = "openbao";
        SocketMode = "0770";
      };
    };

Yes, you’re supposed to let systemd choose a directory that has g+x permissions.

You can try e.g. /run/openbao.sock - systemd will forward the socket via fd, so the cgroup settings won’t interfere. I suspect openbao won’t know what to do with the socket file descriptor though.

openbao doesn’t know what to do with the socket placed in /run/openbao.sock

vm-test-run-openbao> server # [   15.738649] bao[1089]: Error parsing listener configuration.
vm-test-run-openbao> server # [   15.741364] bao[1089]: Error initializing listener of type unix: failed to remove socket file: remove /run/openbao.sock: permission denied

You can submit an upstream issue about this. Other projects end up adding a special fd transport so that you can change the listener to something like fd://3.

In the meantime, you have no option but to make openbao create the socket. You’ll have to add something like systemd.services.openbao.serviceConfig.ReadWritePaths = "/run/openbao.sock";.

diff --git a/test/openbao.nix b/test/openbao.nix
index a7ec746..a541493 100644
--- a/test/openbao.nix
+++ b/test/openbao.nix
@@ -20,6 +20,7 @@ in {
         openbao = {
           after = ["postgresql.service"];
           serviceConfig = {
+            ReadWritePaths = "/run/openbao.sock";
             SupplementaryGroups = ["caddy"];
             User = "openbao";
             Group = "openbao";
@@ -73,6 +74,7 @@ in {
                 tls_key_file = "${dir-cert}/key.pem";
               };
               unix = {
+                address = "/run/openbao.sock";
                 type = "unix";
                 socket_mode = "0660";
                 socket_user = "openbao";

like this? it doesn’t work either

server # [   14.959118] (bao)[987]: openbao.service: Failed to set up mount namespacing: /run/openbao.sock: No such file or directory