Conhecendo o Actuator do Spring Boot
Um dos recursos que mais gosto no Spring Boot e que normalmente é negligenciado por quem usa o framework é o Actuator: natural, dado que o foco normalmente está no código sendo escrito e não após ter sido implantado.
O Actuator é um recurso do Spring Boot que nos permite monitorar e gerenciar aplicações escritas neste framework em seu ambiente de implantação. É bastante rico e fácil de ser usado: já vêm com diversos recursos prontos pra uso sem que você precise escrever uma única linha de código e será nosso assunto aqui.
A curiosa história deste texto e dos próximos
Quando comecei a escrever este texto lembrei que pouca gente conhecia um recurso similar que temos no Java SE chamado JMX, então escrevi aquele post apresentando a tecnologia. Quando finalmente voltei ao objetivo inicial o resultado foi um texto imenso. Sendo assim resolvi dividi-lo em partes: nesta primeira vou apresentar uma visão geral sobre o Actuator e nos restantes vamos ver os recursos que mais usamos em nosso dia a dia.
Vou te mostrar o que é o Actuator, suas principais aplicações (por alto, vou detalhar tudo isto nos posts mais a frente (já estão prontos, “só falta testar”)), as principais configurações e, finalmente, pontos fundamentais relativos à segurança do seu projeto.
O que é o Actuator?
Talvez o Actuator não seja tão usado e conhecido pelo modo como é apresentado pela equipe do Spring Boot e traduzido para o português: “production-ready features”, aí traduzem como “funcionalidades para o ambiente de produção”. Pior: a maior parte dos livros em português tem como foco a escrita de código e no máximo a implantação, ignorando aquela que pra mim é a fase mais importante: a pós implantação.
O Spring Boot oferece à equipe de desenvolvimento todo o ferramental necessário para que possa monitorar e gerenciar sua aplicação após ter sido implantada. Com ele você pode:
- Monitorar a aplicação, isto é, acompanhar diversos aspectos da sua execução após implantada.
- Gerenciar a aplicação, ou seja, interagir com o sistema com ele em execução operando ações neste como, por exemplo, limpeza de cache, tarefas administrativas, alteração de configurações e muito mais.
Ok, você leu o meu texto sobre JMX e viu as mesmas frases. Então qual a diferença? Há algumas.
- O protocolo padrão é o HTTP usando REST como padrão, o que facilita seu uso (há riscos de segurança que vou ensinar a minimizar mais a frente).
- Além do protocolo HTTP também pode usar JMX, que é o mecanismo padrão de instrumentação do Java.
- Assim como o JMX já vêm com uma série de indicadores relativos ao funcionamento da JVM por padrão, o Actuator trás diversas outras categorias de indicadores, a maior parte voltados para o contexto de aplicações web.
- Tem como base o Spring Boot – está amarrado ao framework portanto, você não conseguirá usá-lo de forma fácil em outros frameworks.
- Fornece a plataforma para que diversos módulos do Spring Boot possam fornecer seus próprios.
Resumindo: o Actuator nos dá todos os recursos que precisamos para monitorar e gerenciar aplicações no contexto web, o que é vital se você implementa uma arquitetura baseada em micro serviços.
Monitorar o que?
Toda esta conversa sobre monitoramento é muito bonita mas talvez você se sinta perdido pois há inúmeras opções. Que aspectos relativos à execução do seu projeto interessam ser monitorados? Quais novos indicadores o Actuator trás pra nós?
Indicadores customizados pelo desenvolvedor
Se você leu meu texto sobre JMX, temos aqui o mesmo conceito dos MBeans. Você pode implementar beans aqui capazes de oferecer as seguintes funcionalidades:
- Obtenção de dados – verificar espaço em disco, por exemplo.
- Executar ações – tarefas administrativas como limpeza de cache, remoção de arquivos temporários ou qualquer outro tipo de funcionalidade administrativa que você precise em produção.
Sua imaginação e necessidade são os limites aqui. Você poderia implementar isto como endpoints convencionais do Spring que executassem estas operações, é verdade, mas para o caso de tarefas administrativas o ideal é que até por questões de segurança seja um código isolado.
Checagem de qualidade de serviço (health checks)
Talvez meu uso favorito do Actuator: código de health checking é aquele responsável por verificar se o sistema está executando em condições adequadas. Vamos a alguns exemplos:
- Verificar espaço em disco.
- Quantidade de memória disponível.
- Acesso ao banco de dados (checagem dos data sources).
- Se você realiza interação com outros serviços externos, se consegue se conectar a estes.
- Integridade do sistema de arquivos.
Um dos textos desta série é justamente sobre health checking. É interessante aqui observar que diversos módulos do Spring Boot (como Redis, JPA e muitos outros) adicionam seus próprios testes de verificação de qualidade sem que você precise escrever uma linha de código sequer. A imagem a seguir expõe um exemplo de health checking detalhado usando o que já vêm com o módulo JPA:
Bem legal hein? E eu não escrevi uma linha sequer de código pra verificar se o acesso ao banco de dados está funcionando. Observe que também há um teste sobre espaço em disco: também não escrevi este teste, veio de graça com o Actuator!
E eu te contei que você pode escrever seus próprios testes? Vamos ver isto no próximo post!
Logging
O Actuator pode facilitar bastante o acesso ao conteúdo do arquivo de log da aplicação. E este é um uso bastante útil, essencialmente, para ver o log principal da aplicação você apenas acessa o endpoint /actuator/logfile e boom: o log principal da aplicação está ali. Abaixo você pode ver um exemplo de saída:
É possível até mesmo usando o comando curl obter a sua própria versão do “tail”, veja este exemplo:
curl 'http://localhost:8080/actuator/logfile' -i -X GET
É possível também ver a lista de todos os loggers presentes na aplicação, assim como seus níveis de acesso.
Não pretendo me aprofundar neste tema, mas se você quiser, este é o link a seguir.
Métricas (metrics) – profilando sua aplicação
No caso das métricas temos aqui a medição de um aspecto da aplicação específico (consumo de CPU, memória, conexões ativas com banco de dados, etc), no momento atual. Essencialmente este indicador responde a seguinte questão: “qual o valor do indicador X agora?“.
Isto te permite montar gráficos que possibilitam acompanhar ao longo do tempo o desempenho destes componentes, tal como o gráfico abaixo, que expõe o uso de CPU ao longo do tempo:
Infelizmente o Actuator não vêm com o ferramental que produz este tipo de gráfico, mas provê conectores para diversas ferramentas que podem gerar isto para você, tais como JMX, New Relic, Datadog, Dynatrace, Elastic e muitos outros que você pode ver neste link.
Mas não acaba aí! Você também pode monitorar o tempo de resposta dos seus endpoints com estas métricas. Veja o exemplo a seguir, real, extraído da API do /dev/All:
Quando adicionamos a anotação @Timed (io.micrometer.core.annotation.Timed) na classe do nosso controlador, podemos extrair métricas como número de requisições recebidas, tempo máximo de processamento e outros detalhes, apenas acessando o endereço /actuator/metrics/site (notou que “site” é o valor que passei pra anotação @Timed?). Veja o print a seguir:
É possível anotar apenas alguns endpoints também, o que te permite acompanhar a evolução do desempenho dos mesmos. Notou que obtive tudo isto incluindo apenas uma anotação? Pode aguardar que tem post detalhando este assunto vindo.
Informações genéricas (Info)
Outro grupo de informações muito útil é o info: quem nunca precisou verificar qual a versão da aplicação está em produção? Mas não se limita a apenas isto: você pode incluir literalmente qualquer coisa aqui, até mesmo informações relativas ao Git.
Sim, há um post só sobre este ponto aqui saindo no futuro. Neste primeiro momento pense nas informações genéricas como “a sua base chave/valor de dados no Actuator”.
Menções honrosas
Meu objetivo neste e nos próximos posts é mostrar quais os recursos do Actuator que acho mais interessantes com base na minha experiência. Mas há alguns outros recursos providos por padrão que devem ser mencionados:
- Auditoria – te possibilita registrar e monitorar eventos de autenticação bem ou mal sucedida e acesso não autorizado aos seus endpoints. Muito útil, leia mais neste link.
- Listagem de rotas – muito útil, especialmente quando você está lidando com sistemas pré-existentes. Mais detalhes aqui.
- Gestão do processo principal – sabia que você pode finalizar o processo da sua aplicação pelo Actuator? Yeap, você pode: é o endpoint /actuator/shutdown. Em momentos críticos pode te ajudar bastante (pense num bug bruto em produção gerando prejuízos por segundo). Leia mais aqui.
Actuator na prática
O Actuator está presente desde a primeira versão do Spring Boot. Neste texto estou falando da última versão do framework (2.4.1), e incluí-lo em sua aplicação é muito simples. Se está usando Maven, basta incluir a dependência a seguir:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Usa Gradle? Tão fácil quanto: inclua a dependência tal como no exemplo a seguir:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
Inicie seu projeto e, na sequência, acesse este endereço: http://localhost:8080/actuator (imaginando que seu contexto seja “/”). Você verá uma resposta similar a esta:
Super legal: o Actuator está te mostrando quais os endpoints de monitoramento/gerenciamento disponíveis. Por padrão estão visíveis apenas os endpoints de saúde (health) e informações gerais (info). Experimente navegar por eles, será uma experiência frustrante após ter lido este meu texto, pois você não vê nada do que prometi. Vamos resolver isto agora.
Endpoints – expostos vs habilitados
A unidade base do Actuator é o endpoint. Qualquer ação que você realize no Actuator envolve o acesso a um dos endereços disponibilizados pelo framework. Por segurança não temos todos os endpoints expostos, especialmente por que estamos usando um protocolo que, por padrão, não é seguro, o HTTP (não confundir com HTTPS, que também não é tão seguro assim quanto as propagandas da internet (“Ops!”) vendem).
Sendo assim é necessário alterar as configurações do Spring Boot (não sabe como fazer com segurança? Já escrevi sobre elas aqui) para identificar quais os itens que serão expostos. Quer expor todos? Então mude o valor da configuração management.endpoints.web.exposure.include com o valor * tal como no exemplo abaixo:
management.endpoints.web.exposure.include=*
Atenção: se sua configuração estiver no formato yaml, digite ‘*’ ao invés de *. Acesse novamente o endereço base do Actuator: http://localhost:8080/actuator
Olha aí um monte de endpoints disponíveis pra você agora (inclusive o “shutdown”, que habilitei de propósito e é desabilitado por padrão). Há dois conceitos aqui:
- Endpoints ativos – todos (com exceção de um (então não são todos, qual é este? é o shutdown)) são ativos por padrão, isto é, podem ser executados.
- Endpoints expostos – são os endpoints que podem ser acessados remotamente por HTTP ou JMX.
O endpoint pode estar visível por essencialmente dois protocolos quando estamos tratando do Actuator: JMX ou HTTP. Neste post vamos falar só de HTTP, mas você pode aprender mais sobre o que é o JMX neste meu texto e como trabalhar com JMX e Actuator neste link da documentação.
Não é uma boa ideia expor todos os endpoints. O ideal é que você exponha apenas o que realmente faz sentido, pois quanto mais pontos de monitoramento estiverem visíveis, maior é a área de ataque aos seus sistemas. Sendo assim entra um novo conceito aqui: o identificador do endpoint.
Todo indicador (endpoint) no Actuator tem seu próprio identificador. A lista dos identificadores padrão pode ser conferida neste link.
Como ativar endpoints
Você deve seguir a seguinte sintaxe para ativar um endpoint individualmente:
management.endpoint.[identificador do endpoint].enabled=(true|false)
Vamos a alguns exemplos, habilitando o info e desabilitando o shutdown:
management.endpoint.info.enabled=true
management.endpoint.shutdown.enabled=false
Como mencionei agora há pouco, todos os endpoints estão ativados por padrão com exceção do “shutdown”. Mas e se você não quiser este comportamento? E se quiser habilitar um a um os endpoints que deseja? Aí basta alterar a configuração management.endpoints.enabled-by-default tal como no exemplo a seguir:
# pronto, agora você vai ter de definir um a um os endpoints ativos
management.endpoints.enabled-by-default=false
Como expor endpoints
Por padrão apenas os endpoints info e health estão expostos por padrão ao protocolo HTTP. É muito importante que você leve segurança em consideração aqui, sendo assim recomendo que você exponha apenas os endpoints que sejam realmente importantes para sua equipe.
Novamente, vamos lidar com algumas configurações do Spring Boot aqui. A primeira delas diz quais os endpoints que você quer expor: management.endpoints.web.exposure.include. Ela pode receber dois valores: “*” ou a lista de identificadores separados por vírgula, tal como no exemplo a seguir:
# expondo todos os endpoints
management.endpoints.web.exposure.include=*
# expondo apenas os endpoints que nos interessam: health, info, metrics
management.endpoints.web.exposure.include=health,info,metrics
as pra complicar (ou não) um pouquinho as coisas há outra propriedade que também define os endpoints que desejamos ocultar. É a configuração management.endpoints.web.exposure.exclude. Exclude tem precedência sobre o que será exposto. E a mesma sintaxe que temos para o include, temos para o exclude.
Segurança
Tudo muito bonito: com o Actuator podemos ver praticamente tudo sobre o estado corrente da nossa aplicação e também o ambiente no qual ela está sendo executada. E com as configurações padrão inclusive quem não deveria ter acesso a estas informações.
Alguém interessado em lhe causar problemas sabe tudo sobre sua aplicação: quais pontos da aplicação podem não estar funcionando corretamente (healthcheck), quanta memória está disponível, idem espaço de armazenamento, quantas requisições por segundo sua aplicação recebe, o que sai no log, como está seu banco de dados… enfim, é o prato cheio pra quem quer invadir sua plataforma. E claro, usando um protocolo disponível a todos: HTTP. Com um browser qualquer descubro como lhe causar pesadelos. Vejamos como evitar isto.
Spring Security
Se sua aplicação usa Spring Security (use), é relativamente fácil limitar o acesso aos endpoints do Actuator com base nas permissões do usuário. O caminho mais popular é estender a classe de configuração WebSecurityConfigurerAdapter sobrescrevendo o método configure tal como no exemplo a seguir:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.authorizeRequests()
.antMatchers("/actuator/").hasAuthority("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.csrf().disable();
}
}
Observe, este é um código de mera referência, vai dar um pouquinho mais de trabalho no seu projeto, pegue apenas a ideia geral. Neste caso, apenas os usuários com a permissão (authority) ROLE_ADMIN terão acesso aos endpoints.
Caso queira mais exemplos, sugiro que você confira este e este link. Mas o ponto é: restrinja o acesso.
Caso o Spring Security não seja uma opção, há outras: você pode implementar um filtro, por exemplo, e neste adotar outro tipo de autenticação, como Basic Auth (não recomendo) por exemplo ou mesmo headers de API Keys.
Mude as configurações padrão
Mudando o base path padrão
Se eu quiser varrer sua rede em busca de informações sobre sua infra a primeira coisa que farei é buscar endereços padrão. O endereço padrão do Actuator é “/actuator”. Sendo assim, vamos mudar esta configuração? É simples, você usa a chave management.endpoints.web.base-path , tal como no exemplo abaixo:
# mudando de /actuator para /segredos
management.endpoints.web.base-path=/segredos
Recomendo que você use sua criatividade neste nome, o que pelo menos irá dar um pouco mais de trabalho para quem estiver tentando encontrar seu endereço base do Actuator.
Use outra porta
Esta é outra boa dica. Você pode configurar o Actuator para usar uma porta diferente daquela adotada por sua aplicação. Sendo assim sua API poderia operar na porta 443 (HTTPS) por exemplo, e o Actuator na porta 1979. Com isto, configurando seu firewall (ou regras de acesso a portas do seu serviço cloud) você consegue limitar quais endereços poderão ter acesso ao Actuator na porta customizada. A chave de configuração usada é a management.server.port. O exemplo abaixo define a porta 1979 para o Actuator:
management.server.port=1979
Tente acessar o Actuator pela porta padrão da aplicação e o que você recebe? 404!
Configure CORS
Se você quer que código JavaScript cliente acesse seus endpoints do Actuator (tem certeza disto?) é possível habilitar CORS para os endpoints usando as chaves expostas no exemplo a seguir:
# as origens
management.endpoints.web.cors.allowed-origins=https://itexto.com.br
# quais métodos
management.endpoints.web.cors.allowed-methods=GET,POST
Não sabe o que é CORS? Leia este texto. Mais detalhes sobre o uso de CORS na documentação oficial do Actuator aqui.
SSL
Já que você definiu uma porta diferente pro seu servidor, por que não jogar um certificado SSL no mesmo pra deixar a coisa ainda mais segura?
A configuração a seguir expõe exatamente isto:
# a porta customizada do servidor
management.server.port=1979
# habilitando SSL nesta porta
management.server.ssl.enabled=true
# o keystore que contém seu certificado
management.server.ssl.key-store=classpath:management.jks
# a senha de acesso ao keystore
management.server.ssl.key-password=secret
Maiores detalhes neste link.
Concluindo a introdução e preparando a jornada
Nosso caminho com Actuator está só começando. Meu objetivo neste post foi te mostrar o que é esta ferramenta, abrir seus olhos para algumas das possibilidades que ela nos dá e, principalmente, te preparar para o maior risco que vêm com ela: a exposição de dados sensíveis a partir dos endpoints disponibilizados.
A partir de agora meu objetivo é ir pra prática: vou te ensinar a implementar seus próprios endpoints de health checking, como enriquecer as informações apresentadas pelo seu sistema, lidar com auditoria e implementar seus próprios endpoints.
Até lá!
Para saber mais
Documentação oficial do Actuator – https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html
API do Actuator – te expõe todos os detalhes sobre os endpoints padrão disponibilizados pela ferramenta – https://docs.spring.io/spring-boot/docs/2.4.1/actuator-api/htmlsingle/
Entendendo as configurações do Spring Boot – é fundamental que você entenda como as configurações do Spring Boot funcionam. Então escrevi este texto.
Conheça JMX – o texto que nasceu deste aqui e que contém muitos conceitos que você deve conhecer também. Leia aqui.
Documentação oficial do Spring Security – https://docs.spring.io/spring-security/site/docs/5.4.2/reference/html5/