Request for daemon + browser-support for krellian-kiosk

krellian-kiosk is a snap which provides a web runtime for digital signage and interactive kiosks and therefore needs to be both a daemon and have browser-support. Krellian Kiosk is also intended to become an Ubuntu Appliance.

Requesting approval for daemon + browser-support for the krellian-kiosk snap.

Rejected manual review here.

Prototype source code here.

Thanks

Thanks for making this forum post - the use of browser-support with daemon grants a lot of privileges to a snap (see the previous discussions for a similar request a few years ago for some background on this Suppress the security-snap-v2_daemon_with_browser-support warning for the snap).

Does krellian-kiosk absolutely require the use of browser-support? I understand the wish for daemon is to have long-lived daemon that is automatically started etc - in that case, perhaps the use of the snap_daemon user via system-usernames could help so that the snap doesn’t have to run as root.

However, even in this case, the daemon will still be started as root and it would have to drop privileges to the snap-daemon user, so this doesn’t entirely alleviate the security concern.

As such, if this browser-support is absolutely required, we would need to perform publisher vetting as though this were a request for classic confinement.

Hi Alex,

Krellian Kiosk acts as both a web client and web server. It is essentially a full screen web browser which can be remotely controlled over the Web of Things. I therefore can’t see any way around it being both a browser and a daemon as that is fundamentally what it’s designed to do.

Running as a non-root user would be great, but the application also needs to configure network settings during first time setup (via network-manager) and bind a web server to ports 80 and 443 which I expect requires root access. (It might be possible to bind to different ports and redirect traffic using iptables, but that probably requires root access to configure post-boot as well).

What does publisher vetting involve exactly?

Thanks

Ben

P.S. Might it make sense to request auto-connection of the network-manager interface at the same time?

Are you saying that the browser itself is binding to port 80/443 and manipulating the firewall? If so, the typical design pattern would be to perform all your root actions early, then permanently drop to an unprivileged user. See System usernames for example code on how to do this in a snap-compliant manner.

You might also consider separating your application into different parts which adds security benefits. I don’t know how feasible that is, but eg:

  • run your webserver as a separate daemon, and have it bind to port 80/443 and permanently drop to snap_daemon
  • run your web browser as a separate daemon and either permanently drop immediately to snap_daemon or start is as snap_daemon
  • use configure hooks/etc to setup your firewall settings or have a separate daemon modify the firewall settings

It sounds like your snap would need to plugs network, network-bind and firewall-control (and perhaps network-control).

For use of ‘browser-support’ with a daemon, your snap should be modified to use system-usernames so that the browser process is not running as root. Once that is done, we’ll ask that you continue to use system-usernames for the browser process and assuming you agree, a member of our advocacy will contact you privately and ask a few questions related to your relationship with the software, device, etc.

I’m saying that the application acts as both a web user agent (browser) and web server and the server part binds to port 80/443. As long as the application can bind to port 80/443 (as it currently does) I don’t think it should need to configure the firewall.

It does need to configure the network (e.g. configure a Wi-Fi hotspot, broadcast a service over mDNS and connect to a Wi-Fi access point during first time setup) which can hopefully all still be done as a non-root user via the network-manager interface? (It may also need to re-configure network settings again in future if the network drops for any reason).

OK, I will try to get my head around that, thank you…

I would be open to that, but I’m not sure how feasible it is or how much it would actually help in practice.

An example feature of the application is that a user can control the kiosk remotely using its web interface to tell it to load a given URL:

The way this is implemented using Electron is that an Express.js web server listens for a POST request (or alternatively a WebSocket message) and then tells the system chrome to load the provided URL in its webview by sending a message to the renderer process using Electron’s built-in IPC mechanism (the web server and web content rendering already run in separate processes).

Turning the web user agent and web server into separate executables inside the snap package would mean adding an additional IPC layer for the server process to communicate with the user agent process in order to control it. An example IPC mechanism might be a WebSocket server, which would just be recreating what already exists and adding an unnecessary extra layer of complexity!

If I’ve understood correctly then I would rather avoid this extra complexity if possible as it isn’t needed for any other platforms on which the kiosk application might run.

So for now I will try to implement the system usernames approach and let you know how I get on. I am of course happy to answer any questions about my company and product to assist with the approval process.

Thanks

@benfrancis please update us on your progress with system-usernames etc - also I assume you still require both daemon and browser-support for krellian-kiosk - if so, the only option then is to do publisher vetting as for classic confinement requests. If this is the case, let me know and we can get the @advocacy team to start the process.

@benfrancis, could you please update us on your progress?

Hi @alexmurray @msalvatore, thanks for following up. I haven’t made any tangible progress on this issue yet.

I haven’t fully explored the system usernames system yet, but I noticed all the examples were in C so I was looking for advice on how to achieve this for an Electron/Node.js application.

A key issue is that the application needs to bind a web server to port 80/443 which requires root access.

@ijohnson has suggested having the application start up using the snap_daemon user using setpriv, then have systemd bind to port 80 and add listen-streams to snapcraft.yaml which connect up the sockets.

This seems non-trivial to figure out (though similar to the iptables solution I suggested above) so I’ve been focusing on implementing the remaining features for the 0.1 release of the snap (e.g. configuring a Wi-Fi hotspot for first boot) to make sure that binding to port 80/443 is definitely the only feature that needs root, before I do that.

Any more advice you can provide on how to achieve the above with systemd and listen-stream would be helpful.

Thanks

@benfrancis hopefully @ijohnson can provide some more guidance re systemd / listen-stream as I am not familiar with this.

Sorry if my email was unclear, but I think this should be rather straight-forward for your application, wherever you open the port(s), just replace that bit of code with the calls to get a port from systemd. The relevant bit of code from that example is just

var server = http.createServer(function(req, res) {
...
}
server.listen('systemd')

Wherever you normally call server.listen(80) or some such, just use systemd instead.

and the associated listen-streams in your snapcraft.yaml:

apps:
  krellian-kiosk:
    daemon: simple
    restart-condition: always
    command: desktop-launch xwayland-kiosk-launch bin/drop-snap-daemon.sh $SNAP/krellian-kiosk/krellian-kiosk --no-sandbox -p 80
    sockets:
      http:
        listen-stream: 80
      https:
        listen-stream: 443

(in conjunction with a script bin/drop-snap-daemon.sh)

Have you tried the above? What happens?

@benfrancis ping, did you have a chance to try @ijohnson suggestion? Thanks!

@benfrancis - ping, could you try @ijohnson suggestion? Thanks!

@emitorino Thanks for the suggestion. I’m currently on parental leave. Will be back in about three weeks.

1 Like

@benfrancis - gentle ping - have you had a chance to follow up on this?