かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その12 )( Spring Boot Actuator を導入する )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その11 )( HikariCP のコネクションプーリングの情報を JMX で取得できるようにする ) の続きです。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. WebSecurityConfig.java を変更して /actuator/** にのみ Basic 認証を設定する
  3. application.properties を変更する
  4. 動作確認
  5. 次回は。。。

手順

build.gradle を変更する

build.gradle の以下の点を変更します。

plugins {
    ..........
    id "de.undercouch.download" version "3.4.3"
    id "com.gorylenko.gradle-git-properties" version "1.5.2"
}

..........

dependencies {
    ..........
    implementation("org.springframework.boot:spring-boot-starter-amqp")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    runtimeOnly("org.springframework.boot:spring-boot-devtools")
    ..........
    implementation("org.codehaus.janino:janino")
    implementation("io.micrometer:micrometer-registry-prometheus")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    ..........
  • plugins block の以下の点を変更します。
    • id "com.gorylenko.gradle-git-properties" version "1.5.2" を追加します。
  • dependencies block の以下の点を変更します。
    • implementation("org.springframework.boot:spring-boot-starter-actuator") を追加します。
    • spring-boot-devtools は runtimeOnly で記述すべきなのに変更するのを忘れていることに気づきました。implementation("org.springframework.boot:spring-boot-devtools")runtimeOnly("org.springframework.boot:spring-boot-devtools") に変更します。
    • implementation("io.micrometer:micrometer-registry-prometheus") を追加します。

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

WebSecurityConfig.java を変更して /actuator/** にのみ Basic 認証を設定する

src/main/java/ksbysample/webapp/lending/config/WebSecurityConfig.java の以下の点を変更します。

@Configuration
public class WebSecurityConfig {

    ..........

    @Configuration
    @Order(1)
    public static class ActuatorWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    // Spring Actuator の Endpoint のみ Basic認証を設定する
                    .requestMatcher(EndpointRequest.toAnyEndpoint())
                    .authorizeRequests()
                    .anyRequest().hasRole("ENDPOINT_ADMIN")
                    .and()
                    .httpBasic();
        }

    }

    @Configuration
    public static class FormLoginWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                    // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                    // .antMatchers("/country/**").permitAll()
                    .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                    .antMatchers("/fonts/**").permitAll()
                    .antMatchers("/html/**").permitAll()
                    .antMatchers("/encode").permitAll()
                    .antMatchers("/urllogin").permitAll()
                    .antMatchers("/webapi/**").permitAll()
                    .antMatchers("/springMvcMemo/**").permitAll()
                    .antMatchers("/sessionsample/**").permitAll()
                    .antMatchers("/textareamemo/**").permitAll()
                    .antMatchers("/sample/**").permitAll()
                    .anyRequest().hasAnyRole("USER", "ADMIN", "APPROVER");
            http.formLogin()
                    .loginPage("/")
                    .loginProcessingUrl("/login")
                    .defaultSuccessUrl(DEFAULT_SUCCESS_URL)
                    .usernameParameter("id")
                    .passwordParameter("password")
                    .successHandler(new RoleAwareAuthenticationSuccessHandler())
                    .failureHandler(new ForwardAuthenticationFailureHandler("/"))
                    .permitAll()
                    .and()
                    .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/")
                    .deleteCookies("SESSION")
                    .deleteCookies("remember-me")
                    .invalidateHttpSession(true)
                    .permitAll()
                    .and()
                    .rememberMe()
                    .key(REMEMBERME_KEY)
                    .tokenValiditySeconds(60 * 60 * 24 * 30);
        }

    }

    ..........

    /**
     * @param auth ???
     * @throws Exception
     */
    @SuppressWarnings("PMD.SignatureDeclareThrowsException")
    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        // 必ず auth.inMemoryAuthentication() を先に書くこと
        auth.inMemoryAuthentication()
                .withUser("actuator")
                .password("{noop}xxxxxxxx")
                .roles("ENDPOINT_ADMIN");
        auth.authenticationProvider(daoAuhthenticationProvider())
                .userDetailsService(userDetailsService);
    }

}
  • @Configuration public static class FormLoginWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { ... } を追加し、既存の configure メソッドをこの中へ移動します。また configure メソッド内の .authenticated().hasAnyRole("USER", "ADMIN", "APPROVER") に変更して actuator 用の Role として使用する ENDPOINT_ADMIN ではログインできないようにします。
  • @Configuration @Order(1) public static class ActuatorWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { ... } を追加し、actuator の endpoint の Basic認証をこのクラスで設定します。
  • configAuthentication bean 内に auth.inMemoryAuthentication().withUser("actuator").password("{noop}xxxxxxxx").roles("ENDPOINT_ADMIN"); を追加します。

application.properties を変更する

src/main/resources/application.properties の以下の点を変更します。

doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect

management.endpoints.web.exposure.include=health,info,loggers,prometheus

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.hikari.jdbc-url=jdbc:postgresql://localhost/ksbylending
..........
  • management.endpoints.web.exposure.include=health,info,loggers,prometheus を追加します。

動作確認

ここまでの設定で /actuator/** には Basic 認証が、それ以外のパスには Form 認証が行われるはずなので、確認してみます。

Tomcat を起動した後、http://localhost:8080/admin/library にアクセスするとログイン画面が表示されます。

f:id:ksby:20181028233415p:plain

tanaka.taro@sample.com / taro を入力して「ログイン」ボタンをクリックすると http://localhost:8080/admin/library が表示されます。

f:id:ksby:20181028233537p:plain

ログインしている状態から http://localhost:8080/actuator/prometheus にアクセスすると、現在ログインしている ID では ENDPOINT_ADMIN の ROLE を持っていないので 403 Forbidden が返ってきます。

f:id:ksby:20181028233843p:plain

画面右上の「ログアウト」リンクをクリックしてログアウトしてから再度 http://localhost:8080/actuator/prometheus にアクセスすると、Basic 認証のダイアログが表示されます。

f:id:ksby:20181028234446p:plain

actuator / xxxxxxxx を入力して「OK」ボタンをクリックすると /actuator/prometheus が出力する情報が表示されます。

f:id:ksby:20181028234603p:plain

次回は。。。

Docker で Prometheus+Grafana の環境を構築して Spring Actuator で収集したメトリックスを表示させてみます。

履歴

2018/10/29
初版発行。
2018/11/20
* Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その13 )( Remember Me 認証が使えなくなっていたので調査・修正する ) の結果を反映して auth.inMemoryAuthentication() を書く位置を修正しました。