My thought was that we have two mechanisms in place for the command line UI: the user can use sudo snap install as the simple low barrier to entry method of installing snaps, or they can provide a bit more information (store login credentials) to access paid snaps and remove the need to use sudo.
Adding polkit auth would allow the same graduated access on the graphical side. If gnome-software doesn’t currently have a macaroon access token, it could ask for polkit authorisation and trigger the same auth dialog they see for all other sysadmin tasks on their machine. We could then delay asking for user to create store credentials up to the point where they try to install a paid snap.
@jamesh Right, the question is whether there’s a compelling benefit of that vs. what Robert is currently working on, using a local macaroon. The process for obtaining the local macaroon is similar to what you describe, with sudo, and the handling both on the client and the server (snapd) is very similar to what we do today already, so we’re supposed to get the benefit described without requiring two independent implementations of authentication.
The main benefits I can see for going with polkit directly are:
the admin can configure the level of access for normal users the same way as for other sys-admin tasks. This includes deciding which users can perform the task, whether they need to prove their identity via a password prompt, whether authorisation can be cached for a period of time, etc.
there is no need for the user application to store an access token.
if the admin changes the polkit policy, it will take effect immediately. In contrast, a macaroon will remain valid until its expiry date.
It might make snapd-login-service unnecessary: we could allow a normal user to call the /v2/login API provided polkit allows it.
There are already multiple independent ways to gain privilege on any given system. So far we’ve been mainly suggesting sudo for that, until an authenticated token is desired (for store access, or remote control, etc). If we add support for polkit, that’s again in addition to everything we already have today. That is really the key motivation for the design.
So, if I can simplify your point 1 into “It means not being able to have a polkit policy”, yes, that’s true and perhaps we should do that at some point for reasons related to that. That said, point 2 is not true. We need that regardless because polkit won’t tell us who that user is in the store, so we need the macaroon regardless. For point 3, we must support and improve expiry and other proper security measures with the mechanisms we use (sudo, macaroon, etc), and if we add polkit, we’ll need to also account for that. It’s one more mechanism rather than just a better alternative. Point 4 is closely related to points 2 and 3.
So, this is the background. We may end up going there, but given that this will be more logic, more dependencies, more authentication mechanisms, in addition to everything we already do, perhaps we should wait a bit more and see?
There’s trade-offs between the two options, I’ll weigh in with the main differences as I saw them:
Using Polkit would have resulted in less work and complexity required to implement on the desktop (i.e. snapd-login-service and local macaroons). This work is mostly done now so the up-front costs have been spent. The complexity is avoided by encouraging clients to use snapd-glib/snapd-qt instead of interfacing with snapd directly.
If snapd used Polkit there was an open question about how much Polkit would be required (i.e. does it make sense in IoT? What about other OSs?).
By not putting Polkit into snapd we’ve lost some context (snapd doesn’t know the user that makes a call via snapd-login-service) and fine grained control of privileges (we can’t configure users to only perform some snapd actions). The latter point could be solved by implementing fine grained policy into snapd, but this requires some work to match the current functionality of Polkit.
By making the client store a Macaroon for all operations we push more security responsibility into the client. For example, if the Macaroon was to be read by a different user account on the system it could be used to gain privileges that user shouldn’t have (this can possibly be solved by tying a Macaroon to a user account?). We have systems like libsecret and GNOME Online Accounts to help here but we have to be careful.
By not using Polkit we push more work into the desktop to manage Macaroon policy. Since snapd validates the Macaroon on each request it can potentially be revoked at any time (James’ point 3 above). However, we need more tooling to combine Polkit tools with Macaroon features.
A rejected solution was to make snapd-login-service a bigger deamon that would proxy all snapd requests through (i.e. like aptd / PackageKit). Interestingly this is what KDE Discover was using before they switched to snapd-qt. This had a number of issues:
There would have been a lot of work to mirror all the current and future snapd API.
snapd would have lost all context about clients (every request would have looked like it was coming from root).
Not all snapd operations are suitably low bandwidth to push through D-Bus easily.
I guess the other thing that feels weird to me is that at the point of a REST API request, we’ve got a wealth of information about the caller:
from SO_PEERCRED, we can get uid, gid, and pid
from the pid, we can also determine the AppArmor (or SeLinux) security label
we can even determine what executable is making the request, if we wanted to lock things down that way (although this only has limited value when you take things like LD_PRELOAD into account).
Yet we ignore all that if the user presents an access token that could be shared with other security principals without snapd’s knowledge.
Some of this could be improved by having snapd tie macaroons to a particular local user (although having things like snapd-login-service intermediating the login process complicates this). But if we’re talking about a non-store local macaroon, I wonder why we need the macaroon at all.
One of the other things polkit adds is the ability to differentiate between users with an active local login session, and other cases (e.g. running from a cron job, a remote login via ssh, etc).
Yes, there’s a lot we can do with pretty much endless possibilities and combinations since this is all software, and we’re all for improving snapd’s authentication and authorization semantics. Let’s please keep our feet in the ground while we do that. Small steps forward, preferably solving real problems and taking into account the logic and infrastructure already in place.
The current system was cooked taking into account cross-system usage. That’s mainly why we have macaroons instead of basing off completely on pollkit or user ids. Yes, we can change it, and yes we can do more, and we should even improve what we already have by baking uid, expiration, etc.
I can understand wanting to use the same API for both local access to snapd and eventual remote access. I don’t think it follows that it makes sense to use the same authentication for both use cases.
As a somewhat related example, CUPS uses the same protocol for local and remote access: IPP, either locally over a unix domain socket or remotely via TCP. But while it uses standard HTTP authentication mechanisms for the remote case, it uses peer credentials for the local case. The end result being that most CUPS users never have to configure remote authentication, since things work by default locally.
I also get a bit nervous about the current authentication set up. As I’ve authenticated with the command line snap client, there is a file sitting in my home directory that can effectively be leveraged to gain root access.
In addition to making the “no store login” case work better for graphical apps like gnome-software, polkit could also let us configure things so that e.g. using snap without sudo requires an interactive session on the machine.
To be honest, I’m not sure what value macaroons are bringing in the current state of auth. It’s basically just a cryptographically authenticated reference to a numeric account ID managed by snapd, with snapd mapping that account ID to the store login information.
Given that the number of administrative users on a system is generally going to be small, we’d get similar security by having snapd associate the account IDs with UNIX users, and just have the client present the account ID and use peer credentials to verify that they have access to that account.
My understanding of macaroons is that their primary benefit is that they avoid the need for a service to maintain a central database of session cookies / access tokens, pushing the storage of that info out to the client. But if the we’re working at the scale of snapd is (far fewer sessions than e.g. the store), then the benefits aren’t so clear cut.
But if we are talking about authenticating to the local snapd, that isn’t distributed.
I understand that the main benefit of macaroons is the ability for a recipient to add extra restrictions and pass the result on to delegate a portion of their privileges to another security principal. But if we lock the initial macaroon down to a single user (or even single user + security label), it isn’t clear to me who it could be passed on to. At that point, the macaroon is effectively just a bearer token.
I agree that when snapd becomes accessible over the network, the distributed benefits of macaroons become a lot more interesting. But it isn’t obvious to me that this requires that macaroons be used for all local auth.
One option would be to have an API available on the local socket that lets the user exercise their local credentials to create a starting macaroon. The user could then add their caveats and pass it on to whatever networked management system needs access. I could imagine Polkit checks would be useful for this kind of interface, since an administrator might be willing to let a user install packages, but not delegate the privileges they’ve been given.
Those are the core benefits. Doing something else would happen in addition to everything we already do. It’s more work, more libraries, more code, more dependency on the external APIs in the local systems, more maintenance, more risks. Yes, we can do that if we need to, but that’s why I’ve been trying to avoid it, and why I’m asking whether we might easily adapt the current logic to suit your criteria.
That’s what happens when one runs sudo snap login.
We seem to be bouncing between two different issues here:
Does use of polkit offer any useful benefits over the current status quo?
Are macaroons useful for local authentication?
We got on to (2) because you asked me how we could use macaroons to achieve some of the things I listed as benefits of Polkit. They are separate issues, so would merit separate decisions.
For (1), I think the main thing to take away is that we’ll probably need to use polkit in some fashion on the desktop anyway. We don’t want to run all of gnome-software as root for obvious reasons, and don’t want to open a terminal to run sudo. The current solution is a D-Bus daemon that uses polkit, so we’re really comparing two options:
snapd-login-service running as root proxies the login RPC, and does its own “is the user an administrator?” check, and snapd has no idea who the receives the resulting macaroon.
snapd adds polkit support so it privileged RPC calls are available to graphical apps. There is one less moving part in a security critical operation, and snapd knows who it is talking to.
There isn’t a case where polkit isn’t being used at all.
Now I understand that you may not want to introduce polkit as a dependency for Ubuntu Core. If we treated an error from the polkit D-Bus calls as a denial and fell back to the current policy (checking if the peer has uid=0), then the same snapd binary should work in both environments: there would just be one more way to prove administrator access if polkit was available.
As for (2), my point in previous messages was that if we load up a local macaroon with caveats restricting it to local use and to a particular UNIX user, then there isn’t space to attenuate it further in order to delegate the authority. And if that’s the case, things may be simpler if the client doesn’t have to store a security critical access token.
One thing that I’ve never cared for about the current macaroon-only approach (that @jamesh expressed elsewhere and I did long ago) is that you prove yourself that you’re are an admin once, and then you are never prompted again. I feel this is probably fine in IoT and server installs where local users are relatively few, but in desktop installs where use of the local user is guaranteed, it means that any process in the user’s session could use the macaroon. polkit allows for improving the security stance of the desktop session by allowing privileged daemons (eg, snapd) to hook into polkit, adding finer-grained options like active session, etc (again, as @jamesh mentioned elsewhere) and distro/site specific policy files. Polkit is ubiquitous now in Linux desktops so the dependency isn’t dangerous, but it obviously is something extra and arguably not needed on Ubuntu Core.
@jamesh idea of a runtime check is interesting IMO. Another way to do it would be to have snapd detect if polkitd was running and if not, just use the current macaroon-only approach and if so, require polkit (not sure if it should be in addition to the macaroon or instead of (probably in addtion to?)).
@jdstrand Yes, the constraints we have today on macaroons are simplistic and need work. I’ve been trying to encourage @jamesh to fix that, but it’s not working too well so far.
@jamesh It should be trivial for snapd-login-service to manage macaroons for multiple users instead of a single one. In fact, that’s probably the only reasonable way to implement it, since otherwise any user will be acting and observing the snaps of the first user to login into the store.
Also, the problems you raise about macaroons won’t suddenly disappear if you implement polkit support. Having timed macaroons is still a requirement that needs to be implemented. That’s part of the reason why having a single mechanism is better: we all collaborate to improve the one mechanism instead of having N different ways to do the same thing.
If you really want to introduce a polkit implementation into snapd, though, then please go ahead and propose a minimal change just to start the conversation. A single endpoint would do. We have a PR open to introduce a “userd” daemon into the “snap” command to have a way into the user login session, so the same dbus Go bindings used there should work.
Okay, I’ve gone ahead and put together a basic pull request:
I picked the login command, since this is the one command that gnome-software needed to proxy (via snapd-login-service). With this change, it would be possible to perform store logins by talking directly to snapd.
This change can be tested by moving ~/.snap/auth.json out of the way and then running snap login (no sudo) in a terminal of a graphical desktop session. After entering your email address and store password, the desktop session’s polkit agent will prompt you for your user password. Once polkit is satisfied, the login command will proceed.
So are there any more thoughts on this? I got some review feedback from @chipaca (thanks!), but really need some feedback on whether this has a chance of being accepted.
Sorry for the delay on this. I’m just coming back from holidays today, and we had a sprint a couple of weeks ago, so I’ve been mostly offline over that period. I will give it some priority now.