소스 검색

Enable to dynamically reload authorization plugins via daemon.config

Following #22729, enable to dynamically reload/remove the daemon
authorization plugins (via standard reloading mechanism).
https://docs.docker.com/engine/reference/commandline/daemon/#daemon-
configuration-file

Daemon must store a reference to the authorization middleware to refresh
the plugin on configuration changes.

Signed-off-by: Liron Levin <liron@twistlock.com>
Liron Levin 9 년 전
부모
커밋
4192fe9c06
5개의 변경된 파일29개의 추가작업 그리고 14개의 파일을 삭제
  1. 10 7
      cmd/dockerd/daemon.go
  2. 2 0
      docs/extend/plugins_authorization.md
  3. 1 0
      docs/reference/commandline/dockerd.md
  4. 14 5
      pkg/authorization/middleware.go
  5. 2 2
      pkg/authorization/plugin.go

+ 10 - 7
cmd/dockerd/daemon.go

@@ -55,8 +55,9 @@ type DaemonCli struct {
 	commonFlags *cliflags.CommonFlags
 	configFile  *string
 
-	api *apiserver.Server
-	d   *daemon.Daemon
+	api             *apiserver.Server
+	d               *daemon.Daemon
+	authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins
 }
 
 func presentInHelp(usage string) string { return usage }
@@ -317,10 +318,15 @@ func (cli *DaemonCli) start() (err error) {
 
 func (cli *DaemonCli) reloadConfig() {
 	reload := func(config *daemon.Config) {
+
+		// Reload the authorization plugin
+		cli.authzMiddleware.SetPlugins(config.AuthorizationPlugins)
+
 		if err := cli.d.Reload(config); err != nil {
 			logrus.Errorf("Error reconfiguring the daemon: %v", err)
 			return
 		}
+
 		if config.IsValueSet("debug") {
 			debugEnabled := utils.IsDebugEnabled()
 			switch {
@@ -438,9 +444,6 @@ func (cli *DaemonCli) initMiddlewares(s *apiserver.Server, cfg *apiserver.Config
 	u := middleware.NewUserAgentMiddleware(v)
 	s.UseMiddleware(u)
 
-	if len(cli.Config.AuthorizationPlugins) > 0 {
-		authZPlugins := authorization.NewPlugins(cli.Config.AuthorizationPlugins)
-		handleAuthorization := authorization.NewMiddleware(authZPlugins)
-		s.UseMiddleware(handleAuthorization)
-	}
+	cli.authzMiddleware = authorization.NewMiddleware(cli.Config.AuthorizationPlugins)
+	s.UseMiddleware(cli.authzMiddleware)
 }

+ 2 - 0
docs/extend/plugins_authorization.md

@@ -104,6 +104,8 @@ support the Docker client interactions detailed in this section.
 Enable the authorization plugin with a dedicated command line flag in the
 `--authorization-plugin=PLUGIN_ID` format. The flag supplies a `PLUGIN_ID`
 value. This value can be the plugin’s socket or a path to a specification file.
+Authorization plugins can be loaded without restarting the daemon. Refer
+to the [`dockerd` documentation](../reference/commandline/dockerd.md#configuration-reloading) for more information.
 
 ```bash
 $ docker daemon --authorization-plugin=plugin1 --authorization-plugin=plugin2,...

+ 1 - 0
docs/reference/commandline/dockerd.md

@@ -1152,6 +1152,7 @@ The list of currently supported options that can be reconfigured is this:
   the runtime shipped with the official docker packages.
 - `runtimes`: it updates the list of available OCI runtimes that can
   be used to run containers
+- `authorization-plugin`: specifies the authorization plugins to use.
 
 Updating and reloading the cluster configurations such as `--cluster-store`,
 `--cluster-advertise` and `--cluster-store-opts` will take effect only if

+ 14 - 5
pkg/authorization/middleware.go

@@ -14,17 +14,26 @@ type Middleware struct {
 }
 
 // NewMiddleware creates a new Middleware
-// with a slice of plugins.
-func NewMiddleware(p []Plugin) Middleware {
-	return Middleware{
-		plugins: p,
+// with a slice of plugins names.
+func NewMiddleware(names []string) *Middleware {
+	return &Middleware{
+		plugins: newPlugins(names),
 	}
 }
 
+// SetPlugins sets the plugin used for authorization
+func (m *Middleware) SetPlugins(names []string) {
+	m.plugins = newPlugins(names)
+}
+
 // WrapHandler returns a new handler function wrapping the previous one in the request chain.
-func (m Middleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
+func (m *Middleware) WrapHandler(handler func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error) func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 	return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 
+		if len(m.plugins) == 0 {
+			return handler(ctx, w, r, vars)
+		}
+
 		user := ""
 		userAuthNMethod := ""
 

+ 2 - 2
pkg/authorization/plugin.go

@@ -19,8 +19,8 @@ type Plugin interface {
 	AuthZResponse(*Request) (*Response, error)
 }
 
-// NewPlugins constructs and initializes the authorization plugins based on plugin names
-func NewPlugins(names []string) []Plugin {
+// newPlugins constructs and initializes the authorization plugins based on plugin names
+func newPlugins(names []string) []Plugin {
 	plugins := []Plugin{}
 	pluginsMap := make(map[string]struct{})
 	for _, name := range names {