Classic confinement for bootstack-ops snap


We have a collection of tools and utilities for managing openstack clouds that are built by Juju, and one of the things we wish to do is backup the Juju client configuration - which is hosted in ~/.local/share/juju. This is only available to us if we use classic confinement.

Can we please allow classic for the bootstack-ops snap?

Feel free to hit me on IRC, xavpaice.

Talked to @xavpaice on IRC, the only reason why this snap needs classic confinement is because it wants read-only access to ~/.local/share/juju to perform backups which is a location that the non-snap juju and juju client charm uses.

While the backup scenario is understood (eg, Classic Confinement Request for Restic snap), in this case it is only one particular directory in the user’s home. There was some talk of extending the home interface to accommodate situations like this. @niemeyer - do you have thoughts on this? Shall I grant classic in the meantime (I’ve vetted the publisher).

It would be a shame to lose strict confinement just because it cannot load those files. I think we need a better plan here.

We might extend the home interface to support generic request of specific paths, but there’s a relevant issue: we don’t yet have a way to communicate to the user that these paths are required, which means someone connecting it by hand would not know what they are actually allowing. So a no go for now.

On a different thread, we are also working on a more general solution to support that kind of use case, that could enable the juju snap to request access to those bits. But that will also take a little while.

So we will need a third option here if we want to avoid classic on this snap, which again seems reasonable.

Can we please dig a bit further into the use case for that?

Towards that goal, a first question might be: why do we have a third-party snap fiddling with juju configuration? That doesn’t sound like a good idea in principle.

@niemeyer - AIUI (I’m unfamiliar with this snap), only read-only access is required to this directory since the snap attempts to backup those files. AIUI, there is no restore operation or other functionality that requires write access. @xavpaice, can you confirm?

I understand your point, however to backup the juju client we need to access those files, and that’s one of the tools I’m trying to implement here. These files are created by the juju client snap, which is classic, so we’re following an existing precedent. If the juju snap were to write it’s client config somewhere more accessible, that woudn’t be an issue.

The other aspect of this is that there are several tools we use as operators that make use of the Juju client. In order for that to work, it has to be able to read it’s config files, which are ~/.local/share/juju. If we can’t do that, then a snap is the wrong approach to distribute these tools and we’d need to go about finding a way to build and package all the Python deps we need, which is a pain for sites that have limited Internet access and no way to use Pypi.

@xavpaice Have you considered using a “content” interface with the juju snap? It sounds reasonable to have that data being exposed by juju itself, if it wants its data to be accessible for backups or arbitrary tools.

That seems much more reasonable than making what is today a strict snap become a classic one merely to poke at a different snap’s private data. The strictness there precisely intended to limit that sort of access, and force the snap to request data appropriately instead, so it’s really a feature in this case.

This sounds great. I’m struggling a bit to find the right documentation - but as I understand it, you’re suggesting:

  • change the juju snap to provide a ‘content’ interface, with a read slot for ~/.local/share/juju (dir in home, not in the snap directories). The current implementation of “home” doesn’t allow hidden files/dotfiles.
  • add the plug to my snap

That sounds ideal, however is it possible for a classic snap (Juju) to add plugs for something outside of $SNAP (or at all)?

Juju uses the config in ~/.local because the client is configured per user. Of course, if the client config wasn’t a dotfile, it would be fine to use the “home” interface and I suspect the Juju snap wouldn’t need classic either. I don’t fully understand why dotfiles under the home directory are not allowed to be accessed, surely a snap that allows access to home would still be restricted by the permissions of the filesystem and therefore whether the files are dotfiles or not is irrelevant? Regardless, is it better to raise a bug report requesting a new interface for access to files like this so that users would be well informed (e.g. “home-hidden”)?

Given that the Juju snap itself is classic, and I don’t expect for this bootstack-ops snap to be useful to people outside the Bootstack team, nor ever installed on core, I’d like it if we can get some movement soon even if it does mean allowing classic until we can either move the Juju client config to somewhere accessible, or make dotfiles in home accessible. We’re currently shipping utilities in an unsustainable way and the benefits of using snaps is immense. The limitations we’re facing with our current methods affect current, paying customers and our ability to scale, which is becoming more of a problem as we become more successful. Once we’ve overcome the limitations we’re facing right now, I’d love to switch to strict confinement.

1 Like

If that’s the reason juju is using classic, it would be a misuse of classic. There’s no reason for juju to store its data in that specific location. There must other reasons though, given the sort of work juju needs to do for system management?

The problem is that we need a line to guide ourselves in terms of what is or is not reasonable. Having one snap becoming classic because it needs to access private data from another snap is specifically a case we need to avoid. It’s the very reason why dot files are not accessible for strict snaps in the first place.

Here is a suggestion that can get you going quickly if there are no other alternatives in sight: let’s introduce a juju-client-observe interface that explicitly allows accessing its data. Or perhaps juju-observe, if the snap contains both the client and its daemons.

How does that sound? @jdstrand?

That works for me. I can even write the interface and get it up quickly. @xavpaice, if you are agreeable, please reaffirm that it is only read-only access to ~/.local/share/juju you are interested in. Please consider future cases where you may want read-only access to other things juju (and what those paths are) so we can decide on juju-client-observe vs juju-observe.

Before reading this larger response, please see my question about ‘juju-observe/juju-client-observe’ since that is the immediate path forward. Answering your questions here for completeness.

Note that today classic snaps cannot use ‘plugs’ for various reasons. We could certainly lift that for the content interface (ie, we only add apparmor policy/etc if confinement != classic), but this would require some work to detangle applying various security backends except mount when using classic confinement.

It’s also interesting to think about exporting per-user content via the content interface. Normally we export content from the SNAP, SNAP_COMMON or SNAP_DATA. Yours would be the first use case for this (and likely have to build on the per-user work that was recently done for portals).

Gustavo mentioned why we don’t allow access to dot files and I’ll expand on that. It is important to note that traditional desktops have the concept of a trusted session where each user runs a login session and anything that the user runs is considered trusted by the user. Snaps change that and snaps are considered untrusted by the user session and from each other so we don’t allow snaps to access each other or anything outside the snap by default. We then have interfaces that expand that access in controlled ways. The home interface is a so-called transitional interface (because the access it grants is so broad) to enable existing software to access non-hidden data. We could allow accessing hidden data, but then we’d expose potentially very sensitive data to all snaps using the home interface-- eg, ssh and gpg keys (it is natural to then say “well, just block those” but a blacklist approach is never complete-- we might add ssh and gpg, but forget .fetchmailrc, for example). It is important to also keep in mind the dot directories are used by the user’s trusted session applications that typically come from debs/etc (ie, not snaps) and these files are often incompatible with snaps that have different versions of the same software installed or use different underlying libs (eg, gtk). If the snap had read or write access to arbitrary dot files, then the snap may not function correctly (eg, since the dot files use an old format) or the snap might break the user’s session (eg, since the snap migrates from the old format to the new and now the user session is broken; I’ve personally seen someone’s desktop session get completed hosed because he (on his own, not because it was advised!) bind mounted his home into the snap and the snap made a bunch of incompatible changes).

Finally, it was my understanding that the juju snap could move to strict confinement after we introduced one of the ssh-keys or gpg-keys interfaces (I can’t remember which otoh), and Nicholas said he’d move juju to strict confinement. I realize he has moved on, but if there are still things keeping juju classic, please review those and perhaps introduce a new topic so we can work through any remaining issues.

Hope this clarifies some things!

@jdstrand, @niemeyer, yes it’s read-only access to ~/.local/share/juju that I’m looking for - no write required. Having a juju-client-observe interface would be absolutely perfect for my use case, I hadn’t even considered that adding an interface might be an option. I might need a little advice on how to access the directory since $HOME is specific to the snap, but there’s an env var I can use for juju client config which can remap me back to the right place. Currently, if I add JUJU_DATA=${HOME}/.local/share/juju’ to the env from which I call the snap (i.e. before $HOME is remapped), I seem to get the right result. If there’s a way to trigger the interface to avoid having to edit .bashrc that would be ideal, but not essential.

We will also want access to the juju binary, which is in the path via /snap/bin but might also be from a .deb, depending on the history of the machine.

Thanks so much for the detailed information here, it’s something I think a number of folks might find useful.

It turns out there were a number of items that meant the Juju client snap needed classic, from the README in the repo:

Needed for confinement

To enable strict mode, the following bugs need to be resolved, and the snap updated accordingly.

I can write this. I’ve added it to my todo and should have something up for review later today.

You can always call ‘getent’ to get the home for the user as opposed to the home for the snap. Eg: getent passwd $UID | cut -d ':' -f 6.

“Missing support for abstract unix sockets ( )”
There is an open question on this in the bug. The last time I talked to Nicholas I was under the impression this was no longer needed. Also note new support for socket, socket-mode and listen stream (Snapcraft.yaml reference) that may help you in this area

“Needs SSH interface ( )”
This should be DONE (we now have both ssh-keys and ssh-publis-keys interfaces)

“Bash completion doesn’t work ( )”
This should be DONE. You might try looking into @chipaca’s excellent bash completion work: Tab completion for snaps

“Juju plugin support ( )”
This doesn’t seem to be a snapd deficiency (please correct if I’m wrong). We now have a content interface (The content interface) that should allow the juju snap to ‘slot’ a read/write area and for plugins to ‘plug’ this slot and write data to it. How you organize it, do registration, etc is completely up to you

Can you verify the above and confirm if anything else is still needed?

FYI, juju-client-observe is merged into master and the upcoming 2.33.

1 Like

The Juju plugin protocol requires the ‘juju’ command line tool to execute arbitrary programs on $PATH that begin with ‘juju-’. It seems incompatible with confined snaps, and changing it would technically be a backwards incompatible change and shouldn’t be done until Juju 3.0 (to eg. require plugins to be installed in /snap somewhere, or be distributed as snaps that are plugged into the Juju snap)

I’m not familiar with the juju plugin protocol (maybe @niemeyer should weigh in on design for strictly confined juju), but it seems like the juju snap could provide a read-only slot that plugin snaps could consume which allows use of the ‘juju’ command (additional interfaces might need to be developed) and the juju snap could provide a read/write slot that plugin snaps could consume to write to. The juju snap is updated to add the read/write area to its PATH. Non-snap juju plugins write to wherever the juju command expects to find them (again, another interface might be needed for the juju snap to have this access, perhaps ‘juju-support’).

I am certainly missing details and don’t have the full picture… but it seems based on my limited understanding that juju could plausibly be strictly confined. @niemeyer - help! :slight_smile:

Now that we have the 2.33 released, I tried to use the new interface to hook up the juju client and get confinement working, but when uploading to the store I get the following:

Error while processing...
The store was unable to accept this snap.
  - interface 'juju-client-observe' not found in base declaration
  - interface 'juju-client-observe' not found in base declaration
  - interface 'juju-client-observe' not found in base declaration
  - unknown plugs interface name reference 'juju-client-observe'
  - unknown plugs interface name reference 'juju-client-observe'
  - unknown plugs interface name reference 'juju-client-observe'

Is there something obvious that I’m missing here? I’ve added the following to the snapcraft.yaml:

    command: something
      - all-the-other-plugs
      - juju-client-observe

It exists here:

$ snap interfaces :juju-client-observe
Slot                  Plug
:juju-client-observe  -

$ snap version 
snap    2.34
snapd   2.34
series  16
ubuntu  18.04
kernel  4.15.0-24-generic

What is the output of snap version?