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>
This commit is contained in:
Liron Levin 2016-05-16 21:12:48 +03:00 committed by liron
parent ee355e017d
commit 4192fe9c06
5 changed files with 29 additions and 14 deletions

View File

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

View File

@ -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 Enable the authorization plugin with a dedicated command line flag in the
`--authorization-plugin=PLUGIN_ID` format. The flag supplies a `PLUGIN_ID` `--authorization-plugin=PLUGIN_ID` format. The flag supplies a `PLUGIN_ID`
value. This value can be the plugins socket or a path to a specification file. value. This value can be the plugins 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 ```bash
$ docker daemon --authorization-plugin=plugin1 --authorization-plugin=plugin2,... $ docker daemon --authorization-plugin=plugin1 --authorization-plugin=plugin2,...

View File

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

View File

@ -14,17 +14,26 @@ type Middleware struct {
} }
// NewMiddleware creates a new Middleware // NewMiddleware creates a new Middleware
// with a slice of plugins. // with a slice of plugins names.
func NewMiddleware(p []Plugin) Middleware { func NewMiddleware(names []string) *Middleware {
return Middleware{ return &Middleware{
plugins: p, 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. // 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 { 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 := "" user := ""
userAuthNMethod := "" userAuthNMethod := ""

View File

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