Skip to content

authz plugins: dynamically append authz plugins to middleware chain#33658

Closed
dsheets wants to merge 13 commits intomoby:masterfrom
dsheets:authz-dynamic-enable
Closed

authz plugins: dynamically append authz plugins to middleware chain#33658
dsheets wants to merge 13 commits intomoby:masterfrom
dsheets:authz-dynamic-enable

Conversation

@dsheets
Copy link
Copy Markdown
Contributor

@dsheets dsheets commented Jun 13, 2017

docker plugin install and docker plugin enable for authz plugins "enable" the plugin as listed in docker plugin ls but the plugin is non-functional as it hasn't been added to the authz middleware chain. This is confusing, unintuitive, and does not match the behavior of other plugins. Turning these operations into an error and forcing the plugin into 'disabled' state is not compatible with other design decisions like refusing to start the daemon if a plugin specified in CLI or JSON configuration is 'disabled' (see #33640 where this error condition was distinguished from a missing plugin).

Either:

  1. A new plugin state besides 'disabled' and 'enabled' should be introduced like 'available' or 'partial' which becomes complicated for plugins with multiple plugin capabilities (e.g. a volume and authz plugin which can currently enter this strange half-way loaded state for its different capabilities) or...

  2. The design decision to refuse to start the daemon with explicitly 'disabled' plugins needs to be revisited or...

  3. authz plugins can be enabled and made fully functional dynamically (the simplest option and what this PR does)

This has been discussed previously in at least #22729, #32489, #31836, and #31930 (comment).

The current behavior simply seems broken so I think it would be best for those strongly against a functional docker plugin enable for authz plugins to make their case and suggest an alternative (more states besides 'enabled' and 'disabled'?).

/cc @anusha-ragunathan @riyazdf @jessfraz @liron-l @rogaha @cpuguy83

- What I did

Previously, authz plugins could be installed or enabled using docker plugin commands and they would show as enabled in various status reports like docker plugin ls but they would not actually be active. With this change, authz plugins are now appended to the authz plugin chain when they are dynamically enabled so that docker plugin ls and similar do not lie.

- How I did it

plugin's Manager.Enable now checks for the authz capability and appends the plugin to the authz middleware chain if found.

- How to verify it

287f14b tests that re-enabling an authz plugin behaves as expected.

- Description for the changelog

"authz plugins can now be enabled dynamically with 'docker plugin install' and 'docker plugin enable'"

- A picture of a cute animal (not mandatory but encouraged)

Pygmy marmoset

Cebuella pygmaea, or pygmy marmoset, is the smallest monkey in the world with an average weight of just over 100g. It primarily feeds on gums and saps of trees and lives between the ground and 20m in South American forests. It can turn its head 180 degrees and has elaborate communication behaviors.

@riyazdf
Copy link
Copy Markdown
Contributor

riyazdf commented Jun 13, 2017

thanks @dsheets for bringing this up! I agree that this is a much more intuitive UX.

My only concern is the failure mode if a docker daemon restarts. If the daemon was using a dynamically enabled authz plugin, I think we should also ensure that the plugin is enabled on restart - I'm not sure what the best way of accomplishing this would be, though.

@dsheets dsheets force-pushed the authz-dynamic-enable branch from 287f14b to 99ecf15 Compare June 14, 2017 16:44
@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Jun 14, 2017

@riyazdf good catch! I've updated the patch to append an authz plugin to the middleware chain whenever it is enabled (both during startup and after docker plugin install or docker plugin enable). I used the Handle method of the plugin store for this (relied upon by ipam and network plugins for registration). The CLI and daemon.json remain the only ways to explicitly specify the order of authz plugins (if plugins modify content this is important). As such, using the CLI or daemon.json is still best practice and the preferred way to specify authz plugins.

I'm going to be offline until July 7 but @yallop should be able to answer questions or address concerns in the interim.

Copy link
Copy Markdown
Contributor

@riyazdf riyazdf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @dsheets for the update and explaining how it works, this LGTM 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks for adding this restart test

@cpuguy83
Copy link
Copy Markdown
Member

A few tests failing.

@riyazdf
Copy link
Copy Markdown
Contributor

riyazdf commented Jun 16, 2017

looks like a failure on the v1 authz plugin teardown that affects followup tests, though I'm not sure how this change affects this directly. cc @yallop

18:31:37 ----------------------------------------------------------------------
18:31:37 FAIL: docker_cli_authz_unix_test.go:73: DockerAuthzSuite.TearDownTest
18:31:37 
18:31:37 docker_cli_authz_unix_test.go:76:
18:31:37     s.ds.TearDownTest(c)
18:31:37 environment/clean.go:143:
18:31:37     t.Fatalf("%v", err)
18:31:37 ... Error: json: cannot unmarshal object into Go value of type []types.NetworkResource
18:31:37 
18:31:37 
18:31:37 ----------------------------------------------------------------------
18:31:37 PANIC: docker_cli_authz_unix_test.go:282: DockerAuthzSuite.TestAuthZPluginAPIDenyResponse
18:31:37 
18:31:37 [d36ba59acdb28] waiting for daemon to start
18:31:37 [d36ba59acdb28] daemon started
18:31:37 
18:31:37 [d36ba59acdb28] exiting daemon
18:31:37 ... Panic: Fixture has panicked (see related PANIC)
18:31:37 
18:31:37 ----------------------------------------------------------------------

@thaJeztah thaJeztah added status/2-code-review status/failing-ci Indicates that the PR in its current state fails the test suite and removed status/0-triage labels Jun 23, 2017
@thaJeztah
Copy link
Copy Markdown
Member

ping @dsheets can you work on the failing tests?

@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Jul 21, 2017

Yes, I'm looking at the failing test. It looks like the command-line-specified authz plugin is being retained as enabled. This causes the test teardown to fail as the authz plugin disallows access to endpoints like /networks and /plugins which are required for teardown.

@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Jul 24, 2017

The test was failing because the global test daemon and the authz test suite daemon share the plugin spec directory and V1 plugins are activated during queries or retrieval (Get). V1 plugins have no means to disable an installed plugin and so the V1 model and global plugin kinds like authz don't work well together. Any subsystem that retrieved V1 plugins or requested their type would end up activating those plugins and, with global plugin kinds like authz, inserting the plugin into a global processing chain. This caused the available but not-enabled authz plugin under test in docker_cli_authz_unix_test.go to become enabled in the global test daemon during tear down where plugins get enumerated. The plugin would then block further resource enumerations during teardown as designed.

I've fixed this issue by factoring out plugin V2+ handler registration from all-plugin handler registration and only registering an authz V2+ plugin handler to inject middleware. As V1 authz plugins can only be enabled via the daemon command-line, config file, or daemon reload, the handler does not need to run for V1 plugins. V2 plugins have two states: enabled and disabled. If a V2 plugin is enabled, the handler will ensure that it is loaded into the authz middleware chain. If the plugin is disabled, the handler will not be triggered.

@thaJeztah thaJeztah added area/plugins impact/changelog and removed status/failing-ci Indicates that the PR in its current state fails the test suite labels Jul 24, 2017
@thaJeztah
Copy link
Copy Markdown
Member

ping @cpuguy83 PTAL

@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Aug 3, 2017

Any review?

dsheets pushed a commit to dsheets/moby that referenced this pull request Sep 7, 2017
Necessary until moby#33658 is merged.

Signed-off-by: David Sheets <dsheets@docker.com>
@dsheets dsheets force-pushed the authz-dynamic-enable branch from bcf30d8 to 0bbb8de Compare September 7, 2017 09:44
@dsheets dsheets force-pushed the authz-dynamic-enable branch from 9fbfb6a to d400db7 Compare September 7, 2017 14:35
@dsheets dsheets force-pushed the authz-dynamic-enable branch from b3b68f3 to 7ce4735 Compare October 6, 2017 16:38
@dsheets dsheets requested a review from tianon as a code owner October 6, 2017 16:38
@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Oct 6, 2017

This PR now depends on #34941. I've fixed a number of pre-existing and latent issues that testing state transitions revealed. There are still at least two additional test cases I would like to write before having this merged but I believe the work on names, v1/v2 collisions, and persistent chains can be reviewed now.

@dsheets dsheets force-pushed the authz-dynamic-enable branch 7 times, most recently from 6155114 to 40bf85c Compare October 10, 2017 15:07
David Sheets added 13 commits October 11, 2017 16:09
Previously, authz plugins could be installed or enabled using 'docker
plugin' commands and they would show as 'enabled' in various status
reports like 'docker plugin ls' but they would not actually be
active. With this change, authz plugins are now appended to the authz
plugin chain when they are dynamically enabled so that 'docker plugin
ls' and similar do not lie.

Signed-off-by: David Sheets <dsheets@docker.com>
The legacy V1 plugin model conflates plugin querying/retrieval and
activation which causes issues for global plugin kinds like
authz. store.HandleV2 allows users to register a handler for only V2 and
later plugins to avoid the V1 design mistake.

Signed-off-by: David Sheets <dsheets@docker.com>
interfacer linter was introduced in moby#34625.

Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
This changes the authz middleware chain to use consistent, fixed
names. Previously, the authz chain operated on user-supplied names
initially for purposes such as deduplication. This caused issues as
authz v2 plugins use container names which can have aliases (user/plugin
and user/plugin:latest are actually the same). A test case has been
added testing this v2 plugin name aliasing.

To fix this issue, the authz middleware chain now only uses canonical
names and performs its own plugin validation eagerly. Lazy
initialization and the ability to change a plugin's name have been
removed. Those behaviors were necessary because the middleware chain
used to be initialized before plugins were loaded and so canonical names
were not yet available at initialization time. To fix this, authz
plugins supplied via the daemon command line are now prepended to the
authz chain immediately after the daemon object is initialized. Authz
chain modification functions can now return errors if the named plugin
is not available. Plugin v2 handlers can now also fail plugin
initialization.

Signed-off-by: David Sheets <dsheets@docker.com>
Previously, no error would be triggered when the namespaces collide which
would, in certain circumstances, allow the run-time removal of normally
unremoveable V1 authz plugins.

Signed-off-by: David Sheets <dsheets@docker.com>
Convert authz plugins to use these persistent plugin chains to keep track
of v2 authz middleware ordering.

Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
Signed-off-by: David Sheets <dsheets@docker.com>
@cpuguy83
Copy link
Copy Markdown
Member

Is this ready to go? Needs a rebase.

@djs55
Copy link
Copy Markdown
Contributor

djs55 commented Jan 19, 2018

I don't think @dsheets wants to work on this any more (correct me if I'm wrong, @dsheets!)

I did a quick rebase https://github.com/djs55/docker/tree/authz-dynamic-enable

To my untrained eye the only place where there was an interesting conflict was in pkg/authorization/plugin.go where ddae20c added a field initErr error to the type authorizationPlugin struct . It seemed in this version to be unused so I removed it in the patch which also removed the once sync.Once from the struct ("authz plugins: use fixed, canonical names")

@dsheets
Copy link
Copy Markdown
Contributor Author

dsheets commented Jan 21, 2018

I will not shepherd this PR any more. I recommend checking the osxfs handover document to see if there were remaining TODO items for this work.

@cpuguy83
Copy link
Copy Markdown
Member

Closing this as this is now quite out of date and no one is actively working on it.

@cpuguy83 cpuguy83 closed this May 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants