Unable to access NetworkManager via DBus

Hi,

I’m working on porting my application to balenaOS and have been unable to get my application to connect to NetworkManager on the host via DBus.

After reading the documentation at Network Setup on balenaOS | balena, Communicate outside the container | balena and wifi-connect/README.md at master · balena-os/wifi-connect · GitHub I arrived at the following docker-compose.yml:

version: "2.1"

services:
  webthings-gateway:
    container_name: webthings-gateway
    build: .
    restart: unless-stopped
    network_mode: host
    environment:
      - "TZ=America/Los_Angeles"
      - "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket"
    volumes:
      - webthings-data:/home/node/.webthings
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "10"
    labels:
      io.balena.features.dbus: '1'
    cap_add:
      - NET_ADMIN
volumes:
  webthings-data:

However, the application (using DBus code that works on other platforms) is unable to access the NetworkManager DBus, with the following error:

[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway] 2025-09-15 08:37:50.460 ERROR  : Error: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at new module.exports (/home/node/webthings/gateway/node_modules/dbus/lib/bus.js:20:27)
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at DBus.getBus (/home/node/webthings/gateway/node_modules/dbus/lib/dbus.js:39:9)
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at NetworkManager.start (/home/node/webthings/gateway/build/platforms/utilities/network-manager.js:23:45)
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at NetworkManager.getDevices (/home/node/webthings/gateway/build/platforms/utilities/network-manager.js:40:14)
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at NetworkManager.getWifiDevices (/home/node/webthings/gateway/build/platforms/utilities/network-manager.js:113:36)
[Logs]    [2025-09-15T15:37:50.461Z] [webthings-gateway]     at LinuxBalenaOSPlatform.getNetworkAddressesAsync (/home/node/webthings/gateway/build/platforms/linux-balena-os.js:55:65)

Is there anything else I might need to set on the container to gain access to NetworkManager on the host via DBus?

The application is written in TypeScript and is using node-dbus. Source code in linux-balena-os.ts & network-manager.ts.

Many thanks

Follow up:

I tried setting privileged: true on the service in docker-compose.yml and it didn’t make any difference, which suggested it might not be an issue with missing capabilities.

If I log into the Debian-based container and install the network-manager package using apt I note that the root user can access network settings using nmcli, but the node user (which is being used to run the application) can not.

So is the issue that the node user can not access the DBus system bus in order to communicate with NetworkManager on the host?

If so, is there a safe way to give a non-root user access to the system bus from inside the container, or should I be taking another approach? If I can’t create a DBus policy on the host OS, is my only option to run my application as root inside the container?

I’m disappointed nobody has been able to reply to this :frowning:

I’ve been digging into this a bit more and from what I can tell the default DBus configuration for NetworkManager on balenaOS (/usr/share/dbus-1/system.d/org.freedesktop.NetworkManager.conf) appears to allow non-root users to modify most network settings, but only if PolicyKit allows them to.

I haven’t been able to find a PolicyKit configuration for NetworkManager in /usr/share/polkit-1/actions, so my assumption is that non-root users will be blocked.

Since I can’t modify the host OS this seems to indicate that I would have to run my application as root inside its container so that the UID matches when communicating with NetworkManager outside the container.

Is the only option really to run the application as root inside the container?

hi @benfrancis sorry for the delay in coming back to this.

Have you tried the simple examples in BalenaOS Masterclass | balena?

That should allow to separate a balenaOS problem from an application problem.

@alexgg Thank you for your response.

If I install network-manager inside the container then I can see that nmcli is able to communicate with the host’s NetworkManager when running as root, but not as the non-root node user.

# DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket nmcli c s
NAME                UUID                                  TYPE      DEVICE      
Wired connection 1  2d5077f7-6797-33b8-a594-5ae52221012e  ethernet  eno2        
Sub-Etha            d0e865ac-ef94-4c28-aa44-dd71cb7ba11d  wifi      wlo1        
lo                  454ed9d5-93b3-400d-bb9a-bb72fce80e81  loopback  lo          
supervisor0         b76fbc2e-4c25-4f05-9029-332643ab4ceb  bridge    supervisor0 
# su node
node@3c865c3:~/webthings/gateway$ DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket nmcli c s
Error: Could not create NMClient object: The connection is closed.

I can also confirm that if I reconfigure my Docker image to run the application as root, the network settings web interface works.

So other than re-architecting my entire application into separate services, is my only option to run my application as root inside its container?

Hi @benfrancis,

I can confirm that dbus access only seems to work with root access inside the container, but it doesn’t require that the container is privileged or that it has host networking which should provide some assurance. For instance, this works

# Start non-privileged ubuntua container
$ balena run --rm -v /run/dbus:/host/run/dbus -e DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket -ti ubuntu
root@66a4545a8f96:/# apt-get update && apt-get install -y --no-install-recommends dbus
root@66a4545a8f96:/# DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket \
  dbus-send \
  --system \
  --print-reply \
  --reply-timeout=2000 \
  --type=method_call \
  --dest=org.freedesktop.timedate1 \
  /org/freedesktop/timedate1  \
  org.freedesktop.DBus.Properties.GetAll \
  string:"org.freedesktop.timedate1"
method return time=1759259228.449128 sender=:1.48 -> destination=:1.47 serial=3 reply_serial=2
   array [
      dict entry(
         string "Timezone"
         variant             string ""
      )
      dict entry(
         string "LocalRTC"
         variant             boolean false
      )
      dict entry(
         string "CanNTP"
         variant             boolean false
      )
      dict entry(
         string "NTP"
         variant             boolean false
      )
      dict entry(
         string "NTPSynchronized"
         variant             boolean true
      )
      dict entry(
         string "TimeUSec"
         variant             uint64 1759259228448882
      )
      dict entry(
         string "RTCTimeUSec"
         variant             uint64 1759259229000000
      )
   ]

But doing the same as non-root fails

root@66a4545a8f96:/# useradd me
root@66a4545a8f96:/# su - me
su: warning: cannot change directory to /home/me: No such file or directory
$ DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket \
  dbus-send \
  --system \
  --print-reply \
  --reply-timeout=2000 \
  --type=method_call \
  --dest=org.freedesktop.timedate1 \
  /org/freedesktop/timedate1  \> > > > > > >
  org.freedesktop.DBus.Properties.GetAll \
  string:"org.freedesktop.timedate1"> >
Failed to open connection to "system" message bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.

Hope this helps

Having the same issue. Need to run an Electron app and Chromium requires non-root execution for sandboxing, but my app needs access to host Network Manager via D-Bus.

This issue appears to be related: https://stackoverflow.com/questions/74748794/how-to-use-the-dbus-system-in-a-container-with-docker-root-less

This suggests that the problem is a issue with libdbus EXTERNAL authentication, which could be patched in balenaOS to provide the required functionality: https://github.com/systemd/systemd/commit/1ed4723d38cd0d1423c8fe650f90fa86007ddf55

2 Likes

Any news on this topic? I’m also interested on being able to configure network from a container without having to run as root.

@gmerciel In the end I gave up and had the application running as root inside the Docker container, using a fork of our Docker image specifically for balenaOS.

In the long term I think we will try creating a custom host OS which exposes network settings to the container via an HTTP/WebSocket API.

You could probably achieve the same thing on balenaOS by having a separate (“side-car”) Docker image dedicated to communicating with the system DBus, and exposing network settings over HTTP/WebSocket/TCP socket, with your main application running as a non-root user in the main container.

Thanks @benfrancis, that’s exactly what I did, plus only binding that Web Service to 127.0.0.1, but I need to set network as host for both the dbus container and the container that access it. I guess I could get the internal ip and bind the service to that one, so it will only have access from the internal network, or if I don’t expose the port, I guess nothing of this is needed. What do you think?

Yes only binding the service to 127.0.01 is a good start, but there may still be security risks.

Depending on what else is running on that machine you may also want to use some form of authentication, validate the host header and possibly use CSRF protection.

The approach I was considering was having the host OS provide an authentication token to the container via an environment variable like the balena supervisor API does, but that’s a bit trickier on balenaOS when you can’t modify the host OS. I suppose you could provide the same token to both containers…