Making docker interface implicit

Hi,
I’m working on improving the docker snap experience, and one problem I’d like to fix is the current need to connect the docker interface from the docker snap to itself.
To explain better, the docker snap provides general purpose control/usage of containers through a daemon that listens on a socket, /var/run/docker.sock. The command docker from the docker snap sends REST commands to this socket, so it needs to have permission to talk to that socket. Currently that permission is implemented in the docker interface, but this interface is not implicit. This means that some snap has to provide this interface as a slot and then the docker snap can plug into it in order to have this permission. Currently, that snap is the docker snap itself*, meaning that in order to use the docker command in the snap one has to do something like this:

snap connect docker:docker-cli  docker:docker-daemon

Which isn’t intuitive and seems confusing to need to manually connect a snap to itself.

There are 2 ways I see to fix this.

  1. Make the docker interface implicit, so it connects to the core snap
  2. Make the docker command in the docker snap plug into the docker-support interface.

The docker-support interface has a lot of other permissions however, not just talking to the socket, as the docker-support interface is meant to be plugged by the daemon mentioned above which actually does all the various container creation tasks and such. This means that the apparmor/seccomp profiles for the simple docker command would have a lot of other stuff that it really doesn’t need access to.

What are others thoughts on this?

  • note that the reason the docker snap exposes the interface to talk to the socket at all is so that other snaps could plug into this interface and control docker, and this is an expected use case

I thought that the auto-connection logic would allow a snap to plug its own slot (@pedronis, do you recall the details here?)… if that is true then it sounds like there is a bug. If that is not true, we could also simply issue a snap declaration allowing the docker snap to auto-connect to the docker slot.

if it’s not possible it probably wouldn’t be because of the declaration (the declaration should allow to express that), but I’m not sure the current auto-connect logic even considers self-connections to start with

I looked at the snap declaration for the docker snap, and it already has a declaration to auto-connect. I then installed the docker snap with sudo snap install docker and it was auto-connected fine:

$ snap interfaces
Slot                                      Plug
...
docker:docker-daemon                      docker:docker-cli

And indeed the security policy is updated:

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

At this point, it looks like everything is setup correctly for the docker snap.

Can you give more details on how to reproduce? (I’ve seen at least one recent report where connections didn’t auto-connect or became disconnected that, iirc, @zyga-snapd is looking into)

We were only aware of one case that is now fixed where auto connections would not happen if coupled with refreshes of core.

@jdstrand it would be good to retest with core from edge because we tweaked something there that might affect this

It works there too:

$ snap version
snap    2.33~rc1+git776.efd90f3~ubuntu16.04.1
snapd   2.33~rc1+git776.efd90f3~ubuntu16.04.1
series  16
ubuntu  16.04
kernel  4.4.0-127-generic

$ sudo snap install docker
docker 17.06.2-ce from 'docker-inc' installed

$ snap interfaces
Slot                       Plug
...
docker:docker-daemon       docker:docker-cli

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

The auto-connection doesn’t work for me when I install locally with --jailmode and --dangerous. I assumed that jailmode + dangerous works essentially the same as installing from the store with respect to interface connecting, but perhaps it doesn’t?

No, it doesn’t because of --dangerous this is an unasserted install; in other words there is no snap declaration (an assertion) that provides the auto-connection information. This is operating correctly. It is possible to do an asserted install with a predownloaded snap if you do:

$ snap download docker # this pulls down the snap *and* the assertions
$ sudo snap ack ./docker_179.assert
$ sudo snap install ./docker_179.snap # --dangerous not used

Well the reason I was using --dangerous was because I was locally developing/installing a snap that hadn’t been pushed to the store (I’m updating the docker snap and so testing everything locally before pushing to the store).

Is there a way to do the same locally (i.e. install a local .snap file as if it has all relevant assertions from the store)?

No because your snap is not bit-for-bit the same as the one from the store.

So the only way to test interface auto-connection is to upload a snap to the store and then try installing it from the store?

Again, perhaps I should have made this more clear, I’m working on an update to the docker snap, so what I have is not bit for bit the same because it’s a different version of docker and I want to ensure that my updates work the same as the original docker snap. Here is my snapcraft.yaml if that helps : https://github.com/anonymouse64/docker-snap/blob/master/snap/snapcraft.yaml

You can write unit tests for auto-connection which has a way to mock the signing authority. Typically we don’t test that manually/explicitly (we have some integration tests and unit tests).

Yes, but keep in mind your changes to the docker snap aren’t going to affect auto-connection, so auto-connection needn’t be a part of your testing since snapd will operate the same. This needn’t be an issue in practice because locally you can script up the ‘snap install --dangerous ./docker…snap && snap connect …’ until you are satisfied with your changes. Once you are happy with it, you can upload it to the edge channel (or some other branch or track you use for testing) and then do the full integration/user experience testing and verification that includes auto-connections are working.