Certbot: request for classic snap approval

I’m +1 to give classic as well provided @niemeyer’s points are acknowledged.

In the interest of time, I’ll grant use of classic based on @rbasak not changing ‘grade: devel’ and not handing over the snap until the above points are acknowledged. This is now live and will pass automated review in the future. For the existing revision, please either request a manual review or upload a new revision.

1 Like

I’m an upstream developer of Certbot and @niemeyer’s points sound good to me. We have a question for you all though.

Certbot has a plugin system which allows people to extend the project adding new ways to obtain or deploy certificates. We have plugins to perform domain validation with different DNS providers and plugins configure certificates with software like Apache and Nginx. We also have third party plugins written by people outside of the Certbot team.

To allow people to continue to use this system with a Certbot snap, @rbasak proposed https://github.com/basak/certbot-snap-build/tree/snap-plugins/doc. The way this works is plugins snapped separately can expose their code to the Certbot snap over the content interface which it will load and run.

The potential concern here we wanted to ask you about is that the plugin will be run with Certbot’s classic confinement even if the plugin is a regular confined snap. Classic confinement is often what is needed by the plugin to be able to do things like configure certificates with a web server, however, plugins would be able to do this without review if they implement the correct interfaces and are connected to the Certbot snap.

Are you all OK with Certbot plugins potentially written by a third party using this setup after users manually connect them to the Certbot snap? What about us configuring our own plugins we snap separately to automatically connect since they will be coming from the same publisher?

We wanted to get your approval here before continuing with this approach.

You can’t use the content interface. making it a classic snap will completely turn off interface usage (but with classic you can indeed just access the content of the plugin snaps anyway. classic behaves no different to I.e. a self contained app tarball you extract to /opt, just with some package management (install/remove/rollback) added)

Just note that using classic means your app will not be usable in ubuntu core (iot/cloud/embedded) systems where use of classic is completely denied.

I’m aware of the limitation. We are still using the interface to identify the plugins for the classic snap to load. We aren’t using the interface to actually load them. See my proof of concept for details.

That’s fine - the point of the classic snap is to permit certbot administration of SSL-based services installed on the host system itself outside of a snap. This doesn’t make sense in the iot/cloud/embedded space since AIUI there is no concept of that.

For iot/cloud/embedded I’d expect a certbot part to be used instead. This is orthogonal to, and out of the scope of, the current certbot snap effort.

heh, so you think an IoT gateway that manages a few 100 PLCs in a factory shouldn’t use certbot to manage its certificates when talking to its clients ? i think certbot would be a great bit of added security here and having a strict confined snap (with potentially having additional interfaces) would be a great thing …

nontheless, my point was not to be the party pooper, but just to point out the limitations, after all @jdstrand already granted classic, i didnt mean to stir up a discussion, just to bring up some points about limits this decision brings along :slight_smile:

No, I’m saying that the right way to integrate certbot into such a device would be to embed a certbot part into the snap that provides your SSL-based service itself. As I say this is orthogonal to this current effort as it would exist to support a different use case.

I can conceive of an architecture where there is a snap that provides an interface to coordinate so that a single certificate can be obtained to be shared between multiple services, each that is in its own snap. If this were to be done, it’d be a confined snap, yes, but it would again be orthogonal to and an entirely different effort to the current one. You’d need to invent and implement your own IPC protocols to operate certbot over such an interface since it would require a separation between CSR generation, certificate storage, service configuration and challenge implementation in a fashion that I don’t believe exists today. I’m not sure certbot would even be the right tool for the job; a different ACME implementation might work better. If someone wants to work on that anyway, please feel free, and if you end up using certbot then we can coordinate what to do about the namespace then. :slight_smile:

Edit: and to be clear, nothing that we’re doing limits a future implementation to support the use cases that you mention.

and i’m saying having a single snap with a content interface that all other SSL service using snaps can utilize would be nicer … i understand what you mean but even on IoT gateways we like to avoid duplication :wink:

anyway, as i said, it wasnt the purpose of my post to stir up a discussion, but to mention the limitations for the OP, which i did…

Can someone from the snap team weigh in on my question at Certbot: request for classic snap approval?

We are blocking moving forward with Certbot snaps on explicit approval of this approach.

Thank you for following up. @rbasak, please feel free to push to stable as desired.

This has the potential to invalidate at least the spirit of some of @niemeyer’s points above, but reading the proposal in https://github.com/basak/certbot-snap-build/tree/snap-plugins/doc requires an admin to run sudo snap connect certbot:plugin ..., which must be done by an admin (ie, honors point ‘3’) and the proposal mentions ‘Only perform this step if you trust the plugin author to have “root” on your system.’, which is great, but it would be good if this was somehow surfaced to the admin who might be cutting and pasting commands and not knowing the ramifications of the snap connect command. I’m not sure what a good UX would be for that, but can say that a connection hook may be helpful and/or a wrapper that notices the registered plugin and says something like “INFO: 3rd party plugin detected. Please only use if you trust the author of this plugin with root on your system” (or similar, I don’t want to dictate how this is done).

IMO, this is ok so long as the risk of the snap connect is bubbled up to the user in some manner. @pedronis please comment if you feel my assessment and recommendation need refinement.

1 Like

A way to do this I think would be to have a prepare-plug-plugin hook in the certbot snap that did something like this:

#!/bin/bash -e

if [ "$(snapctl get plugin-accepted)" = "ok" ]; then
    # allow the connection, but reset config to allow for other slots to go through this auth flow
    snapctl unset plugin-accepted
    exit 0
else 
    echo "Only connect this interface if you trust the plugin author to have root on the system"
    echo "Run \`snap set $SNAP_NAME plugin-accepted=ok\` to acknowledge this and then run this command again to perform the connection"
    exit 1
fi

For example with an example snap with network-setup-observe, this looks like:

$ snap install my-snap-name_0.1_amd64.snap --dangerous 
my-snap-name 0.1 installed
$ snap connect my-snap-name:network-setup-observe
error: cannot perform the following tasks:
- Run hook prepare-plug-network-setup-observe of snap "my-snap-name" (run hook "prepare-plug-network-setup-observe": 
-----
Only connect this interface if you trust the plugin author to have root on the system
Run `snap set my-snap-name plugin-accepted=ok` to acknowledge this and then run this command again to perform the connection
-----)
$ snap set my-snap-name plugin-accepted=ok
$ snap get my-snap-name
Key              Value
plugin-accepted  ok
$ snap connect my-snap-name:network-setup-observe
$ snap get my-snap-name
error: snap "my-snap-name" has no configuration
$ snap connections my-snap-name
Interface              Plug                                Slot                    Notes
network                my-snap-name:network                :network                -
network-bind           my-snap-name:network-bind           :network-bind           -
network-setup-observe  my-snap-name:network-setup-observe  :network-setup-observe  manual

This isn’t ideal because it only works with a single connection at a time and the interface hook here doesn’t have a way to uniquely identify an admin’s acceptance of a particular connection, just that they acknowledge a single plugin. I.e. you could have issues like this:

$ snap connect certbot:plugin some-plugin-author1:plugin
<error run snap set ... >
$ snap set certbot plugin-accepted=ok
$ snap connect certbot:plugin some-other-plugin-author2:plugin
<incorrect success, should only have worked for some-plugin-author1:plugin>

Unfortunately I think it is by design that interface hooks do not have knowledge of the other side of the connection, except for attributes. Attributes could be used by the other side, where the other snap is required to set something, but this seems not ideal because then all the plugin authors need to agree on a format for setting attributes that the certbot snap can verify in these hooks.

I like the ingenuity of this, but doesn’t it result in the same problem? Third parties would include this step in the instructions for users to copy and paste, and the user wouldn’t know any different.

IMHO, this is no different than where we instruct snap authors to not include --classic in their snap installation instructions, in that we ask folks to abide by this but at the end of the day we can’t really control what instructions folks put up.

Additionally, the instructions that they would need to post would then become:

$ snap set certbot plugin-accepted=ok
$ snap connect certbot:plugin some-plugin:plugin

Which actually thinking back on it, perhaps we can make it more obvious to the admins who might run into such commands by changing the name of the configuration option. Something like:

$ snap set certbot trust-plugin-with-root=ok

Unfortunately we don’t have a way to interactively block from inside the hook, save a GUI portal which wouldn’t work for users with headless setups which seems likely given the sort of application that certbot is.

This makes total sense to me.

I haven’t looked into what snap offers us yet, but for what it’s worth, I personally like something like snap set certbot trust-plugins-with-root=ok if its absence causes snap connect certbot:plugin ... to fail. A user could still copy and paste the command, but one would hope trust-plugins-with-root=ok would make people think twice about doing so.

Just to make sure we’re all on the same page, based on @jdstrand’s message, I’m planning for us to implement something like this and go forward with this plan. If there are any concerns about this, please raise them now because I’d hate for us to start migrating our users over and find out that the snap store team isn’t OK with Certbot doing this.

As a member of the reviewers team, IMO this is in alignment with @niemeyer’s points. @pedronis, as architect, can you comment one way or the other if you feel differently?

@jdstrand this is fine in the terms of respecting the spirit but in general is problematic to be up to the snap to enforce this kind of policy. The snap can change after the fact.

Not a blocker for this case here in particular, and we don’t have many classic snaps with slots or plugs ATM and we haven’t fully worked out the semantics in the classic case for those.

But in principle, perhaps if an interface could potentially let a confined snap escape that confinement by a connection to a classic snap, maybe snapd itself should warn when connecting ? similarly to snap install vs snap install --classic ?

Would we do this for any interface? A clear subset? The problem here is that if the set is not well defined automation/use of this via the API might get fragile. Also --classic wouldn’t be quite the right flag to connect for these cross-confinement connections.

I agree in principle snapd should be issuing this warning. I think we need the semantics in place first before we can consider UX. Snapd is in the right place to issue the warning, but it doesn’t really know the context of the connection and the actual consequences of it, so the messaging/arg string would have to be just right. Not saying this is the string, but something like --connection-allows-classic conveys that the connected snap may run with classic permissions so perhaps something along those lines makes sense.

@bmw - ok, feel free to proceed with your implementation. At some point we’ll have something that is better integrated that you can move to (see previous comments).

Sounds great. Thanks @jdstrand.