Skip to content

Commit

Permalink
Mesos token auth (#673)
Browse files Browse the repository at this point in the history
Support DC/OS token auth and HTTPS on Mesos
  • Loading branch information
luca3m authored and Luca Marturana committed Nov 15, 2016
1 parent 3afff54 commit 7947e2e
Show file tree
Hide file tree
Showing 10 changed files with 318 additions and 80 deletions.
2 changes: 1 addition & 1 deletion userspace/libsinsp/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ bool sinsp_container_manager::set_mesos_task_id(sinsp_container_info* container,
else
{
g_logger.log("Mesos task ID not found for Mesos container [" + container->m_id + "],"
"thread [" + std::to_string(tinfo->m_tid) + ']', sinsp_logger::SEV_WARNING);
"thread [" + std::to_string(tinfo->m_tid) + ']', sinsp_logger::SEV_DEBUG);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions userspace/libsinsp/marathon_http.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#include <stdexcept>
#include <unistd.h>

marathon_http::marathon_http(mesos& m, const uri& url, bool discover_marathon, int timeout_ms):
mesos_http(m, url, false, discover_marathon, timeout_ms)
marathon_http::marathon_http(mesos& m, const uri& url, bool discover_marathon, int timeout_ms, const string& token):
mesos_http(m, url, false, discover_marathon, timeout_ms, token)
{
g_logger.log("Creating Marathon HTTP object for [" + url.to_string(false) + "] ...", sinsp_logger::SEV_DEBUG);
if(refresh_data())
Expand Down
2 changes: 1 addition & 1 deletion userspace/libsinsp/marathon_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class marathon_http : public mesos_http
public:
typedef std::shared_ptr<marathon_http> ptr_t;

marathon_http(mesos& m, const uri& url, bool discover_marathon, int timeout_ms = 5000L);
marathon_http(mesos& m, const uri& url, bool discover_marathon, int timeout_ms = 5000L, const string& token = "");

~marathon_http();

Expand Down
141 changes: 124 additions & 17 deletions userspace/libsinsp/mesos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const std::string mesos::default_marathon_uri = "http://localhost:8080";
const std::string mesos::default_groups_api = "/v2/groups";
const std::string mesos::default_apps_api = "/v2/apps?embed=apps.tasks";
const std::string mesos::default_watch_api = "/v2/events";
const std::string mesos::default_version_api = "/version";
const int mesos::default_timeout_ms = 5000;

mesos::mesos(const std::string& mesos_state_json,
Expand Down Expand Up @@ -132,24 +133,71 @@ mesos::mesos(const std::string& state_uri,
init();
}

mesos::mesos(const std::string& state_uri,
const uri_list_t& marathon_uris,
bool discover_mesos_leader,
bool discover_marathon_leader,
const credentials_t& dcos_enterprise_credentials,
int timeout_ms,
bool is_captured,
bool verbose):
#ifdef HAS_CAPTURE
m_collector(false),
m_mesos_uri(state_uri),
m_marathon_uris(marathon_uris),
#endif // HAS_CAPTURE
m_state(is_captured, verbose),
m_discover_mesos_leader(discover_mesos_leader),
m_discover_marathon_uris(discover_marathon_leader || marathon_uris.empty()),
m_timeout_ms(timeout_ms),
m_verbose(verbose),
m_testing(false),
m_dcos_enterprise_credentials(dcos_enterprise_credentials)
{
#ifdef HAS_CAPTURE
g_logger.log(std::string("Creating Mesos object for [" +
(m_mesos_uri.empty() ? std::string("capture replay") : m_mesos_uri) +
"], failover autodiscovery set to ") +
(m_discover_mesos_leader ? "true" : "false"),
sinsp_logger::SEV_DEBUG);

if(m_marathon_uris.size() > 1)
{
std::string marathon_uri = m_marathon_uris[0];
m_marathon_uris.clear();
m_marathon_uris.emplace_back(marathon_uri);
g_logger.log("Multiple root marathon URIs configured; only the first one (" + marathon_uri + ") will have effect;"
" others will be treated as generic frameworks (user Marathon frameworks will be discovered).", sinsp_logger::SEV_WARNING);
}

authenticate();
#endif
init();
}

mesos::~mesos()
{
curl_global_cleanup();
}

void mesos::init()
{
#ifdef HAS_CAPTURE
if(!m_mesos_uri.empty())
{
curl_global_init(CURL_GLOBAL_DEFAULT);
m_collector.remove_all();
if((m_state_http) && (!m_state_http.unique()))
{
throw sinsp_exception("Invalid access to Mesos initializer: mesos state http client for [" +
m_mesos_uri + "] not unique.");
}
m_state_http = std::make_shared<mesos_http>(*this, m_mesos_uri + default_state_api, m_discover_mesos_leader, m_marathon_uris.empty(), m_timeout_ms);
m_state_http = std::make_shared<mesos_http>(*this, m_mesos_uri + default_state_api, m_discover_mesos_leader, m_marathon_uris.empty(), m_timeout_ms, m_token);
rebuild_mesos_state(true);
init_marathon();
if(!has_marathon())
{
init_marathon();
}
}
#endif // HAS_CAPTURE
}
Expand All @@ -162,16 +210,15 @@ void mesos::init_marathon()
m_marathon_groups_http.clear();
m_marathon_apps_http.clear();

bool discover_marathon = m_marathon_uris.size() == 0;
const uri_list_t& marathons = discover_marathon ? m_state_http->get_marathon_uris() : m_marathon_uris;
const uri_list_t& marathons = m_discover_marathon_uris ? m_state_http->get_marathon_uris() : m_marathon_uris;
if(marathons.size())
{
g_logger.log("Found " + std::to_string(marathons.size()) + " Marathon URIs", sinsp_logger::SEV_DEBUG);
for(const auto& muri : marathons)
{
g_logger.log("Creating Marathon http objects: " + uri(muri).to_string(false), sinsp_logger::SEV_DEBUG);
m_marathon_groups_http[muri] = std::make_shared<marathon_http>(*this, muri + default_groups_api, discover_marathon, m_timeout_ms);
m_marathon_apps_http[muri] = std::make_shared<marathon_http>(*this, muri + default_apps_api, discover_marathon, m_timeout_ms);
m_marathon_groups_http[muri] = std::make_shared<marathon_http>(*this, muri + default_groups_api, m_discover_marathon_uris, m_timeout_ms, m_token);
m_marathon_apps_http[muri] = std::make_shared<marathon_http>(*this, muri + default_apps_api, m_discover_marathon_uris, m_timeout_ms, m_token);
}

if(has_marathon())
Expand All @@ -183,6 +230,70 @@ void mesos::init_marathon()
#endif // HAS_CAPTURE
}

void mesos::refresh_token()
{
authenticate();
m_state_http->set_token(m_token);
if(has_marathon())
{
for(auto& group_http : m_marathon_groups_http)
{
if(group_http.second)
{
group_http.second->set_token(m_token);
}
else
{
throw sinsp_exception("Marathon groups HTTP client is null.");
}
}
for(auto& app_http : m_marathon_apps_http)
{
if(app_http.second)
{
app_http.second->set_token(m_token);
}
else
{
throw sinsp_exception("Marathon apps HTTP client is null.");
}
}
}
}

void mesos::authenticate()
{
sinsp_curl auth_request(uri("https://localhost/acs/api/v1/auth/login"), "", "");
Json::FastWriter json_writer;
Json::Value auth_obj;
auth_obj["uid"] = m_dcos_enterprise_credentials.first;
auth_obj["password"] = m_dcos_enterprise_credentials.second;
auth_request.add_header("Content-Type: application/json");
auth_request.setopt(CURLOPT_POST, 1);
auth_request.set_body(json_writer.write(auth_obj));
//auth_request.enable_debug();
auto response = auth_request.get_data();

if(auth_request.get_response_code() == 200)
{
Json::Reader json_reader;
Json::Value response_obj;
auto parse_ok = json_reader.parse(response, response_obj, false);
if(parse_ok && response_obj.isMember("token"))
{
m_token = response_obj["token"].asString();
g_logger.format(sinsp_logger::SEV_DEBUG, "Mesos authenticated with token=%s", m_token.c_str());
}
else
{
throw sinsp_exception(string("Cannot authenticate on Mesos master, response=") + response);
}
} else
{
throw sinsp_exception(string("Cannot authenticate on Mesos master, response_code=") + to_string(auth_request.get_response_code()));
}
}

void mesos::refresh()
{
rebuild_mesos_state();
Expand Down Expand Up @@ -647,10 +758,16 @@ void mesos::handle_frameworks(const Json::Value& root)
{
g_logger.log("New or activated Mesos framework detected: " + name + " [" + uid.asString() + ']', sinsp_logger::SEV_INFO);
m_activated_frameworks.insert(uid.asString());
if(mesos_framework::is_root_marathon(name))
#ifdef HAS_CAPTURE
if(mesos_framework::is_root_marathon(name) &&
find_if(m_marathon_groups_http.begin(), m_marathon_groups_http.end(), [uid](const decltype(m_marathon_groups_http)::value_type& item)
{
return item.second->get_framework_id() == uid.asString();
}) == m_marathon_groups_http.end())
{
init_marathon();
}
#endif
}
}
}
Expand Down Expand Up @@ -842,16 +959,6 @@ void mesos::set_state_json(json_ptr_t json, const std::string&)
void mesos::parse_state(Json::Value&& root)
{
clear_mesos();
#ifdef HAS_CAPTURE
if(m_discover_marathon_uris && !has_marathon())
{
m_state_http->discover_framework_uris(root["frameworks"]);
if(has_marathon())
{
init_marathon();
}
}
#endif // HAS_CAPTURE
handle_frameworks(root);
handle_slaves(root);
#ifdef HAS_CAPTURE
Expand Down
19 changes: 17 additions & 2 deletions userspace/libsinsp/mesos.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class mesos
static const std::string default_groups_api;
static const std::string default_apps_api;
static const std::string default_watch_api;
static const std::string default_version_api;
static const int default_timeout_ms;

// constructor for testing only, not to be used in production
Expand All @@ -52,6 +53,15 @@ class mesos
bool is_captured = false,
bool verbose = false);

mesos(const std::string& state_uri,
const uri_list_t& marathon_uris = uri_list_t(),
bool discover_mesos_leader = false,
bool discover_marathon_leader = false,
const credentials_t& dcos_enterprise_credentials = credentials_t(),
int timeout_ms = default_timeout_ms,
bool is_captured = false,
bool verbose = false);

~mesos();

const mesos_state_t& get_state() const;
Expand All @@ -64,7 +74,8 @@ class mesos

void simulate_event(const std::string& json);
bool collect_data();

void refresh_token();

#ifdef HAS_CAPTURE
void send_data_request(bool collect = true);

Expand Down Expand Up @@ -118,6 +129,7 @@ class mesos
private:
void init();
void init_marathon();
void authenticate();
void rebuild_mesos_state(bool full = false);
void rebuild_marathon_state(bool full = false);

Expand Down Expand Up @@ -157,7 +169,10 @@ class mesos
bool m_testing = false;
uri::credentials_t m_mesos_credentials;
uri::credentials_t m_marathon_credentials;

uri::credentials_t m_dcos_enterprise_credentials;
string m_token;
bool m_token_authentication;

typedef std::unordered_set<std::string> framework_list_t;
framework_list_t m_inactive_frameworks;
framework_list_t m_activated_frameworks;
Expand Down
Loading

0 comments on commit 7947e2e

Please sign in to comment.