11 프로덕션 레디 서비스 개발

Bonjugi·2022년 8월 29일
0
post-custom-banner

출처 :
마이크로서비스 패턴 (책)

독후감

  • spring security 를 설정할때 gw 에 설정하자
  • 구성서버를 설정했을때 장점들을 알게되었다.
  • 관측 가능한 서비스를 위한 섀시 프레임워크들에 대해서 알게되었다
  • 서비스메시와 구현체인 이스티오에 대해서 알게되었다.

궁금한점

  • gw는 외부 ipc 에 대해서만 처리한다. 그럼 internal call 에 대해서는 인증을 어떻게 처리하나?
  • 분산추적을 프라임->라스트마일->권역 을 이어붙여서 볼수있으면 좋겠다 라고 생각하긴 했는데, 막상 적용된다고 해도 어떤식으로 잘 쓸수 있는지 잘 모르겠다.
  • 우선 로깅 자체는 슬루스만 연동하면 될거같긴 한데, 이걸 제대로 활용하려면 집킨이 있어야 하는 걸까?
  • 우리도 istio라던지 서비스메시 활용 사례가 있을까?

11.1 보안 서비스 개발 (인증, 인가)

4가지 보안 요소 구현해야함.

  • 인증:
  • 인가:
  • 감사: 보안 이슈 탐지, 컴플라이언스 시행, 고객 지원 등의 작업
  • 보안 IPC: tls 쓰면 됨 등

11.1.1 기존 모놀리식 애플리케이션의 보안

기존 모놀리스 FTGO 에서의 방식

  1. 로그인 요청
  2. LoginHandler 가 자격 증명 확인, 세션 생성 (주체 정보 저장 등 일련의 로그인 요청 처리를 수행)
  3. LoginHandler 가 클라이언트에 세션 토큰을 반환
  4. 클라이언트는 이후 모든 작업을 호출할 때마다 세션 토큰을 넣어 보냄
  5. 4번 요청은 SessionBasedSecurityInterceptor 가 제일 먼저 처리. 세션토큰을 확인한 후, 보안컨텍스트를 설정함.
  6. 요청 핸들러는 보안 컨텍스트를 이용하여 권한있는지 판단. 또한 신원 획득 가능.

인메모리 세션의 단점은 sticky 걸어줘야한다.

  • 부하분산 및 작업을 복잡하게 만든다.
  • 이를테면 인스턴스를 닫기전에 모든 세션이 만료되길 기다리는 세션 드레이닝 메커니즘을 구현해야함.
  • 아니면 DB에 세션을 저장하는 우회책 필요

아니면 세션을 아예 없애기.

  • 매 요청마다 API 키/시크릿 등 자격증명을 제공하는 API 클라이언트가 있기 때문에 서버 쪽 세션을 유지할 필요가 없는 어플리케이션도 많다.
  • 아니면 세션 토큰에 세션 상태를 저장하는 방법도 있다.

msa 에서는 보안 구현이 왜 어려울까?

11.1.2 msa 에서 보안 구현

가령 주문 서비스는 소비자 본인의 주문 정보만 조회할수 있어야 한다.
그러려면 인증/인가 를 조합해야 한다.
인증/인가를 누가 담당해야하나?

모놀리식에서 썼던 다음 2가지 방법은 msa 에서 쓸수 없다.

  • 인메모리 보안 컨텍스트
    메모리를 공유할수가 없기 때문에 인메모리 보안컨텍스트를 쓸수 없다.

  • 중앙화 세션
    인메모리 보안 세션도 마찬가지다.
    셰어드 DB 를 쓰면 DB기반 세션을 이용하면 가능은 하지만..

API 게이트웨이에서 인증 처리

여러가지 방법 존재

서비스마다 알아서 사용자를 인증하는 방식
단점 많다.

  • 미인증 요청이 내부 네트웍으로 들어올수 있음
  • 모든 개발자가 제대로 보안 구현하기 어려움
    - 매 요청마다 basic auth 자격증을 전송하는 순진한 클라이언트가 있을수 있음
    • 요청할때마다 세션 토큰을 발급하는 클라이언트도 있을수 있음

게이트웨이에서 하는게 좋다.

  • 인증 로직을 중앙화 하면 나중에 문제생겼을때도 한곳만 보면 됨.
  • 다양한 인증 메커니즘을 gw가 전담하므로 코드 복잡도 낮출수 있음
  • 신원, 역할 등 사용자 정보가 담긴 토큰을 자신이 호출하는 서비스에 전달한다. (액세스 토큰 패턴. feat jwt)

API 클라이언트와(A), 로그인 기반 클라이언트(B) 의 흐름도.

인가 처리

도메인로직. 즉 개별 애그리게잇에 ACL 을 gw 에 구현하는건 무리.
서비스에서 한다.
역할 기반으로 URL 과 메서드를 인가 하고, ACL로 애그리거트 접근을 따로 관리.

JWT로 사용자 신원/역할(identity/ roles) 전달

jwt 는 transparent token 의 표준 규격.
두 당사자 간의 사용자 신원/역할 등의 정보를 안전하게 표현하는 표준 수단.

json payload.

  • 사용자 정보,
  • 만료 일자
  • 각종 메타데이터

jwt 생성자와 수신자만 알수있는 시크릿으로 서명.
제3자가 위변조 하기는 거의 불가능.

하지만 jwt는 토큰 자체가 포함되어 있기 때문에 취소할수 없다.
그래서 만료일자를 짧게해서 탈취되도 뭔가 못하게.
잦은 갱신의 부담은 OAuth 2.0 표준으로 해결 가능.

OAuth 2.0 응용

깃헙, 구글 같은 퍼블릭클라우드 서비스가, 자기 정보에 접근하는 서드파티에게 패스워드 노출 없이 허가할수 있는 방안을 찾다 정착된 프로토콜.

OAuth 2.0 주제는 깊다. 코딩공작소 7장도 괜찮은 참고자료.

  • 인증서버: 대표적인 프레임워크는 Spring OAuth.
  • 액세스 토큰: 구현체마다 포맷이 다름. Spring OAuth 는 JWT 임
  • 리프레시 토큰: 수명은 길지만 취소 가능한 토큰
  • 리소스 서버
  • 클라이언트: 리소스에 접근하려는 클라이언트. 즉 여기선 gw가 클라.

로그인 기반 클라이언트 인증API 클라이언트 인증 가 있다고 했다.

먼저 API 클라이언트 인증 의 흐름.
그림 11.4

다음은 로그인 기반 클라이언트 인증 의 흐름.
그림 11.5

1~4 부분이 클라이언트가 로그인 하는 과정이다. (access_token 과 refresh_token 을 쿠키 형태로 내려준다)
이후 부터는 두 토큰을 요청마다 담아서 보낸다.
그림에는 없지만, 만료된 경우 gw는 인증서버에 리프레시 승인을 요청한다.

11.2 구성 가능한 서비스 설계

외부구성 설정 방식 2가지.

  • 푸시 모델: OS 환경 변수, 구성 파일 등을 통해 배포 인프라에서 서비스로 프로퍼티 값 전달
  • 풀 모델: 서비스가 인스턴스 구성 서버에 접속해서 읽어옴.

11.2.1 푸시기반 외부화 구성

스프링 부트는 외부화 구현 메커니즘을 제공함.

우선순위
1. CLI 인수
2. OS 환경변수
3. jvm 시스템 프로퍼티
4. OS 환경 변수
5. 현재 디렉터리의 구성파일

11.2.2

구성서버는 여러가지 방법으로 구현 가능

  • git, svn..
  • sql/nosql db
  • 전용 구성 서버 (ex. spring cloud config), 해시코프 볼트, AWS 파라미터 스토어

인스턴스 시동할때, 구성 전용 서버에 접속해서 pull.
구성서버 접속 url 정도는 배포 인프라에 등록되어있어야 한다.

spring cloud config server/client?
서버 : 버전관리시스템, DB, 해시코프볼트 등 구성 프로퍼티를 저장하는 다양한 백엔드기술 지원.
클라 : 서버에서 구성 프로퍼티를 가져와 application context에 주입하는 역할

구성서버 장점?

  • 중앙화 구성 : 모든 구성 프로퍼티를 한곳에서 관리. 전역 기본값 정의 등
  • 민감한 데이터의 투명한 복호화 : 구성서버는 자동으로 복호화해서 서비스에 전달함.
  • 동적 재구성 : 수정된 프로퍼티 값을 폴링 등으로 감지해서 재구성함!!

11.3 관측 가능한 서비스 설계

서버 운영자 입장에서, 초당 요청수, 리소스 이용률, 앱의 상태(disk, mem, cpu..) 등등 이 궁금함.

  • 헬스체크 API
  • 로그 수집
  • 분산 추적
  • 예외 추적
  • 애플리케이션 지표
  • 감사 로깅

하드웨어 가용성 자체에대한 모니터링은 aws 알람 등을 활용해도 되지만, 서비스 동작에 대한건 개발자가 해주는것이 좋겠다.
가령 헬스체크 API 제공은 개발자가, 운영자는 API 를 주기적으로 호출하여 시스템 모니터링 이라고 구분하긴 하지만 그냥 다 개발자가 하는경우도 있지.

11.3.1 헬스체크 API 패턴

rdbms 에는 테스트 쿼리를 날리는 식으로 구체적으로 상태체크를 해야한다.
spring boot acuator구성보다 관습(convention over configuration) 이 적용되어 있다.
rdmbs 가 다운되어있거나 rabbitmq 가 가동중인지 헬스체크하는 로직이 자동 구성 되어있다.
즉 health 가 DOWN 상태로, 503을 반환한다.
eb 를 쓰고 있다면 5변 연속 실패시 서비스에서 제외시킨다.

여기서 궁금!
db나 브로커가 문젠건데, 인스턴스가 out of service 되는게 맞는걸까?
새 인스턴스를 띄워봤자 문제는 여전히 발생할것.
근데 로컬에서 테스트해보니, db 를 죽이면 down 으로 바뀌긴 하는데, 다시 살려봤자 up 으로 바뀌진 않더라. 그런의미에서는 새 인스턴스를 띄우는게 도움이 되려나?

11.3.2 로그 수집 패턴

서비스 로그 생성

자바는 로그 3총사(logback, log4j, jul) 가 있고, 퍼사드인 SLF4 를 쓰고 있을것.
기존에는 파일 시스템 경로에 로그 파일이 생성되도록 설정했었다.
그러나 컨테이너, 서버리스 등 요즘 배포에서는 stdout 에 로깅한다.
(서버리스는 파일시스템 자체가 없다)
서비스의 stdout 을 갖고 뭘 할지는 배포 인프라가 결정함.

로그 수집 인프라

보통 elk 를 쓴다.

11.3.3 분산 추적 패턴

외부 요청마다 유일한 ID (traceId) 를 부여한다.
trace는 하나 이상의 Spen 으로 구성된다. (최상위는 gw 일거고, 계속 자식 스팬이 생성된다)
작업명, 시작/종료 타임스탬프 등 으로 구성되어있다. (mdc context 를 볼수있게 되어있지 않을까 싶다)

instrumentation library 와 추적서버로 구성되어있다

instrumentation 라이브러리

각 서비스는 외부 요청이 들어올때마다 traceId 를 할당. 서비스 간 상태 추적을 전파하면서 분산 추적 서버에 스팬을 보고 한다.
AOP 프레임 워크인 스프링 클라우드 슬루스 를 쓰면 알아서 분산 추적 API 를 호출한다.

분산 추적 서버

instrumentation 라이브러리가 보고한 스팬을, 짜깁기 해서 완전한 트레이스 형태로 만들어 DB 에 저장한다.

집킨 은 잘 알려진 분산 추적 서버이다.
sql/no sql db 같은 저장소에 보관한다.
화면 ui 도 있다.
aws 엑스레이도 분산 추적 서버의 일종이다.

x-ray 는 비용과 효율이 좋지 않다고 하더라.
집키이든 x-ray든 번거로우면 그냥 슬루스만 쓰라고 하더라. 연동도 쉽고

서비스에서 서비스로 흘러가는 과정을 기록
traceId 로는 해당 요청의 모든로그를 찾을수 있다.

11.3.4 애플리케이션 지표 패턴

서비스 수준의 지표 수집

다음은 마이크로미터 메트릭스 라는 라이브러리를 사용한 예시코드이다.

public class OrderService {

  @Autowired
  private MeterRegistry meterRegistry;

  public Order createOrder(...) {
    ...
    meterRegistry.counter("placed_orders").increment();
     return order;
  }

  public void approveOrder(long orderId) {
    ...
    meterRegistry.counter("approved_orders").increment();
   }

  public void rejectOrder(long orderId) {
    ...
    meterRegistry.counter("rejected_orders").increment();
   }

지표 서비스에 지표 전달

push 방식 : aws cloudwatch
pull 방식 : 프로메테우스.

Ftgo 는 micrometer-registry-prometheus 라이브러리로 연계한다.
라이브러리 추가후, GET /actuator/prometheus 하면 프로메테우스가 기대한 포맷으로 지표를 가져올수 있다.

아래는 지표 포맷.

$ curl -v http://localhost:8080/actuator/prometheus | grep _orders
# HELP placed_orders_total
# TYPE placed_orders_total counter
placed_orders_total{service="ftgo-order-service",} 1.0
# HELP approved_orders_total
# TYPE approved_orders_total counter
approved_orders_total{service="ftgo-order-service",} 1.0

11.3.5 예외 추적 패턴

중복된 예외를 제거하고, 알림을 생성하고, 예외 해결 과정을 관리하는 중앙 서비스에 예외를 보고한다.
sentry나 허니배저가 있다.

11.3.6 감사 로깅 패턴

고객지원, 컴플라이언스 준수, 수상한 동작 감지를 위해 사용자 액션을 DB에 저장한다.

  • 감사 로깅 코드를 비즈니스 로직에 추가
    - 직접구현은 좋지 않다. 아래 AOP 를 활용하자
  • AOP 활용
    - 메서드명과 인수에만 접근 가능하다는 단점이 있다는데.. 딱히 문제가 되나?
  • 이벤트 소싱 이용
    - 사용자 신원을 각각의 이벤트에 기록하면 된다.

11.4 서비스 개발: 마이크로서비스 섀시 패턴

11.4.1 마이크로서비스 섀시

마이크로서비스 섀시 프레임워크를 써서 횡단관심사를 해결하자.

  • 외부화 구성

  • 헬스 체크

  • 지표

  • 서비스 디스커버리

  • 회로 차단기

  • 분산 추적

  • 외부화 구성 스프링부트

  • 회로차단기 - 스프링클라우드

11.4.2 이제는 서비스 메시로

마이크로서비스 섀씨는 다양한 횡단 관심사를 구현하기 좋은수단.
하지만 다른 언어에는 소용이 없다.

서비스메시 패턴이란?

  • 회로차단기, 분산추적, 디스커버리, 부하분산, 룰기반 트래픽 라우팅
  • 등의 다양한 관심사가 구현된 네트워킹 계층을 통해 드나드는 모든 네트워크 트래픽을 라우팅 한다.
  • 구현한 제품으로는 이스티오, 링커드, 콘듀이트가 있다.
post-custom-banner

0개의 댓글