Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional ignore_headers audit configuration setting #3885

Merged
merged 16 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class AuditFilters implements ToXContentObject {

private List<String> ignoreRequests;

private List<String> ignoreHeaders;

private List<String> disabledRestCategories;

private List<String> disabledTransportCategories;
Expand All @@ -49,6 +51,7 @@ public AuditFilters() {

this.ignoreUsers = Collections.emptyList();
this.ignoreRequests = Collections.emptyList();
this.ignoreHeaders = Collections.emptyList();
this.disabledRestCategories = Collections.emptyList();
this.disabledTransportCategories = Collections.emptyList();
}
Expand Down Expand Up @@ -93,6 +96,11 @@ public AuditFilters ignoreRequests(List<String> ignoreRequests) {
return this;
}

public AuditFilters ignoreHeaders(List<String> ignoreHeaders) {
this.ignoreHeaders = ignoreHeaders;
return this;
}

public AuditFilters disabledRestCategories(List<String> disabledRestCategories) {
this.disabledRestCategories = disabledRestCategories;
return this;
Expand All @@ -114,6 +122,7 @@ public XContentBuilder toXContent(XContentBuilder xContentBuilder, Params params
xContentBuilder.field("exclude_sensitive_headers", excludeSensitiveHeaders);
xContentBuilder.field("ignore_users", ignoreUsers);
xContentBuilder.field("ignore_requests", ignoreRequests);
xContentBuilder.field("ignore_headers", ignoreHeaders);
xContentBuilder.field("disabled_rest_categories", disabledRestCategories);
xContentBuilder.field("disabled_transport_categories", disabledTransportCategories);
xContentBuilder.endObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,15 @@ public List<Setting<?>> getSettings() {
Function.identity(),
Property.NodeScope
)
); // not filtered here
);
settings.add(
Setting.listSetting(
ConfigConstants.SECURITY_AUDIT_IGNORE_HEADERS,
Collections.emptyList(),
Function.identity(),
Property.NodeScope
)
);// not filtered here
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
settings.add(
Setting.boolSetting(
ConfigConstants.OPENDISTRO_SECURITY_AUDIT_RESOLVE_BULK_REQUESTS,
Expand Down Expand Up @@ -1393,6 +1401,7 @@ public List<Setting<?>> getSettings() {
Property.NodeScope
);
case IGNORE_REQUESTS:
case IGNORE_HEADERS:
return Setting.listSetting(
filterEntry.getKeyWithNamespace(),
Collections.emptyList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
* "ignore_users" : [
* "kibanaserver"
* ],
* "ignore_requests" : [ ]
* "ignore_requests" : [ ],
* "ignore_headers" : [ ],
* },
* "compliance" : {
* "enabled": true,
Expand All @@ -82,6 +83,7 @@
public class AuditConfig {

public static final List<String> DEFAULT_IGNORED_USERS = Collections.singletonList("kibanaserver");

private static Set<String> FIELDS = DefaultObjectMapper.getFields(AuditConfig.class);

private AuditConfig() {
Expand Down Expand Up @@ -138,8 +140,11 @@ public static class Filter {
private final Set<String> ignoredAuditUsers;
@JsonProperty("ignore_requests")
private final Set<String> ignoredAuditRequests;
@JsonProperty("ignore_headers")
private final Set<String> ignoredCustomHeaders;
private final WildcardMatcher ignoredAuditUsersMatcher;
private final WildcardMatcher ignoredAuditRequestsMatcher;
private final WildcardMatcher ignoredCustomHeadersMatcher;
private final Set<AuditCategory> disabledRestCategories;
private final Set<AuditCategory> disabledTransportCategories;

Expand All @@ -153,6 +158,7 @@ public static class Filter {
final boolean excludeSensitiveHeaders,
final Set<String> ignoredAuditUsers,
final Set<String> ignoredAuditRequests,
final Set<String> ignoredCustomHeaders,
final Set<AuditCategory> disabledRestCategories,
final Set<AuditCategory> disabledTransportCategories
) {
Expand All @@ -166,6 +172,8 @@ public static class Filter {
this.ignoredAuditUsersMatcher = WildcardMatcher.from(ignoredAuditUsers);
this.ignoredAuditRequests = ignoredAuditRequests;
this.ignoredAuditRequestsMatcher = WildcardMatcher.from(ignoredAuditRequests);
this.ignoredCustomHeaders = ignoredCustomHeaders;
this.ignoredCustomHeadersMatcher = WildcardMatcher.from(ignoredCustomHeaders);
this.disabledRestCategories = disabledRestCategories;
this.disabledTransportCategories = disabledTransportCategories;
}
Expand All @@ -183,7 +191,8 @@ public enum FilterEntries {
ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_TRANSPORT_CATEGORIES
),
IGNORE_USERS("ignore_users", ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_USERS),
IGNORE_REQUESTS("ignore_requests", ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_REQUESTS);
IGNORE_REQUESTS("ignore_requests", ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_REQUESTS),
IGNORE_HEADERS("ignore_headers", ConfigConstants.SECURITY_AUDIT_IGNORE_HEADERS);

private final String key;
private final String legacyKeyWithNamespace;
Expand Down Expand Up @@ -246,6 +255,9 @@ public static Filter from(Map<String, Object> properties) throws JsonProcessingE
final Set<String> ignoreAuditRequests = ImmutableSet.copyOf(
getOrDefault(properties, FilterEntries.IGNORE_REQUESTS.getKey(), Collections.emptyList())
);
final Set<String> ignoreHeaders = ImmutableSet.copyOf(
getOrDefault(properties, FilterEntries.IGNORE_HEADERS.getKey(), Collections.emptyList())
);

return new Filter(
isRestApiAuditEnabled,
Expand All @@ -256,6 +268,7 @@ public static Filter from(Map<String, Object> properties) throws JsonProcessingE
excludeSensitiveHeaders,
ignoredAuditUsers,
ignoreAuditRequests,
ignoreHeaders,
disabledRestCategories,
disabledTransportCategories
);
Expand Down Expand Up @@ -290,7 +303,7 @@ public static Filter from(Settings settings) {
);
final Set<String> ignoredAuditUsers = fromSettingStringSet(settings, FilterEntries.IGNORE_USERS, DEFAULT_IGNORED_USERS);
final Set<String> ignoreAuditRequests = fromSettingStringSet(settings, FilterEntries.IGNORE_REQUESTS, Collections.emptyList());

final Set<String> ignoreHeaders = fromSettingStringSet(settings, FilterEntries.IGNORE_HEADERS, Collections.emptyList());
return new Filter(
isRestApiAuditEnabled,
isTransportAuditEnabled,
Expand All @@ -300,6 +313,7 @@ public static Filter from(Settings settings) {
excludeSensitiveHeaders,
ignoredAuditUsers,
ignoreAuditRequests,
ignoreHeaders,
disabledRestCategories,
disabledTransportCategories
);
Expand Down Expand Up @@ -403,6 +417,21 @@ WildcardMatcher getIgnoredAuditRequestsMatcher() {
return ignoredAuditRequestsMatcher;
}

@VisibleForTesting
WildcardMatcher getIgnoredCustomHeadersMatcher() {
return ignoredCustomHeadersMatcher;
}

/**
* Check if the specified header is excluded from the audit
*
* @param header
* @return true if header should be excluded
*/
public boolean isHeaderDisabled(String header) {
return ignoredCustomHeadersMatcher.test(header);
}

/**
* Check if request is excluded from audit
* @param action
Expand Down Expand Up @@ -440,6 +469,7 @@ public void log(Logger logger) {
logger.info("Index resolution is {} during request auditing.", resolveIndices ? "enabled" : "disabled");
logger.info("Sensitive headers auditing is {}.", excludeSensitiveHeaders ? "enabled" : "disabled");
logger.info("Auditing requests from {} users is disabled.", ignoredAuditUsersMatcher);
logger.info("Auditing request headers {} is disabled.", ignoredCustomHeadersMatcher);
}

@Override
Expand All @@ -465,6 +495,8 @@ public String toString() {
+ ignoredAuditUsersMatcher
+ ", ignoreAuditRequests="
+ ignoredAuditRequestsMatcher
+ ", ignoredCustomHeaders="
+ ignoredCustomHeadersMatcher
+ '}';
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -927,11 +927,6 @@ boolean checkRestFilter(final AuditCategory category, final String effectiveUser
}
return false;
}

// check rest audit enabled
// check category enabled
// check action
// check ignoreAuditUsers
}

protected abstract void save(final AuditMessage msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,15 @@ public void addRestParams(Map<String, String> params) {
}
}

public void addRestHeaders(Map<String, List<String>> headers, boolean excludeSensitiveHeaders) {
public void addRestHeaders(Map<String, List<String>> headers, boolean excludeSensitiveHeaders, AuditConfig.Filter filter) {
if (headers != null && !headers.isEmpty()) {
final Map<String, List<String>> headersClone = new HashMap<>(headers);
if (excludeSensitiveHeaders) {
headersClone.keySet().removeIf(AUTHORIZATION_HEADER);
}
if (filter != null) {
headersClone.entrySet().removeIf(entry -> filter.isHeaderDisabled(entry.getKey()));
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
}
auditInfo.put(REST_REQUEST_HEADERS, headersClone);
}
}
Expand All @@ -376,14 +379,14 @@ void addRestRequestInfo(final SecurityRequest request, final AuditConfig.Filter
if (request != null) {
final String path = request.path().toString();
addPath(path);
addRestHeaders(request.getHeaders(), filter.shouldExcludeSensitiveHeaders());
addRestHeaders(request.getHeaders(), filter.shouldExcludeSensitiveHeaders(), filter);
addRestParams(request.params());
addRestMethod(request.method());

if (filter.shouldLogRequestBody()) {

if (!(request instanceof OpenSearchRequest)) {
// The request body is only avaliable on some request sources
// The request body is only available on some request sources
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ public static ComplianceConfig from(Map<String, Object> properties, @JacksonInje
final Set<String> ignoredComplianceUsersForRead = ImmutableSet.copyOf(
getOrDefault(properties, "read_ignore_users", AuditConfig.DEFAULT_IGNORED_USERS)
);

stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
final boolean logWriteMetadataOnly = getOrDefault(properties, "write_metadata_only", false);
final boolean logDiffsForWrite = getOrDefault(properties, "write_log_diffs", false);
final List<String> watchedWriteIndicesPatterns = getOrDefault(properties, "write_watched_indices", Collections.emptyList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ public class ConfigConstants {
);
public static final String OPENDISTRO_SECURITY_AUDIT_IGNORE_USERS = "opendistro_security.audit.ignore_users";
public static final String OPENDISTRO_SECURITY_AUDIT_IGNORE_REQUESTS = "opendistro_security.audit.ignore_requests";
public static final String SECURITY_AUDIT_IGNORE_HEADERS = "plugins.security.audit.ignore_headers";
public static final String OPENDISTRO_SECURITY_AUDIT_RESOLVE_BULK_REQUESTS = "opendistro_security.audit.resolve_bulk_requests";
public static final boolean OPENDISTRO_SECURITY_AUDIT_SSL_VERIFY_HOSTNAMES_DEFAULT = true;
public static final boolean OPENDISTRO_SECURITY_AUDIT_SSL_ENABLE_SSL_CLIENT_AUTH_DEFAULT = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public void testDefault() {
assertTrue(auditConfigFilter.shouldExcludeSensitiveHeaders());
assertSame(WildcardMatcher.NONE, auditConfigFilter.getIgnoredAuditRequestsMatcher());
assertEquals(defaultIgnoredUserMatcher, auditConfigFilter.getIgnoredAuditUsersMatcher());
assertSame(WildcardMatcher.NONE, auditConfigFilter.getIgnoredCustomHeadersMatcher());
assertEquals(auditConfigFilter.getDisabledRestCategories(), defaultDisabledCategories);
assertEquals(auditConfigFilter.getDisabledTransportCategories(), defaultDisabledCategories);
}
Expand All @@ -73,6 +74,7 @@ public void testConfig() {
.put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_EXCLUDE_SENSITIVE_HEADERS, false)
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_REQUESTS, "test-request")
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_USERS, "test-user")
.putList(ConfigConstants.SECURITY_AUDIT_IGNORE_HEADERS, "test-header")
.putList(
ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_REST_CATEGORIES,
BAD_HEADERS.toString(),
Expand All @@ -95,6 +97,7 @@ public void testConfig() {
assertFalse(auditConfigFilter.shouldExcludeSensitiveHeaders());
assertEquals(WildcardMatcher.from(Collections.singleton("test-user")), auditConfigFilter.getIgnoredAuditUsersMatcher());
assertEquals(WildcardMatcher.from(Collections.singleton("test-request")), auditConfigFilter.getIgnoredAuditRequestsMatcher());
assertEquals(WildcardMatcher.from(Collections.singleton("test-header")), auditConfigFilter.getIgnoredCustomHeadersMatcher());
assertEquals(auditConfigFilter.getDisabledRestCategories(), EnumSet.of(BAD_HEADERS, SSL_EXCEPTION));
assertEquals(auditConfigFilter.getDisabledTransportCategories(), EnumSet.of(FAILED_LOGIN, MISSING_PRIVILEGES));
}
Expand All @@ -121,6 +124,7 @@ public void testEmpty() {
final Settings settings = Settings.builder()
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_USERS, Collections.emptyList())
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_IGNORE_REQUESTS, Collections.emptyList())
.putList(ConfigConstants.SECURITY_AUDIT_IGNORE_HEADERS, Collections.emptyList())
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_REST_CATEGORIES, Collections.emptyList())
.putList(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_CONFIG_DISABLED_TRANSPORT_CATEGORIES, Collections.emptyList())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public void testDefaultSerialize() throws IOException {
.field("exclude_sensitive_headers", true)
.field("ignore_users", Collections.singletonList("kibanaserver"))
.field("ignore_requests", Collections.emptyList())
.field("ignore_headers", Collections.emptyList())
.endObject()
.startObject("compliance")
.field("enabled", true)
Expand Down Expand Up @@ -107,6 +108,7 @@ public void testDefaultDeserialize() throws IOException {
assertTrue(audit.shouldExcludeSensitiveHeaders());
assertSame(WildcardMatcher.NONE, audit.getIgnoredAuditRequestsMatcher());
assertEquals(DEFAULT_IGNORED_USER, audit.getIgnoredAuditUsersMatcher());
assertEquals(WildcardMatcher.NONE, audit.getIgnoredCustomHeadersMatcher());
assertFalse(compliance.shouldLogExternalConfig());
assertFalse(compliance.shouldLogInternalConfig());
assertFalse(compliance.shouldLogReadMetadataOnly());
Expand All @@ -133,6 +135,7 @@ public void testDeserialize() throws IOException {
.field("exclude_sensitive_headers", true)
.field("ignore_users", Collections.singletonList("test-user-1"))
.field("ignore_requests", Collections.singletonList("test-request"))
.field("ignore_headers", Collections.singletonList("test-headers"))
.endObject()
.startObject("compliance")
.field("enabled", true)
Expand Down Expand Up @@ -196,6 +199,7 @@ public void testSerialize() throws IOException {
true,
ImmutableSet.of("ignore-user-1", "ignore-user-2"),
ImmutableSet.of("ignore-request-1"),
ImmutableSet.of("test-header"),
EnumSet.of(AuditCategory.FAILED_LOGIN, AuditCategory.GRANTED_PRIVILEGES),
EnumSet.of(AUTHENTICATED)
);
Expand Down Expand Up @@ -227,6 +231,7 @@ public void testSerialize() throws IOException {
.field("exclude_sensitive_headers", true)
.field("ignore_users", ImmutableList.of("ignore-user-1", "ignore-user-2"))
.field("ignore_requests", Collections.singletonList("ignore-request-1"))
.field("ignore_headers", Collections.singletonList("test-header"))
.endObject()
.startObject("compliance")
.field("enabled", true)
Expand Down Expand Up @@ -269,6 +274,7 @@ public void testNullSerialize() throws IOException {
.field("exclude_sensitive_headers", true)
.field("ignore_users", ImmutableList.of("kibanaserver"))
.field("ignore_requests", Collections.emptyList())
.field("ignore_headers", Collections.emptyList())
.endObject()
.startObject("compliance")
.field("enabled", true)
Expand All @@ -287,6 +293,7 @@ public void testNullSerialize() throws IOException {
// act
final String json = objectMapper.writeValueAsString(auditConfig);
// assert

assertTrue(compareJson(jsonBuilder.toString(), json));
}

Expand Down Expand Up @@ -370,6 +377,7 @@ public void testCustomSettings() throws IOException {
private boolean compareJson(final String json1, final String json2) throws JsonProcessingException {
ObjectNode objectNode1 = objectMapper.readValue(json1, ObjectNode.class);
ObjectNode objectNode2 = objectMapper.readValue(json2, ObjectNode.class);

stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
return objectNode1.equals(objectNode2);
}
}
Loading
Loading