This is an automated email from the ASF dual-hosted git repository. grag pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 497af42d422a7733b178c3f12b5c34c9328114c0 Author: Joseph Wu <[email protected]> AuthorDate: Fri Jun 28 12:56:11 2019 -0700 Added ACLs for agent draining APIs. This adds three ACLs for the three endpoints added as part of the agent draining feature: * DRAIN_AGENT * DEACTIVATE_AGENT * REACTIVATE_AGENT All three ACLs are coarse-grained; a principal is either allowed to perform the action, or unauthorized. However, there is scope to restrict the action to particular subsets of agents in future. Review: https://reviews.apache.org/r/70910/ --- include/mesos/authorizer/acls.proto | 30 ++++++ include/mesos/authorizer/authorizer.proto | 12 +++ src/authorizer/local/authorizer.cpp | 64 ++++++++++++ src/tests/authorization_tests.cpp | 165 ++++++++++++++++++++++++++++++ src/tests/master_authorization_tests.cpp | 3 + 5 files changed, 274 insertions(+) diff --git a/include/mesos/authorizer/acls.proto b/include/mesos/authorizer/acls.proto index 78acfe6..f40c13e 100644 --- a/include/mesos/authorizer/acls.proto +++ b/include/mesos/authorizer/acls.proto @@ -419,6 +419,33 @@ message ACL { required Entity machines = 2; } + message DrainAgent { + // Subjects: HTTP Username. + required Entity principals = 1; + + // Objects: Given implicitly. Use Entity type ANY or NONE to allow or deny + // access. + required Entity agents = 2; + } + + message DeactivateAgent { + // Subjects: HTTP Username. + required Entity principals = 1; + + // Objects: Given implicitly. Use Entity type ANY or NONE to allow or deny + // access. + required Entity agents = 2; + } + + message ReactivateAgent { + // Subjects: HTTP Username. + required Entity principals = 1; + + // Objects: Given implicitly. Use Entity type ANY or NONE to allow or deny + // access. + required Entity agents = 2; + } + // Which principals are authorized to mark an agent as gone. message MarkAgentGone { // Subjects: HTTP Username. @@ -657,6 +684,9 @@ message ACLs { repeated ACL.StartMaintenance start_maintenances = 37; repeated ACL.StopMaintenance stop_maintenances = 38; repeated ACL.GetMaintenanceStatus get_maintenance_statuses = 39; + repeated ACL.DrainAgent drain_agents = 56; + repeated ACL.DeactivateAgent deactivate_agents = 57; + repeated ACL.ReactivateAgent reactivate_agents = 58; repeated ACL.MarkAgentGone mark_agents_gone = 40; repeated ACL.LaunchStandaloneContainer launch_standalone_containers = 41; repeated ACL.KillStandaloneContainer kill_standalone_containers = 42; diff --git a/include/mesos/authorizer/authorizer.proto b/include/mesos/authorizer/authorizer.proto index ad40d3a..d09c234 100644 --- a/include/mesos/authorizer/authorizer.proto +++ b/include/mesos/authorizer/authorizer.proto @@ -226,6 +226,18 @@ enum Action { GET_MAINTENANCE_STATUS = 33; // This action will not fill in any object fields, since a principal is + // either allowed to drain an agent or is unauthorized. + DRAIN_AGENT = 51; + + // This action will not fill in any object fields, since a principal is + // either allowed to deactivate an agent or is unauthorized. + DEACTIVATE_AGENT = 52; + + // This action will not fill in any object fields, since a principal is + // either allowed to reactivate an agent or is unauthorized. + REACTIVATE_AGENT = 53; + + // This action will not fill in any object fields, since a principal is // either allowed to mark an agent as gone or is unauthorized. MARK_AGENT_GONE = 34; diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp index b89010d..85821c6 100644 --- a/src/authorizer/local/authorizer.cpp +++ b/src/authorizer/local/authorizer.cpp @@ -412,6 +412,9 @@ public: case authorization::START_MAINTENANCE: case authorization::STOP_MAINTENANCE: case authorization::UPDATE_MAINTENANCE_SCHEDULE: + case authorization::DRAIN_AGENT: + case authorization::DEACTIVATE_AGENT: + case authorization::REACTIVATE_AGENT: case authorization::MODIFY_RESOURCE_PROVIDER_CONFIG: case authorization::MARK_RESOURCE_PROVIDER_GONE: case authorization::VIEW_RESOURCE_PROVIDER: @@ -734,6 +737,9 @@ public: case authorization::SET_LOG_LEVEL: case authorization::START_MAINTENANCE: case authorization::STOP_MAINTENANCE: + case authorization::DRAIN_AGENT: + case authorization::DEACTIVATE_AGENT: + case authorization::REACTIVATE_AGENT: case authorization::TEARDOWN_FRAMEWORK: case authorization::UNRESERVE_RESOURCES: case authorization::UPDATE_MAINTENANCE_SCHEDULE: @@ -985,6 +991,9 @@ public: case authorization::SET_LOG_LEVEL: case authorization::START_MAINTENANCE: case authorization::STOP_MAINTENANCE: + case authorization::DRAIN_AGENT: + case authorization::DEACTIVATE_AGENT: + case authorization::REACTIVATE_AGENT: case authorization::TEARDOWN_FRAMEWORK: case authorization::UNKNOWN: case authorization::UNRESERVE_RESOURCES: @@ -1213,6 +1222,9 @@ public: case authorization::TEARDOWN_FRAMEWORK: case authorization::UNRESERVE_RESOURCES: case authorization::UPDATE_MAINTENANCE_SCHEDULE: + case authorization::DRAIN_AGENT: + case authorization::DEACTIVATE_AGENT: + case authorization::REACTIVATE_AGENT: case authorization::VIEW_CONTAINER: case authorization::VIEW_EXECUTOR: case authorization::VIEW_FLAGS: @@ -1502,6 +1514,40 @@ private: } return acls_; + + case authorization::DRAIN_AGENT: + foreach (const ACL::DrainAgent& acl, + acls.drain_agents()) { + GenericACL acl_; + acl_.subjects = acl.principals(); + acl_.objects = acl.agents(); + + acls_.push_back(acl_); + } + + return acls_; + case authorization::DEACTIVATE_AGENT: + foreach (const ACL::DeactivateAgent& acl, + acls.deactivate_agents()) { + GenericACL acl_; + acl_.subjects = acl.principals(); + acl_.objects = acl.agents(); + + acls_.push_back(acl_); + } + + return acls_; + case authorization::REACTIVATE_AGENT: + foreach (const ACL::ReactivateAgent& acl, + acls.reactivate_agents()) { + GenericACL acl_; + acl_.subjects = acl.principals(); + acl_.objects = acl.agents(); + + acls_.push_back(acl_); + } + + return acls_; case authorization::MARK_AGENT_GONE: foreach (const ACL::MarkAgentGone& acl, acls.mark_agents_gone()) { @@ -1749,6 +1795,24 @@ Option<Error> LocalAuthorizer::validate(const ACLs& acls) } } + foreach (const ACL::DrainAgent& acl, acls.drain_agents()) { + if (acl.agents().type() == ACL::Entity::SOME) { + return Error("ACL.DrainAgent type must be either NONE or ANY"); + } + } + + foreach (const ACL::DeactivateAgent& acl, acls.deactivate_agents()) { + if (acl.agents().type() == ACL::Entity::SOME) { + return Error("ACL.DeactivateAgent type must be either NONE or ANY"); + } + } + + foreach (const ACL::ReactivateAgent& acl, acls.reactivate_agents()) { + if (acl.agents().type() == ACL::Entity::SOME) { + return Error("ACL.ReactivateAgent type must be either NONE or ANY"); + } + } + foreach (const ACL::LaunchStandaloneContainer& acl, acls.launch_standalone_containers()) { if (acl.users().type() == ACL::Entity::SOME) { diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp index 7bb0bd8..5ad13b9 100644 --- a/src/tests/authorization_tests.cpp +++ b/src/tests/authorization_tests.cpp @@ -5919,6 +5919,171 @@ TYPED_TEST(AuthorizationTest, GetMaintenanceStatus) } +// This tests the authorization of requests to DrainAgent. +TYPED_TEST(AuthorizationTest, DrainAgent) +{ + ACLs acls; + + { + // "foo" principal can drain agents. + mesos::ACL::DrainAgent* acl = acls.add_drain_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->set_type(mesos::ACL::Entity::ANY); + } + + { + // Nobody else can drain agents. + mesos::ACL::DrainAgent* acl = acls.add_drain_agents(); + acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); + acl->mutable_agents()->set_type(mesos::ACL::Entity::NONE); + } + + Try<Authorizer*> create = TypeParam::create(parameterize(acls)); + ASSERT_SOME(create); + Owned<Authorizer> authorizer(create.get()); + + { + // "foo" is allowed to drain agents. + authorization::Request request; + request.set_action(authorization::DRAIN_AGENT); + request.mutable_subject()->set_value("foo"); + + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + // "bar" is not allowed to drain agents. + authorization::Request request; + request.set_action(authorization::DRAIN_AGENT); + request.mutable_subject()->set_value("bar"); + + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + { + // Test that no authorizer is created with invalid ACLs. + ACLs invalid; + + mesos::ACL::DrainAgent* acl = invalid.add_drain_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->add_values("yoda"); + + Try<Authorizer*> create = TypeParam::create(parameterize(invalid)); + EXPECT_ERROR(create); + } +} + + +// This tests the authorization of requests to DeactivateAgent. +TYPED_TEST(AuthorizationTest, DeactivateAgent) +{ + ACLs acls; + + { + // "foo" principal can deactivate agents. + mesos::ACL::DeactivateAgent* acl = acls.add_deactivate_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->set_type(mesos::ACL::Entity::ANY); + } + + { + // Nobody else can deactivate agents. + mesos::ACL::DeactivateAgent* acl = acls.add_deactivate_agents(); + acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); + acl->mutable_agents()->set_type(mesos::ACL::Entity::NONE); + } + + Try<Authorizer*> create = TypeParam::create(parameterize(acls)); + ASSERT_SOME(create); + Owned<Authorizer> authorizer(create.get()); + + { + // "foo" is allowed to deactivate agents. + authorization::Request request; + request.set_action(authorization::DEACTIVATE_AGENT); + request.mutable_subject()->set_value("foo"); + + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + // "bar" is not allowed to deactivate agents. + authorization::Request request; + request.set_action(authorization::DEACTIVATE_AGENT); + request.mutable_subject()->set_value("bar"); + + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + { + // Test that no authorizer is created with invalid ACLs. + ACLs invalid; + + mesos::ACL::DeactivateAgent* acl = invalid.add_deactivate_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->add_values("yoda"); + + Try<Authorizer*> create = TypeParam::create(parameterize(invalid)); + EXPECT_ERROR(create); + } +} + + +// This tests the authorization of requests to ReactivateAgent. +TYPED_TEST(AuthorizationTest, ReactivateAgent) +{ + ACLs acls; + + { + // "foo" principal can reactivate agents. + mesos::ACL::ReactivateAgent* acl = acls.add_reactivate_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->set_type(mesos::ACL::Entity::ANY); + } + + { + // Nobody else can reactivate agents. + mesos::ACL::ReactivateAgent* acl = acls.add_reactivate_agents(); + acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY); + acl->mutable_agents()->set_type(mesos::ACL::Entity::NONE); + } + + Try<Authorizer*> create = TypeParam::create(parameterize(acls)); + ASSERT_SOME(create); + Owned<Authorizer> authorizer(create.get()); + + { + // "foo" is allowed to reactivate agents. + authorization::Request request; + request.set_action(authorization::REACTIVATE_AGENT); + request.mutable_subject()->set_value("foo"); + + AWAIT_EXPECT_TRUE(authorizer->authorized(request)); + } + + { + // "bar" is not allowed to reactivate agents. + authorization::Request request; + request.set_action(authorization::REACTIVATE_AGENT); + request.mutable_subject()->set_value("bar"); + + AWAIT_EXPECT_FALSE(authorizer->authorized(request)); + } + + { + // Test that no authorizer is created with invalid ACLs. + ACLs invalid; + + mesos::ACL::ReactivateAgent* acl = invalid.add_reactivate_agents(); + acl->mutable_principals()->add_values("foo"); + acl->mutable_agents()->add_values("yoda"); + + Try<Authorizer*> create = TypeParam::create(parameterize(invalid)); + EXPECT_ERROR(create); + } +} + + // This tests the authorization of requests to ViewStandaloneContainer. TYPED_TEST(AuthorizationTest, ViewStandaloneContainer) { diff --git a/src/tests/master_authorization_tests.cpp b/src/tests/master_authorization_tests.cpp index 7d40695..2932564 100644 --- a/src/tests/master_authorization_tests.cpp +++ b/src/tests/master_authorization_tests.cpp @@ -2991,6 +2991,9 @@ public: case authorization::START_MAINTENANCE: case authorization::STOP_MAINTENANCE: case authorization::GET_MAINTENANCE_STATUS: + case authorization::DRAIN_AGENT: + case authorization::DEACTIVATE_AGENT: + case authorization::REACTIVATE_AGENT: case authorization::MARK_AGENT_GONE: case authorization::LAUNCH_STANDALONE_CONTAINER: case authorization::KILL_STANDALONE_CONTAINER:
