From 95fbd75df825db42ca8e1b09ff0b0f87caf03d5c Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Mon, 11 Sep 2017 17:00:33 +0200 Subject: [PATCH] ElasticWriter: Add basic auth support for Elasticsearch behind an HTTP proxy refs #5538 --- doc/09-object-types.md | 2 ++ lib/perfdata/elasticwriter.cpp | 25 ++++++++++++++++++++++++- lib/perfdata/elasticwriter.ti | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/doc/09-object-types.md b/doc/09-object-types.md index f3bf882ab..5c11b4af9 100644 --- a/doc/09-object-types.md +++ b/doc/09-object-types.md @@ -1000,6 +1000,8 @@ Configuration Attributes: enable_send_perfdata | **Optional.** Send parsed performance data metrics for check results. Defaults to `false`. flush_interval | **Optional.** How long to buffer data points before transfering to Elasticsearch. Defaults to `10`. flush_threshold | **Optional.** How many data points to buffer before forcing a transfer to Elasticsearch. Defaults to `1024`. + username | **Optional.** Basic auth username if Elasticsearch is hidden behind an HTTP proxy. + password | **Optional.** Basic auth password if Elasticsearch is hidden behind an HTTP proxy. Note: If `flush_threshold` is set too low, this will force the feature to flush all data to Elasticsearch too often. Experiment with the setting, if you are processing more than 1024 metrics per second or similar. diff --git a/lib/perfdata/elasticwriter.cpp b/lib/perfdata/elasticwriter.cpp index 667dafbb8..c8f50aba6 100644 --- a/lib/perfdata/elasticwriter.cpp +++ b/lib/perfdata/elasticwriter.cpp @@ -27,6 +27,7 @@ #include "icinga/checkcommand.hpp" #include "base/tcpsocket.hpp" #include "base/stream.hpp" +#include "base/base64.hpp" #include "base/json.hpp" #include "base/utility.hpp" #include "base/networkstream.hpp" @@ -422,12 +423,19 @@ void ElasticWriter::SendRequest(const String& body) req.AddHeader("Accept", "application/json"); req.AddHeader("Content-Type", "application/json"); + /* Send authentication if configured. */ + String username = GetUsername(); + String password = GetPassword(); + + if (!username.IsEmpty() && !password.IsEmpty()) + req.AddHeader("Authorization", "Basic " + Base64::Encode(username + ":" + password)); + req.RequestMethod = "POST"; req.RequestUrl = url; #ifdef I2_DEBUG /* I2_DEBUG */ Log(LogDebug, "ElasticWriter") - << "Sending body: " << body; + << "Sending request" << ((!username.IsEmpty() && !password.IsEmpty()) ? " with basic auth " : "" ) << body; #endif /* I2_DEBUG */ try { @@ -451,6 +459,20 @@ void ElasticWriter::SendRequest(const String& body) } if (resp.StatusCode > 299) { + if (resp.StatusCode == 401) { + /* More verbose error logging with Elasticsearch is hidden behind a proxy. */ + if (!username.IsEmpty() && !password.IsEmpty()) { + Log(LogCritical, "ElasticWriter") + << "401 Unauthorized. Please ensure that the user '" << username + << "' is able to authenticate against the HTTP API/Proxy."; + } else { + Log(LogCritical, "ElasticWriter") + << "401 Unauthorized. The HTTP API requires authentication but no username/password has been configured."; + } + + return; + } + Log(LogWarning, "ElasticWriter") << "Unexpected response code " << resp.StatusCode; @@ -459,6 +481,7 @@ void ElasticWriter::SendRequest(const String& body) resp.Parse(context, true); String contentType = resp.Headers->Get("content-type"); + if (contentType != "application/json") { Log(LogWarning, "ElasticWriter") << "Unexpected Content-Type: " << contentType; diff --git a/lib/perfdata/elasticwriter.ti b/lib/perfdata/elasticwriter.ti index 430bb402c..023d9e349 100644 --- a/lib/perfdata/elasticwriter.ti +++ b/lib/perfdata/elasticwriter.ti @@ -19,6 +19,8 @@ class ElasticWriter : ConfigObject [config] bool enable_send_perfdata { default {{{ return false; }}} }; + [config] String username; + [config] String password; [config] int flush_interval { default {{{ return 10; }}}