Spring Security 統合

Spring Cloud Gateway Server MVC は Spring Security と連携して、安全な経路を確保し、トークンを下流サービスに中継します。

依存関係

ゲートウェイに Spring Security を追加するには、以下のスターターを 1 つ以上含めてください。

pom.xml
<!-- Core security (authentication and authorization) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- OAuth2 login and token relay to downstream services -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

<!-- Resource server: validate JWT or opaque tokens on each request -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

デフォルトの動作

spring-boot-starter-security がクラスパス上にある場合、Spring Boot はすべてのリクエストに認証をリクエストする SecurityFilterChain を自動的に構成します。ゲートウェイルートのアクセスルールをカスタマイズするには、明示的に SecurityFilterChain Bean を指定してください。

次の例では、認証なしでヘルスチェックエンドポイントを許可し、その他のすべてのリクエストには有効な JWT をリクエストします。

RouteSecurityConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class RouteSecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/actuator/health/**").permitAll()
                    .anyRequest().authenticated())
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }
}

HTTP ファイアウォール

Spring Security には、エンコードされたパス区切り文字(%2F)、二重スラッシュ(//)、バックスラッシュなど、特定の文字を含む URL を持つ HTTP リクエストを拒否する StrictHttpFirewall が含まれています。これらのパターンは、そのようなパスを受け入れる下流サービスにリクエストをプロキシするゲートウェイでは正当な場合があります。

ゲートウェイがルートが一致する前に 400 Bad Request でリクエストを拒否している場合、StrictHttpFirewall がブロックしている可能性があります。以下のように緩和することができます。

RouteSecurityConfiguration.java
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;

@Configuration
@EnableWebSecurity
public class RouteSecurityConfiguration {

    @Bean
    public HttpFirewall relaxedHttpFirewall() {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setAllowUrlEncodedSlash(true);         // allow %2F in path
        firewall.setAllowUrlEncodedDoubleSlash(true);   // allow %2F%2F
        firewall.setAllowBackSlash(true);               // allow \ in path
        return firewall;
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.httpFirewall(relaxedHttpFirewall());
    }
}

下流サービスが明示的に要求し、かつ脅威モデルがその影響を考慮している場合にのみ、StrictHttpFirewall の要件を緩和してください。詳細は Spring Security HTTP ファイアウォールのリファレンスを参照してください。

トークンリレー

ゲートウェイが OAuth2 クライアントとして動作する場合、現在認証されているユーザーのアクセストークンを下流サービスに転送できます。使用方法と必要な依存関係については、TokenRelay フィルターのドキュメントを参照してください。

参考文献

SecurityFilterChain、メソッドのセキュリティ、OAuth2 統合の詳細については、Spring Security サーブレットアプリケーションのリファレンスを参照してください。