Build: Use environment variables for credentials (elastic/x-pack-elasticsearch#4058)

The credentials now get injected via environment variables, so that
external services can pull those.

As soon as the specified environment variables are set, the tests are run. No need to check for the @Network annotation

This also introduces new secret store settings for the secure settings in order to be sure to not leak them in the configuration files, that get dumped.

Relates elastic/x-pack-elasticsearch#3800

Original commit: elastic/x-pack-elasticsearch@a2cfb9cb86
This commit is contained in:
Alexander Reelsen 2018-03-26 09:10:04 +02:00 committed by GitHub
parent e66072c09f
commit 6eeacf339c
22 changed files with 214 additions and 176 deletions

View File

@ -165,6 +165,10 @@ If you configure multiple HipChat accounts, you either need to set a default
HipChat account or specify which account the notification should be sent with
in the <<actions-hipchat, hipchat>> action.
deprecated[Storing the `auth_token` in the configuration file or using via updating the
settings now is deprecated, as you should use the keystore for this, see
<<secure-settings,secure settings>>]
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
@ -222,13 +226,17 @@ To configure a HipChat account that uses the `integration` profile:
For example, the following snippet configures an account called
`notify-monitoring` that sends messages to the `monitoring` room:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: integration
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
room: monitoring
--------------------------------------------------
@ -241,7 +249,6 @@ xpack.notification.hipchat:
account:
notify-monitoring:
profile: integration
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
room: monitoring
message:
format: text
@ -285,25 +292,33 @@ To configure a HipChat account that uses the `user` profile:
For example, the following configuration creates an account called
`notify-monitoring` that sends messages to the `monitoring` room:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: user
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
--------------------------------------------------
You can also specify defaults for the <{ref}/notification-settings.html#hipchat-account-attributes[
message attributes]:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: user
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
message:
format: text
color: blue
@ -349,13 +364,17 @@ To configure a HipChat account that uses the `v1` profile:
For example, the following configuration creates an account called
`notify-monitoring`:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: v1
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
--------------------------------------------------
You can also specify defaults for the {ref}/notification-settings.html#hipchat-account-attributes[
@ -367,7 +386,6 @@ xpack.notification.hipchat:
account:
notify-monitoring:
profile: v1
auth_token: 3eLB803Nyp7UBmegJwP1rMdUmzk5HqnzJCgflrhv
message:
format: text
color: blue

View File

@ -106,22 +106,22 @@ You configure the accounts {watcher} can use to communicate with Jira in the
`xpack.notification.jira` namespace in `elasticsearch.yml`.
{watcher} supports Basic Authentication for Jira Software. To configure a
Jira account you need to specify:
Jira account you need to specify (see <<secure-settings,secure settings>>):
[source,yaml]
--------------------------------------------------
xpack.notification.jira:
account:
monitoring:
url: https://internal-jira.elastic.co:443
user: B0A6D1PRD
password: mslNSCnJR
bin/elasticsearch-keystore xpack.notification.jira.account.monitoring.secure_url
bin/elasticsearch-keystore xpack.notification.jira.account.monitoring.secure_user
bin/elasticsearch-keystore xpack.notification.jira.account.monitoring.secure_password
--------------------------------------------------
deprecated[The insecure way of storing sensitive data (`url`, `user` and `password`)
in the configuration file or the cluster settings is deprecated]
To avoid credentials that transit in clear text over the network, {watcher} will
reject `url` settings like `http://internal-jira.elastic.co` that are based on
plain text HTTP protocol. This default behavior can be disabled with the explicit
`allow_http setting`:
`allow_http` setting:
NOTE: The `url` field can also contain a path, that is used to create an issue. By
default this is `/rest/api/2/issue`. If you set this as well, make sure that this
@ -132,10 +132,7 @@ path is the full path to the endpoint to create an issue.
xpack.notification.jira:
account:
monitoring:
url: http://unsecure-jira.elastic.co/
allow_http: true
user: B0A6D1PRD
password: mslNSCnJR
--------------------------------------------------
WARNING: It is strongly advised to use Basic Authentication with secured HTTPS
@ -149,9 +146,6 @@ You can also specify defaults for the
xpack.notification.jira:
account:
monitoring:
url: https://internal-jira.elastic.co:443
user: B0A6D1PRD
password: mslNSCnJR
issue_defaults:
project:
key: proj

View File

@ -145,17 +145,17 @@ image::images/pagerduty-services.jpg[]
+
image::images/pagerduty-integrations.jpg[]
To configure a PagerDuty account in `elasticsearch.yml`, at a minimum you
must specify an account name and integration key:
To configure a PagerDuty account in the keystore, you
must specify an account name and integration key, (see <<secure-settings,secure settings>>):
[source,yaml]
--------------------------------------------------
xpack.notification.pagerduty:
account:
my_pagerduty_account:
service_api_key: d3b07384d113edec49eaa6238ad5ff0
bin/elasticsearch-keystore add xpack.notification.pagerduty.account.my_pagerduty_account.secure_service_api_key
--------------------------------------------------
deprecated[Storing the service api key in the YAML file or via cluster
update settings is still supported, but the keystore setting should be used]
You can also specify defaults for the <<pagerduty-event-trigger-incident-attributes,
PagerDuty event attributes>>:
.
@ -165,7 +165,6 @@ PagerDuty event attributes>>:
xpack.notification.pagerduty:
account:
my_pagerduty_account:
service_api_key: d3b07384d113edec49eaa6238ad5ff0
event_defaults:
description: "Watch notification"
incident_key: "my_incident_key"

View File

@ -193,16 +193,16 @@ image::images/slack-add-webhook-integration.jpg[]
image::images/slack-copy-webhook-url.jpg[]
To configure a Slack account, at a minimum you need to specify the account
name and webhook URL:
name and webhook URL in the elasticsearch keystore (<<secure-settings,secure settings>>):
[source,yaml]
[source,shell]
--------------------------------------------------
xpack.notification.slack:
account:
monitoring:
url: https://hooks.slack.com/services/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
bin/elasticsearch-keystore add xpack.notification.slack.account.monitoring.secure_url
--------------------------------------------------
deprecated[You can also configure this via settings in the `elasticsearch.yml` file,
using the keystore is the preferred and secure way of doign this]
You can also specify defaults for the {ref}/notification-settings.html#slack-account-attributes[Slack
notification attributes]:
@ -211,7 +211,6 @@ notification attributes]:
xpack.notification.slack:
account:
monitoring:
url: https://hooks.slack.com/services/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
message_defaults:
from: x-pack
to: notifications

View File

@ -7,6 +7,9 @@ package org.elasticsearch.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.XContentParser;
@ -29,6 +32,8 @@ public abstract class HipChatAccount {
public static final String DEFAULT_COLOR_SETTING = "message_defaults." + HipChatMessage.Field.COLOR.getPreferredName();
public static final String DEFAULT_NOTIFY_SETTING = "message_defaults." + HipChatMessage.Field.NOTIFY.getPreferredName();
private static final Setting<SecureString> SECURE_AUTH_TOKEN_SETTING = SecureSetting.secureString("secure_" + AUTH_TOKEN_SETTING, null);
protected final Logger logger;
protected final String name;
protected final Profile profile;
@ -42,13 +47,23 @@ public abstract class HipChatAccount {
this.profile = profile;
this.server = new HipChatServer(settings, defaultServer);
this.httpClient = httpClient;
this.authToken = settings.get(AUTH_TOKEN_SETTING);
if (this.authToken == null || this.authToken.length() == 0) {
throw new SettingsException("hipchat account [" + name + "] missing required [" + AUTH_TOKEN_SETTING + "] setting");
}
this.authToken = getAuthToken(name, settings);
this.logger = logger;
}
private static String getAuthToken(String name, Settings settings) {
String authToken = settings.get(AUTH_TOKEN_SETTING);
if (authToken == null || authToken.length() == 0) {
SecureString secureString = SECURE_AUTH_TOKEN_SETTING.get(settings);
if (secureString == null || secureString.length() < 1) {
throw new SettingsException("hipchat account [" + name + "] missing required [" + AUTH_TOKEN_SETTING + "] setting");
}
authToken = secureString.toString();
}
return authToken;
}
public abstract String type();
public abstract void validateParsedTemplate(String watchId, String actionId, HipChatMessage.Template message) throws SettingsException;

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.notification.hipchat;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
@ -31,7 +32,13 @@ public class HipChatService extends NotificationService<HipChatAccount> {
private static final Setting.AffixSetting<String> SETTING_AUTH_TOKEN =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "auth_token",
(key) -> Setting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope, Setting.Property.Filtered));
(key) -> Setting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope, Setting.Property.Filtered,
Setting.Property.Deprecated));
private static final Setting.AffixSetting<String> SETTING_AUTH_TOKEN_SECURE =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "secure_auth_token",
(key) -> SecureSetting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope,
Setting.Property.Filtered));
private static final Setting.AffixSetting<String> SETTING_PROFILE =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "profile",
@ -66,6 +73,7 @@ public class HipChatService extends NotificationService<HipChatAccount> {
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_HOST, (s) -> {});
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_PORT, (s) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_AUTH_TOKEN, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_AUTH_TOKEN_SECURE, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_PROFILE, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_ROOM, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_HOST, (s, o) -> {}, (s, o) -> {});
@ -91,7 +99,7 @@ public class HipChatService extends NotificationService<HipChatAccount> {
}
public static List<Setting<?>> getSettings() {
return Arrays.asList(SETTING_DEFAULT_ACCOUNT, SETTING_AUTH_TOKEN, SETTING_PROFILE, SETTING_ROOM, SETTING_MESSAGE_DEFAULTS,
SETTING_DEFAULT_HOST, SETTING_DEFAULT_PORT, SETTING_HOST, SETTING_PORT);
return Arrays.asList(SETTING_DEFAULT_ACCOUNT, SETTING_AUTH_TOKEN, SETTING_AUTH_TOKEN_SECURE, SETTING_PROFILE, SETTING_ROOM,
SETTING_MESSAGE_DEFAULTS, SETTING_DEFAULT_HOST, SETTING_DEFAULT_PORT, SETTING_HOST, SETTING_PORT);
}
}

View File

@ -8,6 +8,10 @@ package org.elasticsearch.xpack.watcher.notification.jira;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
@ -45,6 +49,10 @@ public class JiraAccount {
static final String ISSUE_DEFAULTS_SETTING = "issue_defaults";
static final String ALLOW_HTTP_SETTING = "allow_http";
private static final Setting<SecureString> SECURE_USER_SETTING = SecureSetting.secureString("secure_" + USER_SETTING, null);
private static final Setting<SecureString> SECURE_PASSWORD_SETTING = SecureSetting.secureString("secure_" + PASSWORD_SETTING, null);
private static final Setting<SecureString> SECURE_URL_SETTING = SecureSetting.secureString("secure_" + URL_SETTING, null);
private final HttpClient httpClient;
private final String name;
private final String user;
@ -55,10 +63,8 @@ public class JiraAccount {
public JiraAccount(String name, Settings settings, HttpClient httpClient) {
this.httpClient = httpClient;
this.name = name;
String url = settings.get(URL_SETTING);
if (url == null) {
throw requiredSettingException(name, URL_SETTING);
}
String url = getSetting(name, URL_SETTING, settings, SECURE_URL_SETTING);
ESLoggerFactory.getLogger(getClass()).error("THE URL WAS [{}]", url);
try {
URI uri = new URI(url);
Scheme protocol = Scheme.parse(uri.getScheme());
@ -69,11 +75,11 @@ public class JiraAccount {
} catch (URISyntaxException | IllegalArgumentException e) {
throw new SettingsException("invalid jira [" + name + "] account settings. invalid [" + URL_SETTING + "] setting", e);
}
this.user = settings.get(USER_SETTING);
this.user = getSetting(name, USER_SETTING, settings, SECURE_USER_SETTING);
if (Strings.isEmpty(this.user)) {
throw requiredSettingException(name, USER_SETTING);
}
this.password = settings.get(PASSWORD_SETTING);
this.password = getSetting(name, PASSWORD_SETTING, settings, SECURE_PASSWORD_SETTING);
if (Strings.isEmpty(this.password)) {
throw requiredSettingException(name, PASSWORD_SETTING);
}
@ -91,6 +97,19 @@ public class JiraAccount {
}
}
private static String getSetting(String accountName, String settingName, Settings settings, Setting<SecureString> secureSetting) {
String value = settings.get(settingName);
if (value == null) {
SecureString secureString = secureSetting.get(settings);
if (secureString == null || secureString.length() < 1) {
throw requiredSettingException(accountName, settingName);
}
value = secureString.toString();
}
return value;
}
public String getName() {
return name;
}

View File

@ -31,7 +31,7 @@ public class JiraService extends NotificationService<JiraAccount> {
private static final Setting.AffixSetting<String> SETTING_URL =
Setting.affixKeySetting("xpack.notification.jira.account.", "url",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope));
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<String> SETTING_USER =
Setting.affixKeySetting("xpack.notification.jira.account.", "user",
@ -39,6 +39,18 @@ public class JiraService extends NotificationService<JiraAccount> {
private static final Setting.AffixSetting<String> SETTING_PASSWORD =
Setting.affixKeySetting("xpack.notification.jira.account.", "password",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered, Property.Deprecated));
private static final Setting.AffixSetting<String> SETTING_SECURE_USER =
Setting.affixKeySetting("xpack.notification.jira.account.", "secure_user",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<String> SETTING_SECURE_URL =
Setting.affixKeySetting("xpack.notification.jira.account.", "secure_url",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<String> SETTING_SECURE_PASSWORD =
Setting.affixKeySetting("xpack.notification.jira.account.", "secure_password",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<Settings> SETTING_DEFAULTS =
@ -57,6 +69,9 @@ public class JiraService extends NotificationService<JiraAccount> {
clusterSettings.addAffixUpdateConsumer(SETTING_URL, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_USER, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_PASSWORD, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SECURE_USER, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SECURE_URL, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SECURE_PASSWORD, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_DEFAULTS, (s, o) -> {}, (s, o) -> {});
// do an initial load
setAccountSetting(settings);
@ -68,6 +83,7 @@ public class JiraService extends NotificationService<JiraAccount> {
}
public static List<Setting<?>> getSettings() {
return Arrays.asList(SETTING_ALLOW_HTTP, SETTING_URL, SETTING_USER, SETTING_PASSWORD, SETTING_DEFAULTS, SETTING_DEFAULT_ACCOUNT);
return Arrays.asList(SETTING_ALLOW_HTTP, SETTING_URL, SETTING_USER, SETTING_PASSWORD, SETTING_SECURE_USER,
SETTING_SECURE_PASSWORD, SETTING_SECURE_URL, SETTING_DEFAULTS, SETTING_DEFAULT_ACCOUNT);
}
}

View File

@ -6,6 +6,9 @@
package org.elasticsearch.xpack.watcher.notification.pagerduty;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
@ -17,21 +20,20 @@ import java.io.IOException;
public class PagerDutyAccount {
public static final String SERVICE_KEY_SETTING = "service_api_key";
public static final String TRIGGER_DEFAULTS_SETTING = "event_defaults";
private static final String SERVICE_KEY_SETTING = "service_api_key";
private static final String TRIGGER_DEFAULTS_SETTING = "event_defaults";
private static final Setting<SecureString> SECURE_SERVICE_API_KEY_SETTING =
SecureSetting.secureString("secure_" + SERVICE_KEY_SETTING, null);
final String name;
final String serviceKey;
final HttpClient httpClient;
final IncidentEventDefaults eventDefaults;
final Logger logger;
private final String name;
private final String serviceKey;
private final HttpClient httpClient;
private final IncidentEventDefaults eventDefaults;
private final Logger logger;
public PagerDutyAccount(String name, Settings accountSettings, Settings serviceSettings, HttpClient httpClient, Logger logger) {
PagerDutyAccount(String name, Settings accountSettings, Settings serviceSettings, HttpClient httpClient, Logger logger) {
this.name = name;
this.serviceKey = accountSettings.get(SERVICE_KEY_SETTING, serviceSettings.get(SERVICE_KEY_SETTING, null));
if (this.serviceKey == null) {
throw new SettingsException("invalid pagerduty account [" + name + "]. missing required [" + SERVICE_KEY_SETTING + "] setting");
}
this.serviceKey = getServiceKey(name, accountSettings, serviceSettings);
this.httpClient = httpClient;
this.eventDefaults = new IncidentEventDefaults(accountSettings.getAsSettings(TRIGGER_DEFAULTS_SETTING));
@ -51,4 +53,18 @@ public class PagerDutyAccount {
HttpResponse response = httpClient.execute(request);
return SentEvent.responded(event, request, response);
}
private static String getServiceKey(String name, Settings accountSettings, Settings serviceSettings) {
String serviceKey = accountSettings.get(SERVICE_KEY_SETTING, serviceSettings.get(SERVICE_KEY_SETTING, null));
if (serviceKey == null) {
SecureString secureString = SECURE_SERVICE_API_KEY_SETTING.get(accountSettings);
if (secureString == null || secureString.length() < 1) {
throw new SettingsException("invalid pagerduty account [" + name + "]. missing required [" + SERVICE_KEY_SETTING +
"] setting");
}
serviceKey = secureString.toString();
}
return serviceKey;
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.notification.pagerduty;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
@ -25,7 +26,11 @@ public class PagerDutyService extends NotificationService<PagerDutyAccount> {
private static final Setting.AffixSetting<String> SETTING_SERVICE_API_KEY =
Setting.affixKeySetting("xpack.notification.pagerduty.account.", "service_api_key",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered, Property.Deprecated));
private static final Setting.AffixSetting<String> SETTING_SECURE_SERVICE_API_KEY =
Setting.affixKeySetting("xpack.notification.pagerduty.account.", "secure_service_api_key",
(key) -> SecureSetting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<Settings> SETTING_DEFAULTS =
Setting.affixKeySetting("xpack.notification.pagerduty.account.", "event_defaults",
@ -38,6 +43,7 @@ public class PagerDutyService extends NotificationService<PagerDutyAccount> {
this.httpClient = httpClient;
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_ACCOUNT, (s) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SERVICE_API_KEY, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_SECURE_SERVICE_API_KEY, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_DEFAULTS, (s, o) -> {}, (s, o) -> {});
setAccountSetting(settings);
}
@ -48,6 +54,6 @@ public class PagerDutyService extends NotificationService<PagerDutyAccount> {
}
public static List<Setting<?>> getSettings() {
return Arrays.asList(SETTING_SERVICE_API_KEY, SETTING_DEFAULTS, SETTING_DEFAULT_ACCOUNT);
return Arrays.asList(SETTING_SERVICE_API_KEY, SETTING_SECURE_SERVICE_API_KEY, SETTING_DEFAULTS, SETTING_DEFAULT_ACCOUNT);
}
}

View File

@ -6,6 +6,9 @@
package org.elasticsearch.xpack.watcher.notification.slack;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.ToXContent;
@ -29,9 +32,12 @@ import java.util.List;
public class SlackAccount {
public static final String URL_SETTING = "url";
public static final String MESSAGE_DEFAULTS_SETTING = "message_defaults";
private static final Setting<SecureString> SECURE_URL_SETTING = SecureSetting.secureString("secure_" + URL_SETTING, null);
final String name;
final URI url;
final HttpClient httpClient;
@ -116,6 +122,12 @@ public class SlackAccount {
static URI url(String name, Settings settings, Settings defaultSettings) {
String url = settings.get(URL_SETTING, defaultSettings.get(URL_SETTING, null));
if (url == null) {
SecureString secureStringUrl = SECURE_URL_SETTING.get(settings);
if (secureStringUrl != null && secureStringUrl.length() > 0) {
url = secureStringUrl.toString();
}
}
if (url == null) {
throw new SettingsException("invalid slack [" + name + "] account settings. missing required [" + URL_SETTING + "] setting");
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.notification.slack;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
@ -25,7 +26,11 @@ public class SlackService extends NotificationService<SlackAccount> {
private static final Setting.AffixSetting<String> SETTING_URL =
Setting.affixKeySetting("xpack.notification.slack.account.", "url",
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
(key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered, Property.Deprecated));
private static final Setting.AffixSetting<String> SETTING_URL_SECURE =
Setting.affixKeySetting("xpack.notification.slack.account.", "secure_url",
(key) -> SecureSetting.simpleString(key, Property.Dynamic, Property.NodeScope, Property.Filtered));
private static final Setting.AffixSetting<Settings> SETTING_DEFAULTS =
Setting.affixKeySetting("xpack.notification.slack.account.", "message_defaults",
@ -39,6 +44,7 @@ public class SlackService extends NotificationService<SlackAccount> {
clusterSettings.addSettingsUpdateConsumer(this::setAccountSetting, getSettings());
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_ACCOUNT, (s) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_URL, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_URL_SECURE, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_DEFAULTS, (s, o) -> {}, (s, o) -> {});
setAccountSetting(settings);
}
@ -49,6 +55,6 @@ public class SlackService extends NotificationService<SlackAccount> {
}
public static List<Setting<?>> getSettings() {
return Arrays.asList(SETTING_URL, SETTING_DEFAULT_ACCOUNT, SETTING_DEFAULTS);
return Arrays.asList(SETTING_URL, SETTING_URL_SECURE, SETTING_DEFAULT_ACCOUNT, SETTING_DEFAULTS);
}
}

View File

@ -108,25 +108,6 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
}
}
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2849")
public void testTcpReadTimeout() throws Exception {
Settings settings = Settings.builder()
.put(buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false))
.put("group_search.filter", "(objectClass=*)")
.put("ssl.verification_mode", VerificationMode.CERTIFICATE)
.put(SessionFactorySettings.TIMEOUT_TCP_READ_SETTING, "1ms")
.build();
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
PlainActionFuture<List<String>> groups = new PlainActionFuture<>();
session(sessionFactory, "ironman", SECURED_PASSWORD).groups(groups);
LDAPException expected = expectThrows(LDAPException.class, groups::actionGet);
assertThat(expected.getMessage(), containsString("A client-side timeout was encountered while waiting"));
}
}
public void testAdAuthAvengers() throws Exception {
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));

View File

@ -1,3 +1,5 @@
import org.elasticsearch.gradle.LoggedExec
apply plugin: 'elasticsearch.standalone-rest-test'
apply plugin: 'elasticsearch.rest-test'
@ -6,12 +8,9 @@ dependencies {
testCompile project(path: xpackModule('watcher'), configuration: 'runtime')
}
String integrationAccountPropertyName = 'xpack.notification.hipchat.auth_token_integration'
System.setProperty(integrationAccountPropertyName, 'huuS9v7ccuOy3ZBWWWr1vt8Lqu3sQnLUE81nrLZU')
String userAccountPropertyName = 'xpack.notification.hipchat.auth_token_user'
System.setProperty(userAccountPropertyName, '4UefsFLvKRw01EMN5vo3oyoY6BLiz7IQBQbGug8K')
String v1AccountPropertyName = 'xpack.notification.hipchat.auth_token_v1'
System.setProperty(v1AccountPropertyName, 'a734baf62df618b96dda55b323fc30')
String integrationAccount = System.getenv('hipchat_auth_token_integration')
String userAccount = System.getenv('hipchat_auth_token_user')
String v1Account = System.getenv('hipchat_auth_token_v1')
integTestCluster {
plugin xpackProject('plugin').path
@ -20,19 +19,15 @@ integTestCluster {
setting 'xpack.ml.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'logger.org.elasticsearch.xpack.watcher', 'DEBUG'
// hipchat
setting 'xpack.notification.hipchat.account.integration_account.profile', 'integration'
setting 'xpack.notification.hipchat.account.integration_account.room', 'test-watcher'
setting 'xpack.notification.hipchat.account.integration_account.auth_token', System.getProperty(integrationAccountPropertyName)
setting 'xpack.notification.hipchat.account.user_account.profile', 'user'
setting 'xpack.notification.hipchat.account.user_account.auth_token', System.getProperty(userAccountPropertyName)
setting 'xpack.notification.hipchat.account.v1_account.profile', 'v1'
setting 'xpack.notification.hipchat.account.v1_account.auth_token', System.getProperty(v1AccountPropertyName)
keystoreSetting 'xpack.notification.hipchat.account.integration_account.secure_auth_token', integrationAccount
keystoreSetting 'xpack.notification.hipchat.account.user_account.secure_auth_token', userAccount
keystoreSetting 'xpack.notification.hipchat.account.v1_account.secure_auth_token', v1Account
}
if (!System.getProperty(integrationAccountPropertyName) || !System.getProperty(userAccountPropertyName) ||
!System.getProperty(v1AccountPropertyName) || !System.getProperty('tests.network')) {
integTest.enabled = false
if (!integrationAccount && !userAccount && !v1Account) {
integTest.enabled = false
}

View File

@ -7,8 +7,6 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
@ -26,10 +24,9 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is;
/** Runs rest tests against external cluster */
@Network // Needed to access to an external Jira server
public class SmokeTestWatcherClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public class WatcherHipchatYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public SmokeTestWatcherClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public WatcherHipchatYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

View File

@ -12,17 +12,12 @@ dependencies {
}
ext {
jiraUrlPropertyName = 'xpack.notification.jira.url'
jiraUserPropertyName = 'xpack.notification.jira.user'
jiraPasswordPropertyName = 'xpack.notification.jira.password'
jiraProjectPropertyName = 'xpack.notification.jira.project'
jiraUrl = System.getenv('jira_url')
jiraUser = System.getenv('jira_user')
jiraPassword = System.getenv('jira_password')
jiraProject = System.getenv('jira_project')
}
System.setProperty(jiraUrlPropertyName, 'https://elasticsearch.atlassian.net/')
System.setProperty(jiraUserPropertyName, 'xpack-user@elastic.co')
System.setProperty(jiraPasswordPropertyName, 'N9M4ea9rfy')
System.setProperty(jiraProjectPropertyName, 'XWT')
integTestCluster {
plugin xpackProject('plugin').path
setting 'xpack.security.enabled', 'false'
@ -30,25 +25,17 @@ integTestCluster {
setting 'xpack.ml.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'logger.org.elasticsearch.xpack.watcher', 'DEBUG'
//
// JIRA integration test settings
//
// The integration tests use a JIRA account on elasticsearch.atlassian.net. This account
// has been created by Edward Sy [edward@elastic.co]. It uses the "XPACK WATCHER TEST"
// Jira project available at https://elasticsearch.atlassian.net/projects/XWT/issues/?filter=allopenissues
// and the "xpack-user@elastic.co" username which is also an internal Google Group.
setting 'xpack.notification.jira.account.test.url', System.getProperty(jiraUrlPropertyName)
setting 'xpack.notification.jira.account.test.user', System.getProperty(jiraUserPropertyName)
setting 'xpack.notification.jira.account.test.password', System.getProperty(jiraPasswordPropertyName)
setting 'xpack.notification.jira.account.test.issue_defaults.project.key', System.getProperty(jiraProjectPropertyName)
setting 'xpack.notification.jira.account.test.issue_defaults.labels', ['integration-tests', project.version]
keystoreSetting 'xpack.notification.jira.account.test.secure_url', jiraUrl
keystoreSetting 'xpack.notification.jira.account.test.secure_user', jiraUser
keystoreSetting 'xpack.notification.jira.account.test.secure_password', jiraPassword
setting 'xpack.notification.jira.account.test.issue_defaults.project.key', jiraProject
setting 'xpack.notification.jira.account.test.issue_defaults.issuetype.name', 'Bug'
setting 'xpack.notification.jira.account.test.issue_defaults.labels.0', 'integration-tests'
}
/** Clean up JIRA after tests: delete all created issues **/
task cleanJira(type: DefaultTask) {
doLast {
def issues = jiraIssues(System.getProperty(jiraProjectPropertyName))
List<String> issues = jiraIssues(jiraProject)
assert issues instanceof List
issues.forEach {
// See https://docs.atlassian.com/jira/REST/cloud/#api/2/issue-deleteIssue
@ -59,9 +46,7 @@ task cleanJira(type: DefaultTask) {
}
// require network access for this one, exit early instead of starting up the cluster if we dont have network
if (!System.getProperty(jiraUrlPropertyName) || !System.getProperty(jiraUserPropertyName) ||
!System.getProperty(jiraPasswordPropertyName) || !System.getProperty(jiraProjectPropertyName) ||
!System.getProperty('tests.network')) {
if (!jiraUrl && !jiraUser && !jiraPassword && !jiraProject) {
integTest.enabled = false
} else {
integTestRunner.finalizedBy cleanJira
@ -79,9 +64,6 @@ def jiraIssues(projectKey) {
def jiraHttpRequest(String endpoint, String method, int successCode) {
HttpsURLConnection connection = null;
try {
def jiraUser = System.getProperty(jiraUserPropertyName)
def jiraPassword = System.getProperty(jiraPasswordPropertyName)
def jiraUrl = System.getProperty(jiraUrlPropertyName)
byte[] credentials = "${jiraUser}:${jiraPassword}".getBytes(StandardCharsets.UTF_8);
connection = (HttpsURLConnection) new URL("${jiraUrl}/rest/api/2/${endpoint}").openConnection();
connection.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(credentials));

View File

@ -7,8 +7,6 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
@ -26,10 +24,9 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is;
/** Runs rest tests against external cluster */
@Network // Needed to access to an external Jira server
public class SmokeTestWatcherClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public class WatcherJiraYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public SmokeTestWatcherClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public WatcherJiraYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

View File

@ -210,7 +210,7 @@
- match: { hits.hits.0._source.result.actions.0.jira.reason: "Bad Request - ThrottlerField [issuetype] has error [issue type is required]\n" }
- match: { hits.hits.0._source.result.actions.0.jira.request.method: "post" }
- match: { hits.hits.0._source.result.actions.0.jira.request.path: "/rest/api/2/issue" }
- match: { hits.hits.0._source.result.actions.0.jira.request.auth.basic.username: "xpack-user@elastic.co" }
- is_true: hits.hits.0._source.result.actions.0.jira.request.auth.basic.username
- match: { hits.hits.0._source.result.actions.0.jira.request.auth.basic.password: "::es_redacted::" }
- match: { hits.hits.0._source.result.actions.0.jira.response.body: "{\"errorMessages\":[],\"errors\":{\"issuetype\":\"issue type is required\"}}" }

View File

@ -6,20 +6,7 @@ dependencies {
testCompile project(path: xpackModule('watcher'), configuration: 'runtime')
}
String pagerDutyPropertyName = 'xpack.notification.pagerduty.service_api_key'
System.setProperty(pagerDutyPropertyName, 'fc082467005d4072a914e0bb041882d0')
ext {
jiraUrl = 'https://elasticsearch.atlassian.net/'
jiraUser = 'xpack-user@elastic.co'
jiraPassword = 'N9M4ea9rfy'
jiraProject = 'XWT'
slackUrl = 'https://hooks.slack.com/services/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'
pagerDutyUrl = 'fc082467005d4072a914e0bb041882d0'
hipchatUserAuthToken = '4UefsFLvKRw01EMN5vo3oyoY6BLiz7IQBQbGug8K'
hipchatIntegrationAuthToken = 'huuS9v7ccuOy3ZBWWWr1vt8Lqu3sQnLUE81nrLZU'
hipchatV1AuthToken = 'a734baf62df618b96dda55b323fc30'
}
String pagerDutyServiceKey = System.getenv('pagerduty_service_api_key')
integTestCluster {
plugin xpackProject('plugin').path
@ -28,12 +15,9 @@ integTestCluster {
setting 'xpack.ml.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'logger.org.elasticsearch.xpack.watcher', 'DEBUG'
// pagerduty
setting 'xpack.notification.pagerduty.account.test_account.service_api_key', System.getProperty(pagerDutyPropertyName)
keystoreSetting 'xpack.notification.pagerduty.account.test_account.secure_service_api_key', pagerDutyServiceKey
}
// require network access for this one, exit early instead of starting up the cluster if we dont have network
if (!System.getProperty(pagerDutyPropertyName) || !System.getProperty('tests.network')) {
if (!pagerDutyServiceKey) {
integTest.enabled = false
}

View File

@ -7,8 +7,6 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
@ -26,10 +24,9 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is;
/** Runs rest tests against external cluster */
@Network // Needed to access to an external Jira server
public class SmokeTestWatcherClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public class WatcherPagerDutyYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public SmokeTestWatcherClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public WatcherPagerDutyYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

View File

@ -1,3 +1,6 @@
import org.elasticsearch.gradle.test.NodeInfo
import org.elasticsearch.gradle.LoggedExec
apply plugin: 'elasticsearch.standalone-rest-test'
apply plugin: 'elasticsearch.rest-test'
@ -6,8 +9,7 @@ dependencies {
testCompile project(path: xpackModule('watcher'), configuration: 'runtime')
}
String slackPropertyName = 'xpack.notification.slack.url'
System.setProperty(slackPropertyName, 'https://hooks.slack.com/services/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')
String slackUrl = System.getenv('slack_url')
integTestCluster {
plugin xpackProject('plugin').path
@ -16,11 +18,9 @@ integTestCluster {
setting 'xpack.ml.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'logger.org.elasticsearch.xpack.watcher', 'DEBUG'
setting 'xpack.notification.slack.account.test_account.url', System.getProperty(slackPropertyName)
keystoreSetting 'xpack.notification.slack.account.test_account.secure_url', slackUrl
}
// require network access for this one, exit early instead of starting up the cluster if we dont have network
if (!System.getProperty(slackPropertyName) || !System.getProperty('tests.network')) {
integTest.enabled = false
if (!slackUrl) {
integTest.enabled = false
}

View File

@ -7,8 +7,6 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
@ -26,10 +24,9 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is;
/** Runs rest tests against external cluster */
@Network // Needed to access to an external Jira server
public class SmokeTestWatcherClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public class WatcherSlackYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public SmokeTestWatcherClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public WatcherSlackYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}