From 491e12ab5e8a0cec272ac7e88e7b3edaee0130ba Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 13 Jun 2023 10:42:52 +0200 Subject: [PATCH] Add property to disable Spring Security observations Setting 'management.observations.spring-security.enabled' installs an ObservationPredicate, which prevents all observations starting with 'spring.security.' to be created. Closes gh-34802 --- .../ObservationAutoConfiguration.java | 7 ++++ ...itional-spring-configuration-metadata.json | 6 ++++ .../ObservationAutoConfigurationTests.java | 22 +++++++++++++ .../docs/asciidoc/actuator/observability.adoc | 12 +++++++ .../MyObservationPredicate.java | 32 +++++++++++++++++++ 5 files changed, 79 insertions(+) create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java index 440fc9bf96..5e88d1fcc6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfiguration.java @@ -40,6 +40,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -82,6 +83,12 @@ public class ObservationAutoConfiguration { return new PropertiesObservationFilter(properties); } + @Bean + @ConditionalOnProperty(name = "management.observations.spring-security.enabled", havingValue = "false") + ObservationPredicate springSecurityObservationsDisabler() { + return (name, context) -> !name.startsWith("spring.security."); + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(MeterRegistry.class) @ConditionalOnMissingClass("io.micrometer.tracing.Tracer") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 9a15c30b96..14f14f7c92 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -2038,6 +2038,12 @@ "level": "error" } }, + { + "name": "management.observations.spring-security.enabled", + "description": "Whether to enable observations for Spring Security", + "type": "java.lang.Boolean", + "defaultValue": true + }, { "name": "management.otlp.tracing.compression", "defaultValue": "none" diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java index 186adde605..fd7199af72 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/ObservationAutoConfigurationTests.java @@ -291,6 +291,28 @@ class ObservationAutoConfigurationTests { }); } + @Test + void shouldNotDisableSpringSecurityObservationsByDefault() { + this.contextRunner.run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation.start("spring.security.filterchains", observationRegistry).stop(); + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThat(meterRegistry.get("spring.security.filterchains").timer().count()).isOne(); + }); + } + + @Test + void shouldDisableSpringSecurityObservationsIfPropertyIsSet() { + this.contextRunner.withPropertyValues("management.observations.spring-security.enabled=false") + .run((context) -> { + ObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class); + Observation.start("spring.security.filterchains", observationRegistry).stop(); + MeterRegistry meterRegistry = context.getBean(MeterRegistry.class); + assertThatThrownBy(() -> meterRegistry.get("spring.security.filterchains").timer()) + .isInstanceOf(MeterNotFoundException.class); + }); + } + @Configuration(proxyBeanMethods = false) static class ObservationPredicates { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/observability.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/observability.adoc index f077a1409c..10d8ec7322 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/observability.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/observability.adoc @@ -37,4 +37,16 @@ Commons key-values are applied to all observations as low cardinality key-values The preceding example adds `region` and `stack` key-values to all observations with a value of `us-east-1` and `prod`, respectively. +[[actuator.observability.preventing-observations]] +=== Preventing Observations + +If you'd like to prevent some observations from being reported, you can register beans of type `ObservationPredicate`. +Observations are only reported if all the `ObservationPredicate` beans return `true` for that observation. + +include::code:MyObservationPredicate[] + +The preceding example will prevent all observations with a name starting with "denied.prefix.". + +TIP: If you want to prevent Spring Security from reporting observations, set the property configprop:management.observations.spring-security.enabled[] to `false`. + The next sections will provide more details about logging, metrics and traces. diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.java new file mode 100644 index 0000000000..17a5543dc3 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.docs.actuator.observability.preventingobservations; + +import io.micrometer.observation.Observation.Context; +import io.micrometer.observation.ObservationPredicate; + +import org.springframework.stereotype.Component; + +@Component +class MyObservationPredicate implements ObservationPredicate { + + @Override + public boolean test(String name, Context context) { + return !name.startsWith("denied.prefix."); + } + +}