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:
jaymode 2016-03-15 10:06:54 -04:00
parent 03336912bb
commit edc9580f66
4 changed files with 141 additions and 1 deletions

View File

@ -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);
}
}
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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*]"));
}
}