|
|
|
|
@@ -536,11 +536,32 @@ all enabled endpoints to be exposed over HTTP. The default convention is to use
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-sensitive-endpoints]]
|
|
|
|
|
=== Securing sensitive endpoints
|
|
|
|
|
If you add '`Spring Security`' to your project, all sensitive endpoints exposed over HTTP
|
|
|
|
|
will be protected. By default '`basic`' authentication will be used with the username
|
|
|
|
|
`user` and a generated password (which is printed on the console when the application
|
|
|
|
|
starts).
|
|
|
|
|
=== Accessing sensitive endpoints
|
|
|
|
|
By default all sensitive HTTP endpoints are secured such that only users that have an
|
|
|
|
|
`ACTUATOR` role may access them. Security is enforced using the standard
|
|
|
|
|
`HttpServletRequest.isUserInRole` method.
|
|
|
|
|
|
|
|
|
|
TIP: Use the `management.security.roles` property if you want something different to
|
|
|
|
|
`ACTUATOR`.
|
|
|
|
|
|
|
|
|
|
If you are deploying applications behind a firewall, you may prefer that all your actuator
|
|
|
|
|
endpoints can be accessed without requiring authentication. You can do this by changing
|
|
|
|
|
the `management.security.enabled` property:
|
|
|
|
|
|
|
|
|
|
.application.properties
|
|
|
|
|
[source,properties,indent=0]
|
|
|
|
|
----
|
|
|
|
|
management.security.enabled=false
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
NOTE: By default, actuator endpoints are exposed on the same port that serves regular
|
|
|
|
|
HTTP traffic. Take care not to accidentally expose sensitive information if you change
|
|
|
|
|
the `management.security.enabled` property.
|
|
|
|
|
|
|
|
|
|
If you're deploying applications publicly, you may want to add '`Spring Security`' to
|
|
|
|
|
handle user authentication. When '`Spring Security`' is added, by default '`basic`'
|
|
|
|
|
authentication will be used with the username `user` and a generated password (which is
|
|
|
|
|
printed on the console when the application starts).
|
|
|
|
|
|
|
|
|
|
TIP: Generated passwords are logged as the application starts. Search for '`Using default
|
|
|
|
|
security password`'.
|
|
|
|
|
@@ -556,10 +577,6 @@ in your `application.properties`:
|
|
|
|
|
management.security.roles=SUPERUSER
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
TIP: If you don't use Spring Security and your HTTP endpoints are exposed publicly,
|
|
|
|
|
you should carefully consider which endpoints you enable. See
|
|
|
|
|
<<production-ready-customizing-endpoints>> for details of how you can set
|
|
|
|
|
`endpoints.enabled` to `false` then "`opt-in`" only specific endpoints.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-customizing-management-server-context-path]]
|
|
|
|
|
@@ -1093,19 +1110,19 @@ Example:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter(MetricExportProperties export) {
|
|
|
|
|
return new RedisMetricRepository(connectionFactory,
|
|
|
|
|
export.getRedis().getPrefix(), export.getRedis().getKey());
|
|
|
|
|
}
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter(MetricExportProperties export) {
|
|
|
|
|
return new RedisMetricRepository(connectionFactory,
|
|
|
|
|
export.getRedis().getPrefix(), export.getRedis().getKey());
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
.application.properties
|
|
|
|
|
[source,properties]
|
|
|
|
|
[source,properties,indent=0]
|
|
|
|
|
----
|
|
|
|
|
spring.metrics.export.redis.prefix: metrics.mysystem.${spring.application.name:application}.${random.value:0000}
|
|
|
|
|
spring.metrics.export.redis.key: keys.metrics.mysystem
|
|
|
|
|
spring.metrics.export.redis.prefix: metrics.mysystem.${spring.application.name:application}.${random.value:0000}
|
|
|
|
|
spring.metrics.export.redis.key: keys.metrics.mysystem
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
The prefix is constructed with the application name and id at the end, so it can easily be used
|
|
|
|
|
@@ -1144,21 +1161,21 @@ Example:
|
|
|
|
|
|
|
|
|
|
[source,indent=0]
|
|
|
|
|
----
|
|
|
|
|
curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"metric": "counter.status.200.root",
|
|
|
|
|
"tags": {
|
|
|
|
|
"domain": "org.springframework.metrics",
|
|
|
|
|
"process": "b968a76"
|
|
|
|
|
},
|
|
|
|
|
"aggregateTags": [],
|
|
|
|
|
"dps": {
|
|
|
|
|
"1430492872": 2,
|
|
|
|
|
"1430492875": 6
|
|
|
|
|
curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
"metric": "counter.status.200.root",
|
|
|
|
|
"tags": {
|
|
|
|
|
"domain": "org.springframework.metrics",
|
|
|
|
|
"process": "b968a76"
|
|
|
|
|
},
|
|
|
|
|
"aggregateTags": [],
|
|
|
|
|
"dps": {
|
|
|
|
|
"1430492872": 2,
|
|
|
|
|
"1430492875": 6
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1177,14 +1194,14 @@ Alternatively, you can provide a `@Bean` of type `StatsdMetricWriter` and mark i
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Value("${spring.application.name:application}.${random.value:0000}")
|
|
|
|
|
private String prefix = "metrics";
|
|
|
|
|
@Value("${spring.application.name:application}.${random.value:0000}")
|
|
|
|
|
private String prefix = "metrics";
|
|
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter() {
|
|
|
|
|
return new StatsdMetricWriter(prefix, "localhost", 8125);
|
|
|
|
|
}
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter() {
|
|
|
|
|
return new StatsdMetricWriter(prefix, "localhost", 8125);
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1200,11 +1217,11 @@ Example:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter(MBeanExporter exporter) {
|
|
|
|
|
return new JmxMetricWriter(exporter);
|
|
|
|
|
}
|
|
|
|
|
@Bean
|
|
|
|
|
@ExportMetricWriter
|
|
|
|
|
MetricWriter metricWriter(MBeanExporter exporter) {
|
|
|
|
|
return new JmxMetricWriter(exporter);
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Each metric is exported as an individual MBean. The format for the `ObjectNames` is given
|
|
|
|
|
@@ -1231,24 +1248,24 @@ Example:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Autowired
|
|
|
|
|
private MetricExportProperties export;
|
|
|
|
|
@Autowired
|
|
|
|
|
private MetricExportProperties export;
|
|
|
|
|
|
|
|
|
|
@Bean
|
|
|
|
|
public PublicMetrics metricsAggregate() {
|
|
|
|
|
return new MetricReaderPublicMetrics(aggregatesMetricReader());
|
|
|
|
|
}
|
|
|
|
|
@Bean
|
|
|
|
|
public PublicMetrics metricsAggregate() {
|
|
|
|
|
return new MetricReaderPublicMetrics(aggregatesMetricReader());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MetricReader globalMetricsForAggregation() {
|
|
|
|
|
return new RedisMetricRepository(this.connectionFactory,
|
|
|
|
|
this.export.getRedis().getAggregatePrefix(), this.export.getRedis().getKey());
|
|
|
|
|
}
|
|
|
|
|
private MetricReader globalMetricsForAggregation() {
|
|
|
|
|
return new RedisMetricRepository(this.connectionFactory,
|
|
|
|
|
this.export.getRedis().getAggregatePrefix(), this.export.getRedis().getKey());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MetricReader aggregatesMetricReader() {
|
|
|
|
|
AggregateMetricReader repository = new AggregateMetricReader(
|
|
|
|
|
globalMetricsForAggregation());
|
|
|
|
|
return repository;
|
|
|
|
|
}
|
|
|
|
|
private MetricReader aggregatesMetricReader() {
|
|
|
|
|
AggregateMetricReader repository = new AggregateMetricReader(
|
|
|
|
|
globalMetricsForAggregation());
|
|
|
|
|
return repository;
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
NOTE: The example above uses `MetricExportProperties` to inject and extract the key and
|
|
|
|
|
@@ -1312,34 +1329,34 @@ and obtain basic information about the last 100 requests:
|
|
|
|
|
|
|
|
|
|
[source,json,indent=0]
|
|
|
|
|
----
|
|
|
|
|
[{
|
|
|
|
|
"timestamp": 1394343677415,
|
|
|
|
|
"info": {
|
|
|
|
|
"method": "GET",
|
|
|
|
|
"path": "/trace",
|
|
|
|
|
"headers": {
|
|
|
|
|
"request": {
|
|
|
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
|
|
|
"Connection": "keep-alive",
|
|
|
|
|
"Accept-Encoding": "gzip, deflate",
|
|
|
|
|
"User-Agent": "Mozilla/5.0 Gecko/Firefox",
|
|
|
|
|
"Accept-Language": "en-US,en;q=0.5",
|
|
|
|
|
"Cookie": "_ga=GA1.1.827067509.1390890128; ..."
|
|
|
|
|
"Authorization": "Basic ...",
|
|
|
|
|
"Host": "localhost:8080"
|
|
|
|
|
},
|
|
|
|
|
"response": {
|
|
|
|
|
"Strict-Transport-Security": "max-age=31536000 ; includeSubDomains",
|
|
|
|
|
"X-Application-Context": "application:8080",
|
|
|
|
|
"Content-Type": "application/json;charset=UTF-8",
|
|
|
|
|
"status": "200"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},{
|
|
|
|
|
"timestamp": 1394343684465,
|
|
|
|
|
...
|
|
|
|
|
}]
|
|
|
|
|
[{
|
|
|
|
|
"timestamp": 1394343677415,
|
|
|
|
|
"info": {
|
|
|
|
|
"method": "GET",
|
|
|
|
|
"path": "/trace",
|
|
|
|
|
"headers": {
|
|
|
|
|
"request": {
|
|
|
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
|
|
|
"Connection": "keep-alive",
|
|
|
|
|
"Accept-Encoding": "gzip, deflate",
|
|
|
|
|
"User-Agent": "Mozilla/5.0 Gecko/Firefox",
|
|
|
|
|
"Accept-Language": "en-US,en;q=0.5",
|
|
|
|
|
"Cookie": "_ga=GA1.1.827067509.1390890128; ..."
|
|
|
|
|
"Authorization": "Basic ...",
|
|
|
|
|
"Host": "localhost:8080"
|
|
|
|
|
},
|
|
|
|
|
"response": {
|
|
|
|
|
"Strict-Transport-Security": "max-age=31536000 ; includeSubDomains",
|
|
|
|
|
"X-Application-Context": "application:8080",
|
|
|
|
|
"Content-Type": "application/json;charset=UTF-8",
|
|
|
|
|
"status": "200"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},{
|
|
|
|
|
"timestamp": 1394343684465,
|
|
|
|
|
...
|
|
|
|
|
}]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1396,6 +1413,67 @@ customize the file name and path via the `Writer` constructor.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-cloudfoundry]]
|
|
|
|
|
== Cloud Foundry support
|
|
|
|
|
Spring Boot's actuator module includes additional support that is activated when you
|
|
|
|
|
deploy to a compatible Cloud Foundry instance. The `/cloudfoundryapplication` path
|
|
|
|
|
provides an alternative secured route to all `NamedMvcEndpoint` beans.
|
|
|
|
|
|
|
|
|
|
The extended support allows Cloud Foundry management UIs (such as the web
|
|
|
|
|
application that you can use to view deployed applications) to be augmented with Spring
|
|
|
|
|
Boot actuator information. For example, an application status page may include full health
|
|
|
|
|
information instead of the typical "`running`" or "`stopped`" status.
|
|
|
|
|
|
|
|
|
|
NOTE: The `/cloudfoundryapplication` path is not directly accessible to regular users.
|
|
|
|
|
In order to use the endpoint a valid UAA token must be passed with the request.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-cloudfoundry-disable]]
|
|
|
|
|
=== Disabling extended Cloud Foundry actuator support
|
|
|
|
|
If you want to fully disable the `/cloudfoundryapplication` endpoints you can add the
|
|
|
|
|
following to your `application.properties` file:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.application.properties
|
|
|
|
|
[source,properties,indent=0]
|
|
|
|
|
----
|
|
|
|
|
management.cloudfoundry.enabled=false
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-cloudfoundry-ssl]]
|
|
|
|
|
=== Cloud Foundry self signed certificates
|
|
|
|
|
By default, the security verification for `/cloudfoundryapplication` endpoints makes SSL
|
|
|
|
|
calls to various Cloud Foundry services. If your Cloud Foundry UAA or Cloud Controller
|
|
|
|
|
services use self-signed certificates you will need to set the following property:
|
|
|
|
|
|
|
|
|
|
.application.properties
|
|
|
|
|
[source,properties,indent=0]
|
|
|
|
|
----
|
|
|
|
|
management.cloudfoundry.skip-ssl-validation=true
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-cloudfoundry-custom-security]]
|
|
|
|
|
=== Custom security configuration
|
|
|
|
|
If you define custom security configuration, and you want extended Cloud Foundry actuator
|
|
|
|
|
support, you'll should ensure that `/cloudfoundryapplication/**` paths are open. Without
|
|
|
|
|
a direct open route, your Cloud Foundry application manager will not be able to obtain
|
|
|
|
|
endpoint data.
|
|
|
|
|
|
|
|
|
|
For Spring Security, you'll typically include something like
|
|
|
|
|
`mvcMatchers("/cloudfoundryapplication/**").permitAll()` in your configuration:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
include::{code-examples}/cloudfoundry/CloudFoundryIgnorePathsExample.java[tag=security]
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[[production-ready-whats-next]]
|
|
|
|
|
== What to read next
|
|
|
|
|
If you want to explore some of the concepts discussed in this chapter, you can take a
|
|
|
|
|
|