add ssh-keys, ssh-public-keys, gpg-keys and gpg-public keys interfaces #4100

Merged
merged 15 commits into from Dec 8, 2017
@@ -0,0 +1,59 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin
+
+const gpgKeysSummary = `allows reading gpg user configuration and keys`
+
+const gpgKeysBaseDeclarationSlots = `
+ gpg-keys:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
+`
+
+const gpgKeysConnectedPlugAppArmor = `
+# Description: Can read gpg user configuration as well as public and private
+# keys.
+
+# Allow gpg encrypt, decrypt, list-keys, verify, sign, etc
+/usr/bin/gpg{,1,2,v} ixr,
+/usr/share/gnupg/options.skel r,
+
+owner @{HOME}/.gnupg/{,**} r,
+# gpg sometimes updates the trustdb to decide whether or not to update the
+# trustdb. For now, silence the denial since no other policy references this
+deny @{HOME}/.gnupg/trustdb.gpg w,
+
+# 'wk' is required for gpg encrypt and sign
+owner @{HOME}/.gnupg/random_seed wk,
+`
+
+func init() {
+ registerIface(&commonInterface{
+ name: "gpg-keys",
+ summary: gpgKeysSummary,
+ implicitOnCore: true,
+ implicitOnClassic: true,
+ baseDeclarationSlots: gpgKeysBaseDeclarationSlots,
+ connectedPlugAppArmor: gpgKeysConnectedPlugAppArmor,
+ reservedForOS: true,
+ })
+}
@@ -0,0 +1,102 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
+)
+
+type GpgKeysInterfaceSuite struct {
+ iface interfaces.Interface
+ slotInfo *snap.SlotInfo
+ slot *interfaces.ConnectedSlot
+ plugInfo *snap.PlugInfo
+ plug *interfaces.ConnectedPlug
+}
+
+var _ = Suite(&GpgKeysInterfaceSuite{
+ iface: builtin.MustInterface("gpg-keys"),
+})
+
+const gpgKeysConsumerYaml = `name: consumer
+apps:
+ app:
+ plugs: [gpg-keys]
+ `
+
+const gpgKeysCoreYaml = `name: core
+type: os
+slots:
+ gpg-keys:
+`
+
+func (s *GpgKeysInterfaceSuite) SetUpTest(c *C) {
+ s.plug, s.plugInfo = MockConnectedPlug(c, gpgKeysConsumerYaml, nil, "gpg-keys")
+ s.slot, s.slotInfo = MockConnectedSlot(c, gpgKeysCoreYaml, nil, "gpg-keys")
+}
+
+func (s *GpgKeysInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "gpg-keys")
+}
+
+func (s *GpgKeysInterfaceSuite) TestSanitizeSlot(c *C) {
+ c.Assert(interfaces.BeforePrepareSlot(s.iface, s.slotInfo), IsNil)
+ slotInfo := &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "some-snap"},
+ Name: "gpg-keys",
+ Interface: "gpg-keys",
+ }
+ c.Assert(interfaces.BeforePrepareSlot(s.iface, slotInfo), ErrorMatches,
+ "gpg-keys slots are reserved for the core snap")
+}
+
+func (s *GpgKeysInterfaceSuite) TestSanitizePlug(c *C) {
+ c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
+}
+
+func (s *GpgKeysInterfaceSuite) TestAppArmorSpec(c *C) {
+ spec := &apparmor.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
+ c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `owner @{HOME}/.gnupg/{,**} r,`)
+}
+
+func (s *GpgKeysInterfaceSuite) TestStaticInfo(c *C) {
+ si := interfaces.StaticInfoOf(s.iface)
+ c.Assert(si.ImplicitOnCore, Equals, true)
+ c.Assert(si.ImplicitOnClassic, Equals, true)
+ c.Assert(si.Summary, Equals, `allows reading gpg user configuration and keys`)
+ c.Assert(si.BaseDeclarationSlots, testutil.Contains, "gpg-keys")
+}
+
+func (s *GpgKeysInterfaceSuite) TestAutoConnect(c *C) {
+ // FIXME: fix AutoConnect
+ c.Assert(s.iface.AutoConnect(&interfaces.Plug{PlugInfo: s.plugInfo}, &interfaces.Slot{SlotInfo: s.slotInfo}), Equals, true)
+}
+
+func (s *GpgKeysInterfaceSuite) TestInterfaces(c *C) {
+ c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
+}
@@ -0,0 +1,62 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin
+
+const gpgPublicKeysSummary = `allows reading gpg public keys and non-sensitive configuration`
+
+const gpgPublicKeysBaseDeclarationSlots = `
+ gpg-public-keys:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
+`
+
+const gpgPublicKeysConnectedPlugAppArmor = `
+# Description: Can read gpg public keys and non-sensitive configuration
+
+# Allow gpg encrypt, list-keys, verify, etc
+/usr/bin/gpg{,1,2,v} ixr,
+/usr/share/gnupg/options.skel r,
+
+owner @{HOME}/.gnupg/ r,
+owner @{HOME}/.gnupg/gpg.conf r,
+owner @{HOME}/.gnupg/openpgp-revocs.d/{,*} r,
+owner @{HOME}/.gnupg/pubring.gpg r,
+owner @{HOME}/.gnupg/pubring.kbx r,
+owner @{HOME}/.gnupg/trustedkeys.gpg r,
+
+owner @{HOME}/.gnupg/trustdb.gpg r,
+# gpg sometimes updates the trustdb to decide whether or not to update the
+# trustdb. For now, silence the denial since no other policy references this
+deny @{HOME}/.gnupg/trustdb.gpg w,
+`
+
+func init() {
+ registerIface(&commonInterface{
+ name: "gpg-public-keys",
+ summary: gpgPublicKeysSummary,
+ implicitOnCore: true,
+ implicitOnClassic: true,
+ baseDeclarationSlots: gpgPublicKeysBaseDeclarationSlots,
+ connectedPlugAppArmor: gpgPublicKeysConnectedPlugAppArmor,
+ reservedForOS: true,
+ })
+}
@@ -0,0 +1,102 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/testutil"
+)
+
+type GpgPublicKeysInterfaceSuite struct {
+ iface interfaces.Interface
+ slotInfo *snap.SlotInfo
+ slot *interfaces.ConnectedSlot
+ plugInfo *snap.PlugInfo
+ plug *interfaces.ConnectedPlug
+}
+
+var _ = Suite(&GpgPublicKeysInterfaceSuite{
+ iface: builtin.MustInterface("gpg-public-keys"),
+})
+
+const gpgPublicKeysConsumerYaml = `name: consumer
+apps:
+ app:
+ plugs: [gpg-public-keys]
+ `
+
+const gpgPublicKeysCoreYaml = `name: core
+type: os
+slots:
+ gpg-public-keys:
+`
+
+func (s *GpgPublicKeysInterfaceSuite) SetUpTest(c *C) {
+ s.plug, s.plugInfo = MockConnectedPlug(c, gpgPublicKeysConsumerYaml, nil, "gpg-public-keys")
+ s.slot, s.slotInfo = MockConnectedSlot(c, gpgPublicKeysCoreYaml, nil, "gpg-public-keys")
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "gpg-public-keys")
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestSanitizeSlot(c *C) {
+ c.Assert(interfaces.BeforePrepareSlot(s.iface, s.slotInfo), IsNil)
+ slotInfo := &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "some-snap"},
+ Name: "gpg-public-keys",
+ Interface: "gpg-public-keys",
+ }
+ c.Assert(interfaces.BeforePrepareSlot(s.iface, slotInfo), ErrorMatches,
+ "gpg-public-keys slots are reserved for the core snap")
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestSanitizePlug(c *C) {
+ c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestAppArmorSpec(c *C) {
+ spec := &apparmor.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
+ c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `owner @{HOME}/.gnupg/gpg.conf r,`)
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestStaticInfo(c *C) {
+ si := interfaces.StaticInfoOf(s.iface)
+ c.Assert(si.ImplicitOnCore, Equals, true)
+ c.Assert(si.ImplicitOnClassic, Equals, true)
+ c.Assert(si.Summary, Equals, `allows reading gpg public keys and non-sensitive configuration`)
+ c.Assert(si.BaseDeclarationSlots, testutil.Contains, "gpg-public-keys")
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestAutoConnect(c *C) {
+ // FIXME: fix AutoConnect
+ c.Assert(s.iface.AutoConnect(&interfaces.Plug{PlugInfo: s.plugInfo}, &interfaces.Slot{SlotInfo: s.slotInfo}), Equals, true)
+}
+
+func (s *GpgPublicKeysInterfaceSuite) TestInterfaces(c *C) {
+ c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
+}
@@ -0,0 +1,51 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin
+
+const sshKeysSummary = `allows reading ssh user configuration and keys`
+
+const sshKeysBaseDeclarationSlots = `
+ ssh-keys:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
+`
+
+const sshKeysConnectedPlugAppArmor = `
+# Description: Can read ssh user configuration as well as public and private
+# keys.
+
+/usr/bin/ssh ixr,
+/etc/ssh/ssh_config r,
+owner @{HOME}/.ssh/{,**} r,
+`
+
+func init() {
+ registerIface(&commonInterface{
+ name: "ssh-keys",
+ summary: sshKeysSummary,
+ implicitOnCore: true,
+ implicitOnClassic: true,
+ baseDeclarationSlots: sshKeysBaseDeclarationSlots,
+ connectedPlugAppArmor: sshKeysConnectedPlugAppArmor,
+ reservedForOS: true,
+ })
+}
Oops, something went wrong.