프로덕션 레디 서비스 개발
핵심 내용
- 보안 서비스 개발
- 외부화 구성 패턴 적용
- 관측성 패턴 적용
- 마이크로서비스 섀시 패턴을 응용한 서비스 개발 단순화
보안 서비스 개발
- 애플리케이션 개발자가 주로 구현하는 네 가지 보안 요소
- 인증(Authentication): 애플리케이션에 접근하는 애플리케이션이나 사람의 신원 확인
- 인가(Authorization): 주체가 어떤 데이터에 어떤 작업을 요청하여 수행할 수 있는 권한이 있는지 확인
- 감사(auditing): 보안 이슈 탐지, 컴플라이언스 시행, 고객 지원을 위해 주체가 수행하는 작업 추적
- 보안 IPC
기존 모놀리식 애플리케이션의 보안
애플리케이션의 클라이언트가 인증을 요청하는 과정
- 사용자: ID/패스워드로 로그인
- 클라이언트: 사용자 자격증명을 애플리케이션에 POST로 요청
- 애플리케이션: 자격증명이 맞으면 클라이언트에 세션 토큰을 반환
- 클라이언트: 이후 요청은 모두 이 세션 토큰을 포함시켜 전송
보안 아키텍처에서의 핵심은 세션(session)
- 주체의 ID와 역할은 세션에 보관
- 자바 애플리케이션은 HttpSession 객체를 메모리에서 관리
- 예: FTGO 애플리케이션의 세션 토큰은 JESSIONID라는 HTTP 쿠키
보안 컨텍스트(security context)
- 현재 요청을 보낸 사용자 정보를 보안 컨텍스트에 저장
- 자바 EE 표준에는 보안 컨텍스트를 정적 스레드 로컬 변수에 저장
- 모든 요청 핸들러 코드가 얼마든지 보안 컨텍스트에 접근 가능
마이크로서비스 아키텍처에서의 보안 구현
- MSA는 모든 외부 요청을 API 게이트웨이와 하나 이상의 서비스가 처리하는 분산 시스템
- MSA에서 보안을 구현하려면 먼저 사용자의 인증/인사 처리를 누가 담당할지부터 결정해야함
- 모놀리식에서는 통했지만 MSA에서는 사용할 수 없는 방법들
- 인-메모리 보안 컨텍스트
- 중앙화 세션
- MSA에서는 다른 방식이 필요
API 게이트웨이에서 인증 처리
- 인증 처리 방법
- 서비스마다 알아서 사용자를 인증하는 방식
- 미인증 요청이 내부 네트워크에 들어올 수 있음
- 모든 개발자가 제대로 보안을 구현하리라 보기 어렵기에 보안 취약점 노출 위험성이 큼
- 인증하는 방식이 클라이언트마다 제각각일 수 있음
- 요청을 서비스에 보내기 전에 API 게이트웨이가 요청을 인증하는 방식(추천)
- 인증 로직을 API 게이트웨이에 중앙화하면 나중에 문제가 생겨도 한곳만 수정하면 되기에 보안 취약점 노출 가능성이 줄어듬
- 복잡한 코드도 서비스에서 감출 수 있음
- 처리 방식
- API 클라이언트: 자격증명을 포함시켜 요청 전송 후 세션 토큰 발급 받음
- API 게이트웨이: 요청을 인증 후, 하나 이상의 서비스를 호출
- 서비스마다 알아서 사용자를 인증하는 방식
인가 처리
- 해당 클라이언트가 요청한 작업을 할 수 있도록 허가되었는지 검사하는 인가 메커니즘 역시 중요함
- 인증처럼 인가 로직도 API 게이트웨이 내부에 중앙화하면 보안을 강화할 수 있지만 추천 하지 않음
- API 게이트웨이와 서비스가 단단히 결함하게 되어서 나중에 변경할 일이 생기면 서로 맞물리게 될 수 있음
- 역할 기반의 URL 경로 접근만 구현할 수 있으며, 개별 도메인 객체의 접근 권한을 제어하는 ACL(접근 제어 목록) 까지 구현하기에는 무리
- 인가 로직은 서비스에 구현하는 것이 좋음
- 서비스가 직접 역할 기나으로 URL과 메서드를 인가하고, ACL로 애그리거트 접근을 따로 관리
JWT로 사용자 신원/역할 전달
- API 게이트웨이가 어떤 종류의 토큰에 사용자 정보를 담아 서비스에 전달할지 결정해야함
- 토큰 종류
- 난독화 토큰
- UUID가 많이 사용되며, 성능 및 가용성이 떨어지고 지연 시간이 길다는 것이 단점
- 보안 서비스 호출이 필요 없는 투명 토큰
- JWT(JSON Web Token)이 사실상 투명 토큰의 표준
- 두 당사자 간의 사용자 신원/역할 등의 정보를 안전하게 표현하는 표준 수단
- 각종 메타데이터가 포함된 JSON 객체를 페이로드에 담아 JWT 생성자와 JWT 수신자만 알 수 잇는 시크릿으로 서명함
- JWT는 토큰 자체가 포함되어 있기 때문에 취소할 수 없는 문제가 있음
- 유효 기간이 짧은 JWT를 발급해야함
- 난독화 토큰
OAuth 2.0 응용
- OAuth 2.0: 퍼블릭 클라우드 서비스 사용자가 자기 정보에 접근하려는 서드파티 애플리케이션을 패스워드 노출 없이 허가할 수 있는 방안을 찾다가 정착된 인증 프로토콜
- OAuth 2.0을 애플리케이션의 인증/인가 용도로도 사용할 수 있음
- OAuth 2.0 핵심 개념
- 인증 서버
- 액세스 토큰
- 리프레시 토큰
- 리소스 서버
- 클라이언트
- API 클라이언트의 요청을 API 게이트웨이가 인증하는 과정
- 클라이언트는 기본 인증을 이용하여 자격증명과 함께 요청
- API 게이트웨이는 OAuth 2.0 인증 서버에 패스워드 승인을 요청
- 인증 서버는 API 클라이언트의 자격증명을 검증하고 엑세스/리프레시 토큰을 반환
- API 게이트웨이는 서비스에 요청을 할 때마다 발급받은 엑세스 토큰을 넣어 보내고, 서비스는 액세스 토큰을 이용하여 요청을 인증
- 액세스 토큰을 세션 토큰처럼 이용해서 세션 지향 클라이언트를 인증할 수 있음
- 로그인 기반의 클라이언트가 자격증명을 API 게이트웨이에 POST
- API 게이트웨이의 로그인 핸들러는 OAuth 2.0 인증 서버에 패스워드 승인을 요청
- 인증 서버는 클라이언트의 자격증명을 검증 후, 액세스/리프레시 토큰을 반환
- API 게이트웨이 인증 서버에서 받은 두 토큰을 클라이언트에 반환
- 클라이언트는 액세스/리프레시 토큰을 API 게이트웨이에 요청할 때마다 실어 보냄
- API 게이트웨이의 세션 인증 인터셉터는 액세스 토큰을 검증 후 서비스에 토큰을 넣어 보냄
구성 가능한 서비스 설계
- 여러 구성 프로퍼티를 소스 코드에 미리 하드 코딩해 놓거나, 스프링 프레임워크의 프로파일 장치로 런타임에 프로퍼티 세트를 선택하는 구조는 보안에 취약하고 배포에 한계가 있어서 적절치 않음
- 런타임에 구성 프로퍼티 값을 서비스에 제공하는 외부화 구성 메커니즘
- 푸시 모델: OS 환경 변수, 구성 파일 등을 통해 배포 인프라에서 서비스로 프로퍼티 값 전달
- 풀 모델: 서비스 인스턴스가 구성 서버에 접속해서 프로퍼티 값을 읽어옴
푸시 기반의 외부화 구성
- OS 환경 변수, 구성 파일 등을 통해 배포 인프라에서 서비스로 프로퍼티 값 전달
- 도커 컨테이너를 통해 환경 변수를 지정하는 방법
- 스프링 부트
- CLI 인수
- JVM 시스템 프로퍼티
- OS 환경변수
- 현재 디렉터리의 구성 파일
풀 기반의 외부화 구성
- 서비스 인스턴스가 구성 서버에 접속해서 프로퍼티 값을 읽어옴
- 버전 관리 시스템
- SQL/NoSQL DB
- 전용 구성 서버(스프링 클라우드 컨피스 서버), 해시코프 볼트, AWS 파라미터 스토어
- 스프링 클라우드 컨피그
- 서버/클라이언트로 구성된, 유명한 구성 서버 기반 프레임워크
- 서버: 버전 관리 시스템, DB, 해시코프 볼트 등 구성 프로퍼티 를 저장하는 다양한 백엔드 기술 지원
- 클라이언트: 서버에서 구성 프로퍼티를 가져와 스프링 ApplicationContext에 주입하는 역할
- 구성 서버 장점
- 중앙화 구성
- 민감한 데이터의 투명한 복호화
- 동적 재구성
관측 가능한 서비스 설계
- 관측 가능한 서비스를 설계하는 패턴
- 헬스 체크 API: 서비스 헬스를 반환하는 끝점을 표출
- 로그 수집: 서비스 활동을 로깅하면서 검색/경고 기능이 구현된 중앙 로그 서버에 로그 출력
- 분산 추척: 각 외부 요청에 ID를 하나씩 붙여 서비스 사이를 드나드는 과정을 추적
- 예외 추적: 예외 중복 제거, 개발자 알림, 예외별 해결 상황 추적 등을 수행하는 예외 추적 서비스에 예외를 보고
- 애플리케이션 지표: 서비스는 카운터, 게이지 등 지표를 유지하고, 수집한 데이터를 지표 서버에 표줄
- 감사 로깅: 사용자 액션을 로깅
헬스 체크 API 패턴
- 서비스는 서비스 상태를 반환하는 GET /health 등의 헬스 체크 API로 엔드포인트를 표출함
헬스 체크 엔드포인트 구현
- 헬스 체크 엔드포인트를 구현한 코드는 서비스 인스턴스의 상태를 어떻게든 판단해야함
- 스프링 부트 액추에이터는 /actuator/health 엔드포인트를 호출하면 헬스 체크 실행 결과를 반환함
헬스 체크 엔드포인트 호출
- 호출하는 코드가 없으면 헬스 체크 엔드포인트는 쓸모가 없기에 서비스를 배포할 때 배포 인프라가 헬스 체크 엔드포인트를 호출하도록 구성해야함
- 헬스 체크 엔드포인트 호출 방법
- 서비스 레지스트리(예: 넷플릭스 유레카)가 헬스 체크 엔드포인트를 호출하도록 구성해서 서비스 인스턴스로 전송이 되었는지 확인
- 도커, 쿠버네티스로 구성하는 방법은 12장에서 설명
로그 수집 패턴
- 전체 서비스 로그를 중앙 DB에 수집하여 검색/알림 기능을 제공
- 모든 서비스 인스턴스가 남긴 로그를 로그 수집 파이프라인을 통해 중앙 로깅 서버로 보내는 것
서비스 로그 생성
- 적절한 로깅 라이브러리를 선택한 후, 로그 항목을 어디에 출력할지 결정 필요
- 자바 로깅 라이브러리
- 로그백, Log4J, JUL, Slf4J
- Node.js 로깅 라이브러리
- Log4js
- 로그를 남길 장소 결정
- 파일 시스템 경로에 로그 파일 생성(기존방식)
- AWS 람다는 파일 시스템 자체가 없으므로 stdout에 로깅
로그 수집 인프라
- 로깅 인프라는 로그를 수집, 저장함
- 대표적인 로깅 인프라: ELK 스택
- 엘라스틱 서치: 로깅 서버로 쓰이는 텍스트 검색 지향 NoSQL DB
- 로그 스태시: 서비스 로그를 수집하여 엘라스틱 서치에 출력하는 로그 파이프라인
- 키바나: 엘라스틱 서치 전용 시각화 툴
- 오픈 소스 로그 파이프라인: Fluentd, 아파치 플룸
- 로깅 서버: AWS 클라우드워치 로그 등
분산 추적 패턴
- 외부 요청마다 유일한 ID를 하나씩 부여해서 한 서비스에서 다음 서비스로 흘러가는 과정을 기록하고, 시각화/분석 기능을 제공하는 중앙화 서버에 자료를 남김
- 각 요청은 하나의 트레이스로 표시됨
- 스팬: 작업을 나타내며, 작업명, 시작/종료 타임스탬프가 주요 속성이며 자식 스팬을 거느릴 수 있음
- 트레이스: 하나 이상의 스팬으로 구성
- 분산 추적은 각 서비스에 쓰이는 인스트루멘테이션 라이브러리와 분산 추적 서버 두 부분으로 구성
인스트루멘테이션 라이브러리
- 스팬 트리를 만들어서 분산 추적 서버로 보냄
분산 추적 서버
- 전달받은 스팬을 서로 짜깁기해서 와넞ㄴ한 트레이스 형태로 만든 후 DB에 저장
- 잘 알려진 분산 추적 서버: 오픈 집킨
애플리케이션 지표 패턴
- 서비스는 수집, 시각화, 알림 기능을 제공하는 중앙 서버로 지표를 보고
서비스 수준의 지표 수집
- 스프링 부트 기반의 서비스는 마이크로미터 메트릭스라는 라이브러리를 디펜던시로 추가하고 구성 코드 몇 줄만 넣으면 기본 지표는 바로 수집 가능
- 애플리케이션의 특정한 지표를 수집하고 싶다면 마이크로미터 메트릭스 API를 직접 호출하는 코드를 서비스에 작성하면 됨
지표 서비스에 지표 전달
- 수집한 지표를 푸시 또는 풀 방식으로 메트릭스 서비스에 전달함
- 푸시 모델
- 서비스 인스턴스가 API를 호출하여 메트릭스 서비스에 지표를 밀어 넣는 방법(예: AWS 클라우드워치)
- 풀 모델
- 메트릭스 서비스(또는 로컬에서 실행되는 에이전트)가 서비스 API를 호출하여 서비스 인스턴스에서 지표를 당겨오는 방법(예: 프로메테우스)
- 애플리케이션 지표는 애플리케이션의 동작을 파악하는 중요한 단서 제공
예외 추적 패턴
- 서비스는 중복된 예외를 제거하고, 알림을 생성하고, 예외 해결 과정을 관리하는 중앙 서비스에 예외를 보고함
감사 로깅 패턴
- 고객 지원, 컴플라이언스 준수, 수상한 동작 감지를 위해 사용자 액션을 DB에 저장
감사 로깅 코드를 비즈니스 로직에 추가
애스팩트 지향 프로그래밍 활용
이벤트 소싱 이용
서비스 개발: 마이크로서비스 섀시 패턴
마이크로서비스 섀시
- 예외 추적, 로깅, 헬스 체크, 외부화 구성, 분산 추적 등의 횡단 관심사를 처리하는 프레임워크를 기반으로 서비스를 구축
참고
- 마이크로서비스 패턴 자바(저 : 크리스 리처드슨)
'dev > 아키텍처' 카테고리의 다른 글
마이크로서비스 패턴(8) (0) | 2022.04.14 |
---|---|
마이크로서비스 패턴(7) (0) | 2022.04.06 |
마이크로서비스 패턴(6) (0) | 2022.03.31 |
마이크로서비스 패턴(5) (0) | 2022.03.24 |
마이크로서비스 패턴(4) (0) | 2022.03.10 |