Sudo-less snap commands

Hello everyone :wave:

I’ve noticed it’s possible to run snap commands (search, list, install, remove, refresh) without using sudo. I am however yet unable to find what controls these permissions. I manage a few Linux workspaces and would like my users to only be able to use the software centre to install snaps, and not command-line interface (or rather, to not be able to install locally created snaps, as this allows escalation to root).

If someone could point me in the right direction, that’d be great! Thanks in advance :slight_smile:

it is sudo snap login that allows you to do this … if you have properly logged in you will not need sudo for any snap commands … if you want to enforce that everyone on a machine needs sudo, just call snap logout

Thanks for your quick reply! Can I forcefully log out all users from snapd? Because snap logout requires authentication and afterwards says I’m not logged in, whilst still allowing me to remove and install snaps:

user@linuxvdi:~$ snap logout
error: not logged in
user@linuxvdi:~$ snap remove codium
codium removed
user@linuxvdi:~$ snap install codium --classic
codium 1.56.0 from Snapcrafters installed

this actually smells like a bug …

Alright. Is this the place to report said bug, or should I go elsewhere with this? :slight_smile:

lets just wait until someone from the snapd team sees this thread …

What is the output of the following commands:

snap version
snap whoami
sudo cat /var/lib/snapd/state.json | jq '.data.auth.users| length'
sudo cat /var/lib/snapd/state.json | jq '.data.auth.users | .[].id'
sudo cat /var/lib/snapd/state.json | jq '.data.auth."last-id"'

Hi @ijohnson! Here’s the output of the commands you requested:

$ snap version
snap    2.51.1
snapd   2.51.1
series  16
ubuntu  20.04
kernel  5.8.0-59-generic
$ snap whoami
e-mail: -
$ sudo cat /var/lib/snapd/state.json | jq '.data.auth.users| length'
0
$ sudo cat /var/lib/snapd/state.json | jq '.data.auth.users | .[].id'
jq: error (at <stdin>:0): Cannot iterate over null (null)
$ sudo cat /var/lib/snapd/state.json | jq '.data.auth."last-id"'
0

Do you have a file located at ~/.snap/auth.json ? If so, what does this show (don’t paste the whole file, it contains a sensitive macaroon):

cat ~/.snap/auth.json | jq '[ .id, .email]'

The snap install command asks the backend snapd daemon to install the snap on its behalf, the same way the Snap Store app does.

Snapd will process the request if one of the following is true:

  1. the request came from the root user (using credentials read from the unix socket connection)
  2. the request included auth data for a Snap Store login created using sudo snap login (what the other replies are referring to).
  3. polkitd says the request is authorised.

I suspect you’re probably seeing (3). When installing a snap, snapd asks if the caller is authorised to use the io.snapcraft.snapd.manage action. The default policy for this action is auth_admin_keep, which requires the user be an “administrator” and that they enter their own password.

On an Ubuntu system, an administrator is a user who is a member of either the sudo or admin groups (as configured via /etc/polkit-1/localauthority.conf.d/51-ubuntu-admin.conf). You can also override the default policy for how an action is handled. On Ubuntu and Debian systems, this is done via .pkla files. On most other systems it is via JavaScript .rules files.

As for trying to allow users to install only strict confined snaps, we unfortunately don’t separate that out into a separate polkit action. So there is no way to allow one but not the other.

2 Likes

There isn’t such file:

 $ cat ~/.snap/auth.json | jq '[ .id, .email]'
cat: /home/user/.snap/auth.json: No such file or directory

However, I think the custom polkit configuration is what causes the issue…

Hi @jamesh! Thanks for your reply! Your notes regarding polkit makes me think that may be the issue. I’ve modified the polkit configuration in order to allow passwordless installation of snaps through the software centre, and may have allowed a bit too much.

I create a polkit action file called /usr/share/polkit-1/actions/io.snapcraft.snapd.policy with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
 "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>

  <vendor>Snapcraft</vendor>
  <vendor_url>http://snapcraft.io</vendor_url>

  <action id="io.snapcraft.snapd.login">
    <description gettext-domain="snappy">Authenticate on snap daemon</description>
    <message gettext-domain="snappy">Authorization is required to authenticate on the snap daemon</message>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin_keep</allow_active>
    </defaults>
  </action>

  <action id="io.snapcraft.snapd.manage">
    <description gettext-domain="snappy">Install, update, or remove packages</description>
    <message gettext-domain="snappy">Authentication is required to install, update, or remove packages</message>
    <defaults>
      <allow_any>yes</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>yes</allow_active>
    </defaults>
  </action>

  <action id="io.snapcraft.snapd.manage-interfaces">
    <description gettext-domain="snappy">Connect, disconnect interfaces</description>
    <message gettext-domain="snappy">Authentication is required to connect or disconnect interfaces</message>
    <defaults>
      <allow_any>yes</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>yes</allow_active>
    </defaults>
  </action>
</policyconfig>

I thought this would only affect the software centre, but hadn’t realised the snap command itself also relies on polkit to authenticate.

However, perhaps I am surpassing the goal I want to achieve with all this configuration. From your reply I can tell I wasn’t entirely clear; users are allowed to install non-confined snaps, I just don’t want them to install locally (non-snapstore) snaps that they can craft themselves in order to escalate to root. I thought the only way to achieve this is to only allow users to use the software centre to install snaps, but if this can be achieved using the snap command as well, that would of course also work.

I’d strongly suggest that you don’t edit the XML files directly. They are not treated as configuration files and will likely be overwritten during an upgrade at some point.

You will want to create a new file under /etc/polkit-1/localauthority, as described in this man page:

This will survive package upgrades, and gives more flexibility than the policy defaults that can be set in the XML files.

But as I said earlier, I don’t think our use of polkit actions is currently granular enough to do what you want. Installing a snap file is handled via a POST request to /v2/snaps API endpoint, but that is also used for install/update/removal of multiple snaps at once. The polkit check is performed before we determine which of those cases we’re handling, so you can’t really distinguish them.

It would be nice to improve the polkit support. What’s there at the moment was essentially the minimum we needed to get a nice experience in the Snap Store UI. On a default install, this is to enable users who already have permission to execute arbitrary commands via sudo to also install snaps via the GUI. It hasn’t really addressed the needs of people trying to build locked down desktop systems.

1 Like

Thanks for your reply! I’ll get to re-writing the policy files and place them under /etc/polkit-1/20-org.d/.

As for not being able to allow users to install snaps only through the software centre, that’s a pity. I’ll have to discuss this matter with my colleagues and decide whether we’ll accept the risk of escalating to root, or don’t want our users to install snaps themselves at all.

As a final verification, it is not possible to disable usage of the snap command whilst still allowing users to install snaps through the software centre?

It isn’t currently possible, no.

It does sound like a useful thing to let a sysadmin do (although maybe in the form of restricting the --dangerous flag, rather than restricting applications). I can’t give a timeline on that getting implemented though.

Alright, thank you for the information! I’ll close the issue at our end, and eagerly wait for it to be implemented.