Browse Source

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

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
Riyaz Faizullabhoy 8 years ago
parent
commit
2b045027ce
2 changed files with 154 additions and 3 deletions
  1. 25 3
      cmd/dockerd/daemon.go
  2. 129 0
      integration-cli/docker_cli_authz_plugin_v2_test.go

+ 25 - 3
cmd/dockerd/daemon.go

@@ -35,6 +35,7 @@ import (
 	"github.com/docker/docker/pkg/jsonlog"
 	"github.com/docker/docker/pkg/jsonlog"
 	"github.com/docker/docker/pkg/listeners"
 	"github.com/docker/docker/pkg/listeners"
 	"github.com/docker/docker/pkg/pidfile"
 	"github.com/docker/docker/pkg/pidfile"
+	"github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/registry"
@@ -287,7 +288,9 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
 	cli.d = d
 	cli.d = d
 
 
 	// initMiddlewares needs cli.d to be populated. Dont change this init order.
 	// initMiddlewares needs cli.d to be populated. Dont change this init order.
-	cli.initMiddlewares(api, serverConfig)
+	if err := cli.initMiddlewares(api, serverConfig); err != nil {
+		logrus.Fatalf("Error creating middlewares: %v", err)
+	}
 	d.SetCluster(c)
 	d.SetCluster(c)
 	initRouter(api, d, c)
 	initRouter(api, d, c)
 
 
@@ -318,7 +321,11 @@ func (cli *DaemonCli) start(opts daemonOptions) (err error) {
 func (cli *DaemonCli) reloadConfig() {
 func (cli *DaemonCli) reloadConfig() {
 	reload := func(config *daemon.Config) {
 	reload := func(config *daemon.Config) {
 
 
-		// Reload the authorization plugin
+		// Revalidate and reload the authorization plugins
+		if err := validateAuthzPlugins(config.AuthorizationPlugins, cli.d.PluginStore); err != nil {
+			logrus.Fatalf("Error validating authorization plugin: %v", err)
+			return
+		}
 		cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins)
 		cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins)
 
 
 		if err := cli.d.Reload(config); err != nil {
 		if err := cli.d.Reload(config); err != nil {
@@ -459,7 +466,7 @@ func initRouter(s *apiserver.Server, d *daemon.Daemon, c *cluster.Cluster) {
 	s.InitRouter(utils.IsDebugEnabled(), routers...)
 	s.InitRouter(utils.IsDebugEnabled(), routers...)
 }
 }
 
 
-func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) {
+func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config) error {
 	v := cfg.Version
 	v := cfg.Version
 
 
 	exp := middleware.NewExperimentalMiddleware(cli.d.HasExperimental())
 	exp := middleware.NewExperimentalMiddleware(cli.d.HasExperimental())
@@ -476,6 +483,21 @@ func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config
 	u := middleware.NewUserAgentMiddleware(v)
 	u := middleware.NewUserAgentMiddleware(v)
 	s.UseMiddleware(u)
 	s.UseMiddleware(u)
 
 
+	if err := validateAuthzPlugins(cli.Config.AuthorizationPlugins, cli.d.PluginStore); err != nil {
+		return fmt.Errorf("Error validating authorization plugin: %v", err)
+	}
 	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, cli.d.PluginStore)
 	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins, cli.d.PluginStore)
 	s.UseMiddleware(cli.authzMiddleware)
 	s.UseMiddleware(cli.authzMiddleware)
+	return nil
+}
+
+// validates that the plugins requested with the --authorization-plugin flag are valid AuthzDriver
+// plugins present on the host and available to the daemon
+func validateAuthzPlugins(requestedPlugins []string, pg plugingetter.PluginGetter) error {
+	for _, reqPlugin := range requestedPlugins {
+		if _, err := pg.Get(reqPlugin, authorization.AuthZApiImplements, plugingetter.LOOKUP); err != nil {
+			return err
+		}
+	}
+	return nil
 }
 }

+ 129 - 0
integration-cli/docker_cli_authz_plugin_v2_test.go

@@ -0,0 +1,129 @@
+// +build !windows
+
+package main
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/docker/docker/pkg/integration/checker"
+	"github.com/go-check/check"
+)
+
+var (
+	authzPluginName            = "riyaz/authz-no-volume-plugin"
+	authzPluginTag             = "latest"
+	authzPluginNameWithTag     = authzPluginName + ":" + authzPluginTag
+	authzPluginBadManifestName = "riyaz/authz-plugin-bad-manifest"
+	nonexistentAuthzPluginName = "riyaz/nonexistent-authz-plugin"
+)
+
+func init() {
+	check.Suite(&DockerAuthzV2Suite{
+		ds: &DockerSuite{},
+	})
+}
+
+type DockerAuthzV2Suite struct {
+	ds *DockerSuite
+	d  *Daemon
+}
+
+func (s *DockerAuthzV2Suite) SetUpTest(c *check.C) {
+	testRequires(c, DaemonIsLinux, ExperimentalDaemon, Network)
+	s.d = NewDaemon(c)
+	c.Assert(s.d.Start(), check.IsNil)
+}
+
+func (s *DockerAuthzV2Suite) TearDownTest(c *check.C) {
+	s.d.Stop()
+	s.ds.TearDownTest(c)
+}
+
+func (s *DockerAuthzV2Suite) TestAuthZPluginAllowNonVolumeRequest(c *check.C) {
+	// Install authz plugin
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginNameWithTag)
+	c.Assert(err, checker.IsNil)
+	// start the daemon with the plugin and load busybox, --net=none build fails otherwise
+	// because it needs to pull busybox
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginNameWithTag), check.IsNil)
+	c.Assert(s.d.LoadBusybox(), check.IsNil)
+
+	// defer disabling the plugin
+	defer func() {
+		c.Assert(s.d.Restart(), check.IsNil)
+		_, err = s.d.Cmd("plugin", "disable", authzPluginNameWithTag)
+		c.Assert(err, checker.IsNil)
+		_, err = s.d.Cmd("plugin", "rm", authzPluginNameWithTag)
+		c.Assert(err, checker.IsNil)
+	}()
+
+	// Ensure docker run command and accompanying docker ps are successful
+	out, err := s.d.Cmd("run", "-d", "busybox", "top")
+	c.Assert(err, check.IsNil)
+
+	id := strings.TrimSpace(out)
+
+	out, err = s.d.Cmd("ps")
+	c.Assert(err, check.IsNil)
+	c.Assert(assertContainerList(out, []string{id}), check.Equals, true)
+}
+
+func (s *DockerAuthzV2Suite) TestAuthZPluginRejectVolumeRequests(c *check.C) {
+	// Install authz plugin
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginNameWithTag)
+	c.Assert(err, checker.IsNil)
+
+	// restart the daemon with the plugin
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginNameWithTag), check.IsNil)
+
+	// defer disabling the plugin
+	defer func() {
+		c.Assert(s.d.Restart(), check.IsNil)
+		_, err = s.d.Cmd("plugin", "disable", authzPluginNameWithTag)
+		c.Assert(err, checker.IsNil)
+		_, err = s.d.Cmd("plugin", "rm", authzPluginNameWithTag)
+		c.Assert(err, checker.IsNil)
+	}()
+
+	out, err := s.d.Cmd("volume", "create")
+	c.Assert(err, check.NotNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
+
+	out, err = s.d.Cmd("volume", "ls")
+	c.Assert(err, check.NotNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
+
+	// The plugin will block the command before it can determine the volume does not exist
+	out, err = s.d.Cmd("volume", "rm", "test")
+	c.Assert(err, check.NotNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
+
+	out, err = s.d.Cmd("volume", "inspect", "test")
+	c.Assert(err, check.NotNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
+
+	out, err = s.d.Cmd("volume", "prune", "-f")
+	c.Assert(err, check.NotNil)
+	c.Assert(out, checker.Contains, fmt.Sprintf("Error response from daemon: plugin %s failed with error:", authzPluginNameWithTag))
+}
+
+func (s *DockerAuthzV2Suite) TestAuthZPluginBadManifestFailsDaemonStart(c *check.C) {
+	// Install authz plugin with bad manifest
+	_, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", authzPluginBadManifestName)
+	c.Assert(err, checker.IsNil)
+
+	// start the daemon with the plugin, it will error
+	c.Assert(s.d.Restart("--authorization-plugin="+authzPluginBadManifestName), check.NotNil)
+
+	// restarting the daemon without requiring the plugin will succeed
+	c.Assert(s.d.Restart(), check.IsNil)
+}
+
+func (s *DockerAuthzV2Suite) TestNonexistentAuthZPluginFailsDaemonStart(c *check.C) {
+	// start the daemon with a non-existent authz plugin, it will error
+	c.Assert(s.d.Restart("--authorization-plugin="+nonexistentAuthzPluginName), check.NotNil)
+
+	// restarting the daemon without requiring the plugin will succeed
+	c.Assert(s.d.Restart(), check.IsNil)
+}