서비스 간 Passport 통신 최적화 (2)

hbjs97·2024년 7월 29일
1

이전 포스팅에서 Istio EnvoyFilter 를 사용해 http 요청을 후킹하여 헤더를 전파하는 시도를 했으나 실패했다.
EnvoyFilter 의 Inbound, Outbound 는 독립적인 컨텍스트를 가지고 있었고 헤더를 공유할 수 없었다.

gateway → service A 까지는 되는데 service A → service B 는 안된다.
service A 의 inbound 트래픽에서 passport 헤더를 확인하는것까지 확인 가능했으나 outbound 트래픽에서 passport 설정을 실패했다.

EnvoyFilter 를 사용한 다양한 시도끝에 결국 해결하지 못하고 원점으로 돌아왔다.

다른 방법?

두 가지 정도 해결책을 찾을 수 있었다.

  1. 인증/인가 방식 전면 개편
  2. 애플리케이션 레벨에서 Request Context 후킹

이까지 오니 여러 서비스간 통신을 고려하지 못한 시스템 자체에서 근본적인 문제가 있다고 생각했다.
지금 Passport 형태로 사용자 정보를 여러 서비스에 전파해야하는 가장 큰 이유는 SpringSecurity 를 사용하는 부분에 있었다.

RestController 의 엔드포인트에 @PreAuthorize 애노테이션을 사용해 role base 인증을 하고있다. 이를 위해 SecurityContextHolder 에 인증된 컨텍스트를 set 해주는 과정이 선행되어야한다.
그리고, 개발중인 Spring Boot 서비스들은 공통으로 사용하는 UserPrincipal 클래스가 있다.

(1) 이 구조 자체를 뜯어고치는 방법을 먼저 생각했다.
인증/인가를 모두 SpringGateway 서비스에서 수행하고 이후 서비스들은 별도의 검증없이 로직을 수행하는것이다.
Gateway 에서 인증/인가 로직이 방대해지고 문제가 발생할 경우 치명적일 수 있다는 문제점이 있지만, 다른 서비스에서 불필요한 로직을 구현할 필요가 없다는 장점이 있다.
하지만, 이 경우 기존 시스템 구조를 갈아엎어야 하는 부담이 있어서 보류했다. 수정하면서 발생하는 문제역시 무시할 수 없었다.

최대한 변경없이 해결하기 위해 (2) 애플리케이션 레벨에서 Request 를 후킹해서 헤더 정보를 사용하는 방법도 고려했다.
request 에 있는 정보를 infra 레벨에서 사용하자니 중간에 호출되는 함수들에 passport 에 대한 의존성이 생기는 문제가 있었다. 이 문제를 해결하려면 request header 정보를 infra 레벨에서 직접 사용할 수 있어야 한다.
SpringBoot, Nestjs 모두 요청-응답 사이에 컨텍스트가 유지되고 request header 를 후킹해 사용할 수 있었다.

두 가지 방법을 놓고 비교해본 결과 2번 방법이 더 적합하다고 판단했다.

적용

  1. SpringGateway 서비스에서 인증/인가 후 익명 사용자가 아닌경우 passport 정보를 헤더에 주입
  2. 라우팅된 서비스에 따라 passport 정보를 파싱
  • SpringBoot 의 경우
  • NestJS 의 경우
  1. 다른 서비스 요청 시 request header 후킹해서 passport 정보 전파
  • SpringBoot 의 경우(FeignClient 사용)
  • NestJS 의 경우

0개의 댓글