Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
| ... | ... |
@@ -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 |
+} |