security: validate that security and audit indices can be auto created
Adds a check to the settings at startup to ensure that the security and audit indices are allowed to be auto created if a user has disabled auto create explicitly. Additionally fixes a small issue with the error message for watcher passing the incorrect value. Closes elastic/elasticsearch#1453 Original commit: elastic/x-pack-elasticsearch@2b0698ff19
This commit is contained in:
parent
03336912bb
commit
edc9580f66
|
@ -6,11 +6,15 @@
|
|||
package org.elasticsearch.shield;
|
||||
|
||||
import org.elasticsearch.action.ActionModule;
|
||||
import org.elasticsearch.common.Booleans;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.component.LifecycleComponent;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.LoggerMessageFormat;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
|
@ -35,6 +39,8 @@ import org.elasticsearch.shield.action.user.TransportPutUserAction;
|
|||
import org.elasticsearch.shield.action.user.TransportDeleteUserAction;
|
||||
import org.elasticsearch.shield.action.user.TransportGetUsersAction;
|
||||
import org.elasticsearch.shield.audit.AuditTrailModule;
|
||||
import org.elasticsearch.shield.audit.index.IndexAuditTrail;
|
||||
import org.elasticsearch.shield.audit.index.IndexNameResolver;
|
||||
import org.elasticsearch.shield.audit.logfile.LoggingAuditTrail;
|
||||
import org.elasticsearch.shield.authc.AuthenticationModule;
|
||||
import org.elasticsearch.shield.authc.Realms;
|
||||
|
@ -71,6 +77,8 @@ import org.elasticsearch.shield.transport.filter.IPFilter;
|
|||
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -102,6 +110,7 @@ public class Shield {
|
|||
this.enabled = XPackPlugin.featureEnabled(settings, NAME, true);
|
||||
if (enabled && !transportClientMode) {
|
||||
failIfShieldQueryCacheIsNotActive(settings, true);
|
||||
validateAutoCreateIndex(settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,4 +419,72 @@ public class Shield {
|
|||
.INDEX_QUERY_CACHE_TYPE_SETTING.getKey() + "] with value [" + queryCacheImplementation + "]");
|
||||
}
|
||||
}
|
||||
|
||||
static void validateAutoCreateIndex(Settings settings) {
|
||||
String value = settings.get("action.auto_create_index");
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean indexAuditingEnabled = AuditTrailModule.indexAuditLoggingEnabled(settings);
|
||||
final String auditIndex = indexAuditingEnabled ? "," + IndexAuditTrail.INDEX_NAME_PREFIX + "*" : "";
|
||||
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
|
||||
" restrictive. disable [action.auto_create_index] or set it to " +
|
||||
"[{}{}]", (Object) value, ShieldTemplateService.SECURITY_INDEX_NAME, auditIndex);
|
||||
if (Booleans.isExplicitFalse(value)) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
if (Booleans.isExplicitTrue(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] matches = Strings.commaDelimitedListToStringArray(value);
|
||||
List<String> indices = new ArrayList<>();
|
||||
indices.add(ShieldTemplateService.SECURITY_INDEX_NAME);
|
||||
if (indexAuditingEnabled) {
|
||||
DateTime now = new DateTime(DateTimeZone.UTC);
|
||||
// just use daily rollover
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now, IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusDays(1), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(1), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(2), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(3), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(4), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(5), IndexNameResolver.Rollover.DAILY));
|
||||
indices.add(IndexNameResolver.resolve(IndexAuditTrail.INDEX_NAME_PREFIX, now.plusMonths(6), IndexNameResolver.Rollover.DAILY));
|
||||
}
|
||||
|
||||
for (String index : indices) {
|
||||
boolean matched = false;
|
||||
for (String match : matches) {
|
||||
char c = match.charAt(0);
|
||||
if (c == '-') {
|
||||
if (Regex.simpleMatch(match.substring(1), index)) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
} else if (c == '+') {
|
||||
if (Regex.simpleMatch(match.substring(1), index)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (Regex.simpleMatch(match, index)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexAuditingEnabled) {
|
||||
logger.warn("the [action.auto_create_index] setting is configured to be restrictive [{}]. " +
|
||||
" for the next 6 months audit indices are allowed to be created, but please make sure" +
|
||||
" that any future history indices after 6 months with the pattern " +
|
||||
"[.shield_audit_log*] are allowed to be created", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.shield;
|
|||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.shield.audit.index.IndexAuditTrail;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
||||
|
@ -16,6 +17,7 @@ import static org.hamcrest.CoreMatchers.is;
|
|||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
public class ShieldPluginSettingsTests extends ESTestCase {
|
||||
|
||||
|
@ -132,4 +134,59 @@ public class ShieldPluginSettingsTests extends ESTestCase {
|
|||
assertThat(additionalSettings.get("tribe.t2.shield.bar"), is("foo"));
|
||||
assertThat(additionalSettings.getAsArray("tribe.t2.shield.something.else.here"), arrayContaining("foo", "bar"));
|
||||
}
|
||||
|
||||
public void testValidAutoCreateIndex() {
|
||||
Shield.validateAutoCreateIndex(Settings.EMPTY);
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", true).build());
|
||||
|
||||
try {
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString(ShieldTemplateService.SECURITY_INDEX_NAME));
|
||||
assertThat(e.getMessage(), not(containsString(IndexAuditTrail.INDEX_NAME_PREFIX)));
|
||||
}
|
||||
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".security").build());
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "*s*").build());
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".s*").build());
|
||||
|
||||
try {
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", "foo").build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString(ShieldTemplateService.SECURITY_INDEX_NAME));
|
||||
assertThat(e.getMessage(), not(containsString(IndexAuditTrail.INDEX_NAME_PREFIX)));
|
||||
}
|
||||
|
||||
try {
|
||||
Shield.validateAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".shield_audit_log*").build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString(ShieldTemplateService.SECURITY_INDEX_NAME));
|
||||
}
|
||||
|
||||
Shield.validateAutoCreateIndex(Settings.builder()
|
||||
.put("action.auto_create_index", ".security")
|
||||
.put("shield.audit.enabled", true)
|
||||
.build());
|
||||
|
||||
try {
|
||||
Shield.validateAutoCreateIndex(Settings.builder()
|
||||
.put("action.auto_create_index", ".security")
|
||||
.put("shield.audit.enabled", true)
|
||||
.put("shield.audit.outputs", randomFrom("index", "logfile,index"))
|
||||
.build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString(ShieldTemplateService.SECURITY_INDEX_NAME));
|
||||
assertThat(e.getMessage(), containsString(IndexAuditTrail.INDEX_NAME_PREFIX));
|
||||
}
|
||||
|
||||
Shield.validateAutoCreateIndex(Settings.builder()
|
||||
.put("action.auto_create_index", ".shield_audit_log*,.security")
|
||||
.put("shield.audit.enabled", true)
|
||||
.put("shield.audit.outputs", randomFrom("index", "logfile,index"))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ public class Watcher {
|
|||
|
||||
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
|
||||
" restrictive. disable [action.auto_create_index] or set it to " +
|
||||
"[.watches,.triggered_watches,.watcher-history*]", (Object) settings);
|
||||
"[.watches,.triggered_watches,.watcher-history*]", (Object) value);
|
||||
if (Booleans.isExplicitFalse(value)) {
|
||||
throw new IllegalArgumentException(errorMessage);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.elasticsearch.watcher;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class WatcherPluginTests extends ESTestCase {
|
||||
|
||||
public void testValidAutoCreateIndex() {
|
||||
|
@ -17,6 +19,7 @@ public class WatcherPluginTests extends ESTestCase {
|
|||
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
|
||||
}
|
||||
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index",
|
||||
".watches,.triggered_watches,.watcher-history*").build());
|
||||
|
@ -26,16 +29,19 @@ public class WatcherPluginTests extends ESTestCase {
|
|||
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watches").build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
|
||||
}
|
||||
try {
|
||||
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".triggered_watch").build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
|
||||
}
|
||||
try {
|
||||
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watcher-history*").build());
|
||||
fail("IllegalArgumentException expected");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue