Plugin Signing

Security

By default, the Snap daemon (snapd) has plugin signing verification enabled. To disable it or turn it to warning, the flag --plugin-trust, -t can be set to 0 or 2 respectively.

How it works

How it works
Private/public keys and keyrings are generated by GPG. The plugin is signed with the private key and the public key needs to be added to the user's keyring. The signing is an armored detached signature in the form of a .asc file.

The Snap daemon uses the Golang OpenPGP library's CheckArmoredDetachedSignature function to validate the signature using the keyring, plugin, and signature file before loading the plugin. It checks the issuer key ID, hash, and signature type.

openpgp.CheckArmoredDetachedSignature(keyring, signed, signature)

Usage

snapd
  --plugin-trust, -t '1'        0-2 (Disabled, Enabled, Warning) [$SNAP_TRUST_LEVEL]
  --keyring-paths, -k           Keyring files for signing verification separated by colons [$SNAP_KEYRING_FILES]

One keyring (-t flag is not needed for signing enabled)

$ $SNAP_PATH/bin/snapd -k <keyringFileOrDirectory>
$ $SNAP_PATH/bin/snapd -t <trustLevel> -k <keyringFileOrDirectory>
$ $SNAP_PATH/bin/snapd -t <trustLevel> -k someDirectory/someFile.gpg
$ $SNAP_PATH/bin/snapd -t <trustLevel> -k someDirectory/

Multiple keyrings (may need full path, not ~)

$ $SNAP_PATH/bin/snapd -t <trustLevel> -k <keyringFile1>:<keyringFile2>

By default, plugin-trust is 1 (enabled), so the flag is only needed for 0 (disabled) and 2 (warning) You can make an export to avoid needing the -k flag:

$ export SNAP_KEYRING_FILE=<keyringFile>
$ $SNAP_PATH/bin/snapd -t <trustLevel>

Loading a single plugin using $SNAP_PATH/bin/snapctl

$ $SNAP_PATH/bin/snapctl plugin load <pluginFile> -a <pluginFile>.asc

Examples

No keyring, trust enabled/warning
$ $SNAP_PATH/bin/snapd -l 1

INFO[0000] setting plugin trust level to: enabled
FATA[0000] need keyring file when trust is on (--keyring-file or -k)  _module=snapd block=main
Invalid Keyring

Keyring doesn't exist

$ $SNAP_PATH/bin/snapd -l 1 -k /Users/tiffany/.gnupg/pubring.gpg:/Users/tiffany/.gnupg/stuff.gpg
INFO[0000] adding keyring file /Users/tiffany/.gnupg/pubring.gpg
FATA[0000] bad keyring file                              _module=snapd block=main error=stat /Users/tiffany/.gnupg/stuff.gpg: no such file or directory keyringPath=/Users/tiffany/.gnupg/stuff.gpg
Correct Keyring, trust enabled

Valid signature

$ $SNAP_PATH/bin/snapd -l 1 -k /Users/tiffany/.gnupg/

INFO[0000] setting plugin trust level to: enabled
INFO[0000] Adding keyrings from: /Users/tiffany/.gnupg
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/pubkeys.gpg
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/pubkeys2.gpg
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/pubring.gpg
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/snap.pubring
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/secring.gpg
INFO[0000] adding keyring file: /Users/tiffany/.gnupg/trustdb.gpg
$ $SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock1 -a build/plugin/snap-plugin-collector-mock1.asc
Plugin loaded
Name: mock
Version: 1
Type: collector
Signed: true
Loaded Time: Thu, 12 Nov 2015 13:53:58 PST
INFO[0036] API request                                   _module=_mgmt-rest index=3 method=POST url=/v1/plugins
DEBU[0037] wrote 7332032 to /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/485061199/snap-plugin-collector-mock1
DEBU[0037] wrote 473 to /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/784063842/snap-plugin-collector-mock1.asc
INFO[0037] Loading plugin: /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/485061199/snap-plugin-collector-mock1  _module=_mgmt-rest
Signature made Thu, 12 Nov 2015 13:53:58 PST using RSA key ID 43F744A0
Good signature from Tiffany Jernigan (Main signing key) <my.email@intel.com>

No signature

$ $SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock2
Error loading plugin:
Signature file (.asc) not found:
open : no such file or directory
DEBU[0033] wrote 7327840 to /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/180549107/snap-plugin-collector-mock2
INFO[0033] Loading plugin: /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/180549107/snap-plugin-collector-mock2  _module=_mgmt-rest
ERRO[0033] Signature file (.asc) not found:
open : no such file or directory  _module=_mgmt-rest
DEBU[0033] Removing file (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/180549107/snap-plugin-collector-mock2) after failure to load plugin (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/180549107/snap-plugin-collector-mock2)  _module=_mgmt-rest

Invalid signature

$SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock2 -a build/plugin/snap-plugin-collector-mock1.asc
Error loading plugin:
Error checking signature
openpgp: invalid signature: hash tag doesn't match
DEBU[0003] wrote 7327840 to /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/719702627/snap-plugin-collector-mock2
DEBU[0003] wrote 473 to /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/700509798/snap-plugin-collector-mock1.asc
INFO[0003] Loading plugin: /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/719702627/snap-plugin-collector-mock2  _module=_mgmt-rest
ERRO[0003] Error checking signature
openpgp: invalid signature: hash tag doesn't match  _module=_mgmt-rest
DEBU[0003] Removing file (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/719702627/snap-plugin-collector-mock2) after failure to load plugin (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/719702627/snap-plugin-collector-mock2)  _module=_mgmt-rest
DEBU[0003] Removing file (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/700509798/snap-plugin-collector-mock1.asc) after failure to load plugin (/var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/719702627/snap-plugin-collector-mock2)  _module=_mgmt-rest

Wrong keyring

$ $SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock1 -a build/plugin/snap-plugin-collector-mock1.asc
Error loading plugin:
Error checking signature
openpgp: signature made by unknown entity
INFO[0002] Loading plugin: /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/057449871/snap-plugin-collector-mock1  _module=_mgmt-rest

ERRO[0002] Error checking signature
openpgp: signature made by unknown entity  _module=_mgmt-rest
Correct keyring, trust warning
$ $SNAP_PATH/bin/snapd -l 1 -k ~/.gnupg/pubring.gpg -t 2
INFO[0000] setting plugin trust level to: warning
INFO[0000] adding keyring file /Users/tiffany/.gnupg/pubring.gpg
$ $SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock1 -a build/plugin/snap-plugin-collector-mock1.asc

Plugin loaded
Name: mock
Version: 1
Type: collector
Signed: true
Loaded Time: Thu, 12 Nov 2015 14:08:32 PST

$ $SNAP_PATH/bin/snapctl plugin load build/plugin/snap-plugin-collector-mock2

Plugin loaded
Name: mock
Version: 2
Type: collector
Signed: false
Loaded Time: Thu, 12 Nov 2015 14:08:49 PST
INFO[0338] Loading plugin: /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/276797457/snap-plugin-collector-mock1  _module=_mgmt-rest
Signature made Thu, 12 Nov 2015 14:08:32 PST using RSA key ID 43F744A0
Good signature from Tiffany Jernigan (ACI signing key) <my.email@intel.com>
WARN[0355] Loading unsigned plugin /var/folders/kh/v2qy5_zx3zlgbc0gll7fzjnm0000gp/T/205904491/snap-plugin-collector-mock2  _block=load _module=control

Creating Signing Files and Validating Signature

Creating a key for plugin signing

The following is leveraged from the CoreOS RKT Signing and Verification Guide

Create a file named gpg-batch with the following

%echo Generating a default key
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: Tiffany Jernigan
Name-Comment: Plugin signing key
Name-Email: my.email@intel.com
Expire-Date: 0
Passphrase: snap
%pubring snap.pubring
%secring snap.secring
%commit
%echo done
Generate the key using batch mode
$ gpg --batch --gen-key gpg-batch
List the keys
$ gpg --no-default-keyring --secret-keyring ./snap.secring --keyring ./snap.pubring \
--list-keys
./snap.pubring
-----------
pub   2048R/FE9B5E28 2015-11-04
uid                  Tiffany Jernigan (Plugin signing key) <my.email@intel.com>
sub   2048R/0BC6D4D7 2015-11-04

Since we know exactly where this key came from let's trust it:

$ gpg --no-default-keyring --secret-keyring ./snap.secring --keyring ./snap.pubring \
--edit-key FE9B5E28 trust
gpg (GnuPG) 1.4.19; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Secret key is available.

pub  2048R/FE9B5E28  created: 2015-11-04  expires: never       usage: SCEA
                     trust: unknown       validity: unknown
sub  2048R/0BC6D4D7  created: 2015-11-04  expires: never       usage: SEA
[ unknown] (1). Tiffany Jernigan (Plugin signing key) <my.email@intel.com>

pub  2048R/FE9B5E28  created: 2015-11-04  expires: never       usage: SCEA
                     trust: unknown       validity: unknown
sub  2048R/0BC6D4D7  created: 2015-11-04  expires: never       usage: SEA
[ unknown] (1). Tiffany Jernigan (Plugin signing key) <my.email@intel.com>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

pub  2048R/FE9B5E28  created: 2015-11-04  expires: never       usage: SCEA
                     trust: ultimate      validity: unknown
sub  2048R/0BC6D4D7  created: 2015-11-04  expires: never       usage: SEA
[ unknown] (1). Tiffany Jernigan (Plugin signing key) <my.email@intel.com>
Please note that the shown key validity is not necessarily correct
unless you restart the program.

gpg> quit
Export the public key
$ gpg --no-default-keyring --armor \
--secret-keyring ./snap.secring --keyring ./snap.pubring \
--export my.email@intel.com > pubkeys.gpg

Signing the plugin/plugin package using generated keyrings

Sign file
$ gpg --no-default-keyring --armor \
--secret-keyring ./snap.secring --keyring ./snap.pubring \
--output <pluginFile>.asc \
--detach-sig <pluginFile>
Verify the image using gpg
$ gpg --no-default-keyring \
--secret-keyring ./snap.secring --keyring ./snap.pubring \
--verify <pluginFile>.asc <pluginFile>
gpg: Signature made Wed Nov  4 14:24:18 2015 PST using RSA key ID 0BC6D4D7
gpg: Good signature from "Tiffany Jernigan (Plugin signing key) <my.email@intel.com>

Signing file using key in your default keyring

If you already have a key, you can use that. Otherwise you can create a key and directly add to your keyring
Create a file named gpg-batch with the following

%echo Generating a default key
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: Tiffany Jernigan
Name-Comment: Main signing key
Name-Email: my.email@intel.com
Expire-Date: 0
Passphrase: snap
%commit
%echo done
Generate the key using batch mode
$ gpg --batch --gen-key gpg-batch
$ gpg --list-keys
/Users/tiffany/.gnupg/pubring.gpg
----------------------------------
pub   2048R/43F744A0 2015-08-22
uid                  Tiffany Jernigan (Main signing key) <my.email@intel.com>
sub   2048R/2ED40FB2 2015-08-22
Sign file
$ gpg --armor --output <pluginFile>.asc --detach-sig <pluginFile>
Verify the image using gpg
$ gpg --verify <pluginFile>.asc <pluginFile>

Keyring

Adding to your keyring

If you only have one key, you can use the snap.pubring you just made as your <keyringFile>. For multiple you can just separate them by a colon (e.g. : ) . If you want to add future pubkeys.gpg files to an existing keyring you can do:

$ gpg --no-default-keyring --keyring <keyringFile> --import pubkeys.gpg

If you just want to add to your gnupg default keyring (e.g. ~/.gnupg/pubring.gpg) you can just do

$ gpg --import pubkeys.gpg

Validating a public key from someone else

From the GPG Handbook:
Once a key is imported it should be validated. GnuPG uses a powerful and flexible trust model that does not require you to personally validate each key you import. Some keys may need to be personally validated, however. A key is validated by verifying the key's fingerprint and then signing the key to certify it as a valid key. A key's fingerprint can be quickly viewed with the --fingerprint command-line option, but in order to certify the key you must edit it.

Add --no-default-keyring --keyring to all commands below if you are editing a specific keyring that isn't your gnupg default one.

$ gpg --list-keys
/Users/tiffany/.gnupg/pubring.gpg
----------------------------------
pub   2048R/43F744A0 2015-08-22
uid                  Tiffany Jernigan (Main signing key) <my.email@intel.com>
sub   2048R/2ED40FB2 2015-08-22

pub   2048R/FE9B5E28 2015-11-04
uid                  Tiffany Jernigan (Plugin signing key) <my.email@intel.com>
sub   2048R/0BC6D4D7 2015-11-04
$ gpg --edit-key FE9B5E28
gpg (GnuPG) 1.4.19; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


pub  2048R/FE9B5E28  created: 2015-11-04  expires: never       usage: SCEA
                     trust: unknown       validity: ultimate
sub  2048R/0BC6D4D7  created: 2015-11-04  expires: never       usage: SEA
[ultimate] (1). Tiffany Jernigan (Plugin signing key) <my.email@intel.com>

gpg> sign

pub  2048R/FE9B5E28  created: 2015-11-04  expires: never       usage: SCEA
                     trust: unknown       validity: ultimate
 Primary key fingerprint: 60BF B0AD 3CDB 5188 CE27  EBD5 F7D3 7AF8 FE9B 5E28

     Tiffany Jernigan (Plugin signing key) <my.email@intel.com>

Are you sure that you want to sign this key with your
key "Tiffany Jernigan (Main signing key) <my.email@intel.com>" (43F744A0)

Really sign? (y/N) y

You need a passphrase to unlock the secret key for
user: "Tiffany Jernigan (Main signing key) <my.email@intel.com>"
2048-bit RSA key, ID 43F744A0, created 2015-08-22

gpg> check
uid  Tiffany Jernigan (Plugin signing key) <my.email@intel.com>
sig!3        FE9B5E28 2015-11-04  [self-signature]
sig!         43F744A0 2015-11-05  Tiffany Jernigan (Main signing key) <my.email@intel.com>

gpg> quit
Save changes? (y/N) y