Browse code

Check authz plugins are valid on daemon startup, add integration tests

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>

Riyaz Faizullabhoy authored on 2016/11/01 05:14:00
Showing 2 changed files
... ...
@@ -35,6 +35,7 @@ import (
35 35
 	"github.com/docker/docker/pkg/jsonlog"
36 36
 	"github.com/docker/docker/pkg/listeners"
37 37
 	"github.com/docker/docker/pkg/pidfile"
38
+	"github.com/docker/docker/pkg/plugingetter"
38 39
 	"github.com/docker/docker/pkg/signal"
39 40
 	"github.com/docker/docker/pkg/system"
40 41
 	"github.com/docker/docker/registry"
... ...
@@ -287,7 +288,9 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
287 287
 	cli.d = d
288 288
 
289 289
 	// initMiddlewares needs cli.d to be populated. Dont change this init order.
290
-	cli.initMiddlewares(api, serverConfig)
290
+	if err := cli.initMiddlewares(api, serverConfig); err != nil {
291
+		logrus.Fatalf("Error creating middlewares: %v", err)
292
+	}
291 293
 	d.SetCluster(c)
292 294
 	initRouter(api, d, c)
293 295
 
... ...
@@ -318,7 +321,11 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
318 318
 func (cli *DaemonCli) reloadConfig() {
319 319
 	reload := func(config *daemon.Config) {
320 320
 
321
-		// Reload the authorization plugin
321
+		// Revalidate and reload the authorization plugins
322
+		if err := validateAuthzPlugins(config.AuthorizationPlugins, cli.d.PluginStore); err != nil {
323
+			logrus.Fatalf("Error validating authorization plugin: %v", err)
324
+			return
325
+		}
322 326
 		cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins)
323 327
 
324 328
 		if err := cli.d.Reload(config); err != nil {
... ...
@@ -459,7 +466,7 @@ func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
459 459
 	s.InitRouter(utils.IsDebugEnabled(), routers...)
460 460
 }
461 461
 
462
-func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) {
462
+func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) error {
463 463
 	v := cfg.Version
464 464
 
465 465
 	exp := middleware.NewExperimentalMiddleware(cli.d.HasExperimental())
... ...
@@ -476,6 +483,21 @@ func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config
476 476
 	u := middleware.NewUserAgentMiddleware(v)
477 477
 	s.UseMiddleware(u)
478 478
 
479
+	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, cli.d.PluginStore); err != nil {
480
+		return fmt.Errorf("Error validating authorization plugin: %v", err)
481
+	}
479 482
 	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, cli.d.PluginStore)
480 483
 	s.UseMiddleware(cli.authzMiddleware)
484
+	return nil
485
+}
486
+
487
+// validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
488
+// plugins present on the host and available to the daemon
489
+func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
490
+	for _, reqPlugin := range requestedPlugins {
491
+		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.LOOKUP); err != nil {
492
+			return err
493
+		}
494
+	}
495
+	return nil
481 496
 }
482 497
new file mode 100644
... ...
@@ -0,0 +1,129 @@
0
+// +build !windows
1
+
2
+package main
3
+
4
+import (
5
+	"fmt"
6
+	"strings"
7
+
8
+	"github.com/docker/docker/pkg/integration/checker"
9
+	"github.com/go-check/check"
10
+)
11
+
12
+var (
13
+	authzPluginName            = "riyaz/authz-no-volume-plugin"
14
+	authzPluginTag             = "latest"
15
+	authzPluginNameWithTag     = authzPluginName + ":" + authzPluginTag
16
+	authzPluginBadManifestName = "riyaz/authz-plugin-bad-manifest"
17
+	nonexistentAuthzPluginName = "riyaz/nonexistent-authz-plugin"
18
+)
19
+
20
+func init() {
21
+	check.Suite(&DockerAuthzV2Suite{
22
+		ds: &DockerSuite{},
23
+	})
24
+}
25
+
26
+type DockerAuthzV2Suite struct {
27
+	ds *DockerSuite
28
+	d  *Daemon
29
+}
30
+
31
+func (s *DockerAuthzV2Suite) SetUpTest(c *check.C) {
32
+	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
33
+	s.d = NewDaemon(c)
34
+	c.Assert(s.d.Start(), check.IsNil)
35
+}
36
+
37
+func (s *DockerAuthzV2Suite) TearDownTest(c *check.C) {
38
+	s.d.Stop()
39
+	s.ds.TearDownTest(c)
40
+}
41
+
42
+func (s *DockerAuthzV2Suite) TestAuthZPluginAllowNonVolumeRequest(c *check.C) {
43
+	// Install authz plugin
44
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginNameWithTag)
45
+	c.Assert(err, checker.IsNil)
46
+	// start the daemon with the plugin and load busybox, --net=none build fails otherwise
47
+	// because it needs to pull busybox
48
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginNameWithTag), check.IsNil)
49
+	c.Assert(s.d.LoadBusybox(), check.IsNil)
50
+
51
+	// defer disabling the plugin
52
+	defer func() {
53
+		c.Assert(s.d.Restart(), check.IsNil)
54
+		_, err = s.d.Cmd("plugin", "disable", authzPluginNameWithTag)
55
+		c.Assert(err, checker.IsNil)
56
+		_, err = s.d.Cmd("plugin", "rm", authzPluginNameWithTag)
57
+		c.Assert(err, checker.IsNil)
58
+	}()
59
+
60
+	// Ensure docker run command and accompanying docker ps are successful
61
+	out, err := s.d.Cmd("run", "-d", "busybox", "top")
62
+	c.Assert(err, check.IsNil)
63
+
64
+	id := strings.TrimSpace(out)
65
+
66
+	out, err = s.d.Cmd("ps")
67
+	c.Assert(err, check.IsNil)
68
+	c.Assert(assertContainerList(out, []string{id}), check.Equals, true)
69
+}
70
+
71
+func (s *DockerAuthzV2Suite) TestAuthZPluginRejectVolumeRequests(c *check.C) {
72
+	// Install authz plugin
73
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginNameWithTag)
74
+	c.Assert(err, checker.IsNil)
75
+
76
+	// restart the daemon with the plugin
77
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginNameWithTag), check.IsNil)
78
+
79
+	// defer disabling the plugin
80
+	defer func() {
81
+		c.Assert(s.d.Restart(), check.IsNil)
82
+		_, err = s.d.Cmd("plugin", "disable", authzPluginNameWithTag)
83
+		c.Assert(err, checker.IsNil)
84
+		_, err = s.d.Cmd("plugin", "rm", authzPluginNameWithTag)
85
+		c.Assert(err, checker.IsNil)
86
+	}()
87
+
88
+	out, err := s.d.Cmd("volume", "create")
89
+	c.Assert(err, check.NotNil)
90
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
91
+
92
+	out, err = s.d.Cmd("volume", "ls")
93
+	c.Assert(err, check.NotNil)
94
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
95
+
96
+	// The plugin will block the command before it can determine the volume does not exist
97
+	out, err = s.d.Cmd("volume", "rm", "test")
98
+	c.Assert(err, check.NotNil)
99
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
100
+
101
+	out, err = s.d.Cmd("volume", "inspect", "test")
102
+	c.Assert(err, check.NotNil)
103
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
104
+
105
+	out, err = s.d.Cmd("volume", "prune", "-f")
106
+	c.Assert(err, check.NotNil)
107
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
108
+}
109
+
110
+func (s *DockerAuthzV2Suite) TestAuthZPluginBadManifestFailsDaemonStart(c *check.C) {
111
+	// Install authz plugin with bad manifest
112
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginBadManifestName)
113
+	c.Assert(err, checker.IsNil)
114
+
115
+	// start the daemon with the plugin, it will error
116
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginBadManifestName), check.NotNil)
117
+
118
+	// restarting the daemon without requiring the plugin will succeed
119
+	c.Assert(s.d.Restart(), check.IsNil)
120
+}
121
+
122
+func (s *DockerAuthzV2Suite) TestNonexistentAuthZPluginFailsDaemonStart(c *check.C) {
123
+	// start the daemon with a non-existent authz plugin, it will error
124
+	c.Assert(s.d.Restart("--authorization-plugin="+nonexistentAuthzPluginName), check.NotNil)
125
+
126
+	// restarting the daemon without requiring the plugin will succeed
127
+	c.Assert(s.d.Restart(), check.IsNil)
128
+}