Repository: mesos Updated Branches: refs/heads/master f22af9805 -> 8443b1848
Enabled authorization for Mesos log access. Uses the authorization primitives in `mesos::internal::Files` to add protection of the Mesos logs on both master and agents. Review: https://reviews.apache.org/r/47921/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/8443b184 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/8443b184 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/8443b184 Branch: refs/heads/master Commit: 8443b18489c48996df0a88f90baf260a0fb12176 Parents: f22af98 Author: Alexander Rojas <[email protected]> Authored: Sun May 29 11:16:03 2016 -0700 Committer: Adam B <[email protected]> Committed: Mon May 30 00:59:14 2016 -0700 ---------------------------------------------------------------------- include/mesos/authorizer/acls.proto | 11 +++++++++++ include/mesos/authorizer/authorizer.proto | 4 ++++ src/authorizer/local/authorizer.cpp | 19 ++++++++++++++++++- src/master/master.cpp | 25 +++++++++++++++++++++++-- src/master/master.hpp | 3 +++ src/slave/slave.cpp | 25 +++++++++++++++++++++++-- src/slave/slave.hpp | 3 +++ 7 files changed, 85 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/include/mesos/authorizer/acls.proto ---------------------------------------------------------------------- diff --git a/include/mesos/authorizer/acls.proto b/include/mesos/authorizer/acls.proto index b05586a..db55ee5 100644 --- a/include/mesos/authorizer/acls.proto +++ b/include/mesos/authorizer/acls.proto @@ -223,6 +223,16 @@ message ACL { // executors/tasks sandboxes can be accessed. optional Entity users = 2; } + + // Which principals are authorized to access the Mesos logs. + message AccessMesosLog { + // Subjects: HTTP Username. + required Entity principals = 1; + + // Objects: Given implicitly. Use Entity type ANY or NONE to allow or deny + // access. + optional Entity logs = 2; + } } @@ -271,4 +281,5 @@ message ACLs { repeated ACL.ViewTask view_tasks = 17; repeated ACL.ViewExecutor view_executors = 18; repeated ACL.AccessSandbox access_sandboxes = 19; + repeated ACL.AccessMesosLog access_mesos_logs = 20; } http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/include/mesos/authorizer/authorizer.proto ---------------------------------------------------------------------- diff --git a/include/mesos/authorizer/authorizer.proto b/include/mesos/authorizer/authorizer.proto index 3ff6785..4478bbd 100644 --- a/include/mesos/authorizer/authorizer.proto +++ b/include/mesos/authorizer/authorizer.proto @@ -85,6 +85,10 @@ enum Action { // This action will have a `FrameworkInfo` and `ExecutorInfo` set, // allowing both as objects in order to perform authorization. ACCESS_SANDBOX = 17; + + // This action will not fill in any object fields, since the object + // is the master/agent log itself. + ACCESS_MESOS_LOG = 18; } http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/src/authorizer/local/authorizer.cpp ---------------------------------------------------------------------- diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp index 7ddb323..547bbdd 100644 --- a/src/authorizer/local/authorizer.cpp +++ b/src/authorizer/local/authorizer.cpp @@ -273,6 +273,17 @@ public: return authorized(request, acls_); break; + case authorization::ACCESS_MESOS_LOG: + foreach (const ACL::AccessMesosLog& acl, acls.access_mesos_logs()) { + GenericACL acl_; + acl_.subjects = acl.principals(); + acl_.objects = acl.logs(); + + acls_.push_back(acl_); + } + + return authorized(request, acls_); + break; case authorization::ACCESS_SANDBOX: { authorization::Request realRequest; realRequest.set_action(authorization::ACCESS_SANDBOX); @@ -303,7 +314,6 @@ public: return authorized(realRequest, acls_); break; } - // TODO(joerg84): Add logic for the `VIEW_*` actions. case authorization::VIEW_FRAMEWORK: case authorization::VIEW_TASK: @@ -504,6 +514,13 @@ Option<Error> LocalAuthorizer::validate(const ACLs& acls) "together with deprecated set_quotas/remove_quotas!"); } + + foreach (const ACL::AccessMesosLog& acl, acls.access_mesos_logs()) { + if (acl.logs().type() == ACL::Entity::SOME) { + return Error("acls.access_mesos_logs type must be either NONE or ANY"); + } + } + return None(); } http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/src/master/master.cpp ---------------------------------------------------------------------- diff --git a/src/master/master.cpp b/src/master/master.cpp index 67d3309..a6f740f 100644 --- a/src/master/master.cpp +++ b/src/master/master.cpp @@ -1156,10 +1156,14 @@ void Master::initialize() provide("", path::join(flags.webui_dir, "master/static/index.html")); provide("static", path::join(flags.webui_dir, "master/static")); + auto authorize = [this](const Option<string>& principal) { + return authorizeLogAccess(principal); + }; + // Expose the log file for the webui. Fall back to 'log_dir' if // an explicit file was not specified. if (flags.external_log_file.isSome()) { - files->attach(flags.external_log_file.get(), "/master/log") + files->attach(flags.external_log_file.get(), "/master/log", authorize) .onAny(defer(self(), &Self::fileAttached, lambda::_1, @@ -1171,7 +1175,7 @@ void Master::initialize() if (log.isError()) { LOG(ERROR) << "Master log file cannot be found: " << log.error(); } else { - files->attach(log.get(), "/master/log") + files->attach(log.get(), "/master/log", authorize) .onAny(defer(self(), &Self::fileAttached, lambda::_1, log.get())); } } @@ -1406,6 +1410,23 @@ void Master::_exited(Framework* framework) } +Future<bool> Master::authorizeLogAccess(const Option<std::string>& principal) +{ + if (authorizer.isNone()) { + return true; + } + + authorization::Request request; + request.set_action(authorization::ACCESS_MESOS_LOG); + + if (principal.isSome()) { + request.mutable_subject()->set_value(principal.get()); + } + + return authorizer.get()->authorized(request); +} + + void Master::visit(const MessageEvent& event) { // There are three cases about the message's UPID with respect to http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/src/master/master.hpp ---------------------------------------------------------------------- diff --git a/src/master/master.hpp b/src/master/master.hpp index 9cc79ef..eeeccdf 100644 --- a/src/master/master.hpp +++ b/src/master/master.hpp @@ -917,6 +917,9 @@ private: return leader.isSome() && leader.get() == info_; } + process::Future<bool> authorizeLogAccess( + const Option<std::string>& principal); + /** * Returns whether the given role is on the whitelist. * http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/src/slave/slave.cpp ---------------------------------------------------------------------- diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp index 1ef8cfb..c235c14 100644 --- a/src/slave/slave.cpp +++ b/src/slave/slave.cpp @@ -776,10 +776,14 @@ void Slave::initialize() return http.containers(request, principal); }); + auto authorize = [this](const Option<string>& principal) { + return authorizeLogAccess(principal); + }; + // Expose the log file for the webui. Fall back to 'log_dir' if // an explicit file was not specified. if (flags.external_log_file.isSome()) { - files->attach(flags.external_log_file.get(), "/slave/log") + files->attach(flags.external_log_file.get(), "/slave/log", authorize) .onAny(defer(self(), &Self::fileAttached, lambda::_1, @@ -791,7 +795,7 @@ void Slave::initialize() if (log.isError()) { LOG(ERROR) << "Agent log file cannot be found: " << log.error(); } else { - files->attach(log.get(), "/slave/log") + files->attach(log.get(), "/slave/log", authorize) .onAny(defer(self(), &Self::fileAttached, lambda::_1, log.get())); } } @@ -5386,6 +5390,23 @@ double Slave::_executor_directory_max_allowed_age_secs() } +Future<bool> Slave::authorizeLogAccess(const Option<std::string>& principal) +{ + if (authorizer.isNone()) { + return true; + } + + authorization::Request request; + request.set_action(authorization::ACCESS_MESOS_LOG); + + if (principal.isSome()) { + request.mutable_subject()->set_value(principal.get()); + } + + return authorizer.get()->authorized(request); +} + + Future<bool> Slave::authorizeSandboxAccess( const Option<std::string>& principal, const FrameworkID& frameworkId, http://git-wip-us.apache.org/repos/asf/mesos/blob/8443b184/src/slave/slave.hpp ---------------------------------------------------------------------- diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp index 26e94c6..52aeb0d 100644 --- a/src/slave/slave.hpp +++ b/src/slave/slave.hpp @@ -419,6 +419,9 @@ private: // exited. void _shutdownExecutor(Framework* framework, Executor* executor); + process::Future<bool> authorizeLogAccess( + const Option<std::string>& principal); + Future<bool> authorizeSandboxAccess( const Option<std::string>& principal, const FrameworkID& frameworkId,
