Skip to content

Commit

Permalink
Logfile audit settings validation (elastic#52537)
Browse files Browse the repository at this point in the history
Add validation for the following logfile audit settings:

    xpack.security.audit.logfile.events.include
    xpack.security.audit.logfile.events.exclude
    xpack.security.audit.logfile.events.ignore_filters.*.users
    xpack.security.audit.logfile.events.ignore_filters.*.realms
    xpack.security.audit.logfile.events.ignore_filters.*.roles
    xpack.security.audit.logfile.events.ignore_filters.*.indices

Closes elastic#52357
Relates elastic#47711 elastic#47038
Follows the example from elastic#47246
  • Loading branch information
albertzaharovits committed Feb 24, 2020
1 parent f3cbeea commit a7da064
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,33 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
ANONYMOUS_ACCESS_DENIED.toString(), AUTHENTICATION_FAILED.toString(), CONNECTION_DENIED.toString(), TAMPERED_REQUEST.toString(),
RUN_AS_DENIED.toString(), RUN_AS_GRANTED.toString());
public static final Setting<List<String>> INCLUDE_EVENT_SETTINGS = Setting.listSetting(setting("audit.logfile.events.include"),
DEFAULT_EVENT_INCLUDES, Function.identity(), Property.NodeScope, Property.Dynamic);
DEFAULT_EVENT_INCLUDES, Function.identity(), value -> AuditLevel.parse(value, List.of()),
Property.NodeScope, Property.Dynamic);
public static final Setting<List<String>> EXCLUDE_EVENT_SETTINGS = Setting.listSetting(setting("audit.logfile.events.exclude"),
Collections.emptyList(), Function.identity(), Property.NodeScope, Property.Dynamic);
Collections.emptyList(), Function.identity(), value -> AuditLevel.parse(List.of(), value),
Property.NodeScope, Property.Dynamic);
public static final Setting<Boolean> INCLUDE_REQUEST_BODY = Setting.boolSetting(setting("audit.logfile.events.emit_request_body"),
false, Property.NodeScope, Property.Dynamic);
public static final String FILTER_POLICY_PREFIX = setting("audit.logfile.events.ignore_filters.");
// because of the default wildcard value (*) for the field filter, a policy with
// an unspecified filter field will match events that have any value for that
// particular field, as well as events with that particular field missing
public static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_PRINCIPALS = Setting.affixKeySetting(FILTER_POLICY_PREFIX,
"users",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), Property.NodeScope, Property.Dynamic));
public static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_REALMS = Setting.affixKeySetting(FILTER_POLICY_PREFIX,
"realms",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), Property.NodeScope, Property.Dynamic));
public static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_ROLES = Setting.affixKeySetting(FILTER_POLICY_PREFIX,
"roles",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), Property.NodeScope, Property.Dynamic));
public static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_INDICES = Setting.affixKeySetting(FILTER_POLICY_PREFIX,
"indices",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_PRINCIPALS =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "users",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_REALMS =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "realms",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_ROLES =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "roles",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));
protected static final Setting.AffixSetting<List<String>> FILTER_POLICY_IGNORE_INDICES =
Setting.affixKeySetting(FILTER_POLICY_PREFIX, "indices",
(key) -> Setting.listSetting(key, Collections.singletonList("*"), Function.identity(),
value -> EventFilterPolicy.parsePredicate(value), Property.NodeScope, Property.Dynamic));

private static final Marker AUDIT_MARKER = MarkerManager.getMarker("org.elasticsearch.xpack.security.audit");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public void testInvalidFilterSettings() throws Exception {
settingsBuilder.put(randomFrom(allSettingsKeys), invalidLuceneRegex);
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> client().admin().cluster().prepareUpdateSettings().setTransientSettings(settingsBuilder.build()).get());
assertThat(e.getMessage(), containsString("illegal value can't update"));
assertThat(e.getMessage(), containsString("invalid pattern [/invalid]"));
}

public void testDynamicHostSettings() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
import java.util.regex.Pattern;

import static org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail.PRINCIPAL_ROLES_FIELD_NAME;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
Expand Down Expand Up @@ -206,6 +209,54 @@ public void clearLog() throws Exception {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
}

public void testEventsSettingValidation() {
final String prefix = "xpack.security.audit.logfile.events.";
Settings settings = Settings.builder().putList(prefix + "include", Arrays.asList("access_granted", "bogus")).build();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.INCLUDE_EVENT_SETTINGS.get(settings));
assertThat(e, hasToString(containsString("invalid event name specified [bogus]")));

Settings settings2 = Settings.builder().putList(prefix + "exclude", Arrays.asList("access_denied", "foo")).build();
e = expectThrows(IllegalArgumentException.class, () -> LoggingAuditTrail.EXCLUDE_EVENT_SETTINGS.get(settings2));
assertThat(e, hasToString(containsString("invalid event name specified [foo]")));
}

public void testAuditFilterSettingValidation() {
final String prefix = "xpack.security.audit.logfile.events.";
Settings settings =
Settings.builder().putList(prefix + "ignore_filters.filter1.users", Arrays.asList("mickey", "/bogus")).build();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace("filter1").get(settings));
assertThat(e, hasToString(containsString("invalid pattern [/bogus]")));

Settings settings2 = Settings.builder()
.putList(prefix + "ignore_filters.filter2.users", Arrays.asList("tom", "cruise"))
.putList(prefix + "ignore_filters.filter2.realms", Arrays.asList("native", "/foo")).build();
assertThat(LoggingAuditTrail.FILTER_POLICY_IGNORE_PRINCIPALS.getConcreteSettingForNamespace("filter2").get(settings2),
containsInAnyOrder("tom", "cruise"));
e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace("filter2").get(settings2));
assertThat(e, hasToString(containsString("invalid pattern [/foo]")));

Settings settings3 = Settings.builder()
.putList(prefix + "ignore_filters.filter3.realms", Arrays.asList("native", "oidc1"))
.putList(prefix + "ignore_filters.filter3.roles", Arrays.asList("kibana", "/wrong")).build();
assertThat(LoggingAuditTrail.FILTER_POLICY_IGNORE_REALMS.getConcreteSettingForNamespace("filter3").get(settings3),
containsInAnyOrder("native", "oidc1"));
e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace("filter3").get(settings3));
assertThat(e, hasToString(containsString("invalid pattern [/wrong]")));

Settings settings4 = Settings.builder()
.putList(prefix + "ignore_filters.filter4.roles", Arrays.asList("kibana", "elastic"))
.putList(prefix + "ignore_filters.filter4.indices", Arrays.asList("index-1", "/no-inspiration")).build();
assertThat(LoggingAuditTrail.FILTER_POLICY_IGNORE_ROLES.getConcreteSettingForNamespace("filter4").get(settings4),
containsInAnyOrder("kibana", "elastic"));
e = expectThrows(IllegalArgumentException.class,
() -> LoggingAuditTrail.FILTER_POLICY_IGNORE_INDICES.getConcreteSettingForNamespace("filter4").get(settings4));
assertThat(e, hasToString(containsString("invalid pattern [/no-inspiration]")));
}

public void testAnonymousAccessDeniedTransport() throws Exception {
final TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);

Expand Down

0 comments on commit a7da064

Please sign in to comment.