우리는 보안쪽을 라이브러리화를 하려다 보니 인증/인가에 대한 생각이 많아졌다.
그중에 Netfilx의 Passport라는 개념을 우리프로젝트에 적용 할 생각인데, 마침 toss도 passport를 활용한다기에 공부를 해보았다.
Route - Predicate, Filter
라우트는 이렇게 두개로 나뉜다.
Predicate | 요청을 구분 Path, Method,Host 요청을 매칭 |
Filter | 매칭된 요청에 대한 전처리나 서비스의 응댑에 대한 후처리를 구현 |
하나의 Route안에 여러개의 필터 선언가능, Gateway는 순서에따라 필터를 처리한다.
공통로직을 Gateway로 몰아두면 하나의 커다란 모놀리틱 서비스가 됩니다.
Web에서 필요한 로직과 App에서 필요한 로직이 다르지만 게이트웨이는 이 두가지 로직을 모두 가져야 합니다.
이를 해결하기위한 패턴이 BFF패턴입니다.
Client에 맞는 하나의 백엔드를 사용하는 패턴이다.
이를통해 Client별로 관심사를 분리, 전략을 가져간다.
web에서오는 요청은 webGateway가 app은 appGateway가 해당로직을 처리한다.
Client목적에 맞는 Gateway를 사용하여 route를 추가하고 해당 라우트에 필요한 로직을 넣어 서비스로서의 요청을 만든다.
공통로직 처리방식
<Request처리>
gateway에서 request를 sanitize하는것
sanitize는 클라이언트로부터 올바르지 않은 요청이 올 경우 이를 지워주거나 올바른 값으로 바꿔주는것을 의미한다.
사용자가 악의적으로 값을주고 요청하더라도 게이트웨이에서 이를 올바른 값으로 변경해 넘겨준다.
하나의 트랜잭션 안에 여러서비스에서 공통으로 필요한 정보가 있을수 있다.
기존에는 모든 서비스가 공통 api를 요청 이는 불필요한 반복요청이 발생된다. -> gateway에서는공통으로 필요한 정보를 internal Header주입하여 서비스로 전달
서비스에서는 internal Header에서 필요한값을 추출해 사용
각 서비스는 약관 api를 요청할필요없이 헤더에서 정보를 가져와 사용한다.
이를 통해 트랜잭션 내 중복요청을 상당 수 줄인다.
User처리 방식
모든 서비스에서 유저정보가 필요할때 유저 api를 호출하여 정보를 가져온다. --> 트랜잭션 내에 불필요한 중복요청 서버리소스의 낭비
넷플릭스의 Passport구조 참고
유저 인증시에 Passport라는 ID토큰을 트랜잭션 내로 전파하는 방법을 사용한다.
Passport 는 사용자 기기정보와 유저정보를 담은 하나의 토큰이다.
app에서 유저식별키와 함께 API를 요청하게 되면 게이트웨이에서 이키를 토대로 인증서버에 Passport 를 요청한다.
Passport 에는 사용자 기기정보와 유저정보를 담겨있고 Gateway는 이를 Serialize하여 서비스에 전파한다.
유저정보가 필요한 서비스는 유저정보호출없이 Passport 정보를 통하여 유저 정보 호출없이 유저정보를 사용할 수 있다.
보안과 안정성
종단간 암호화를 통해 패킷분석의 허들을 높여 안전하게 정보를 전달한다.
APP에서 암호화키를 이용하여 요청 바디를 암호화하고 Gateway에서 복호화하여 서비스에 전달합니다.
복화하 과정에서 인증/인가 로직이 처리되고 복호화된 데이터와 유저정보를 서비스로 넘겨주게 된다.
게이트웨이에서 이과정을 전부처리 서비스에서는 편하고 안전하게 사용자의 요청을 처리하게 된다.
프론트의 SSR과 같이 종단간 암호화를 사용하기 어려운 스펙을 개발하는 경우 Gateway 에서는 jwt를 통한 api요청 기능도 지원한다.
client는 매 요청마다 새로운 토큰을 만들고 이를 public Gateway 로 전달, public Gateway 에서는 해당토큰의 서명값, 유효기간, 중복사용여부 , 만료여부 검증 ReplayAttack이나 토큰변조 방지
검증된 토큰을 프프론트의 node서버에 전달 SSR - Gateway 를 통해 업스트림 서비스에 전달
SSR - Gateway 에서는 토큰을 통해 유저정보를 가져와 알맞은 업스트림 서비스를 전달하는 역할을 하고 있다.
OAuth2 를 활용
허가된 Client가 접근 토큰을 발급받을 수 있도록 미리 식별자와 시크릿 키를 발급해주고 허가된 Client는 접근 토큰을 요청에 실어 보낸다.
Gateway 에서는 접근토큰이 유효한지 내부의 Oauth서버에게 질의하여 확인한 후 요청한 api가 해당 토큰이 접근할 수 있는 범위의 요청인지 판단하여 서비스로 요청을 전달하게 된다.
인증/인가를 넘어서 각요청이 실제로 위변조되지않았는지 토스에서만들어진 요청인지도 검증한다.
토스는 내부적으로 매 요청을 서명할 아주 짧은 유효기간을 가진 안전한 키값과 변조되지않은 토스에서만 알수 있는 정보를 활용하여 각요청을 서명하고 Gateway 로 보낸다. Gateway 에서는 각 요청에 들어있는 서명값을 통해서 토스에서 만들어진 요청인지 중복해서 사용되진 않았는지 유효기간이 만료된 키로 만들어지지 않았는지 검증
App 위변조, Delayed Request, Replaying Attack Block을 방지하고 의심스로운 요청이 발견시 FDS를 통해 계정을 비활성화하여
사용자를 안전하게 보호한다.
또한 각 요청단위의 유효성 검증을 넘어서 유저의 모든 행위 기반 로그 분석으 ㄹ통한 의심스러운 행동을 막는 기능 제공
의심스러운 행동 발견시 Gateway 로 유저정보를 넘기게 된다. 이를 기반으로 IPS차단을 통해 전체 서비스를 막는 것이 아닌 특정유저 ip 디바이스가 특정 api나 서비스를 못하게 하도록 정교한 차단을 시켜 안전하게 보호한다.
Gateway 에서는 외부회사나 내부개발자의 서비스 호출을 위해 클라이언트 인증서를 위한 mTLS API호출도 지원한다.
서비스안정화
마이크로 서비스아키텍쳐 패턴은 많은서비스들이 거미줄처럼 서로 상호작용을한다.
따라서 하나의 서비스에서 응답지연이 발생하면 해당서비스에 의존하는 수많은 서비스들에게 응답지연이 전파된다.
이렇게 퍼져나간 응답지연이 시스템의 자원을 점유하여 모든 시스템이 먹통이 되는 상황이 발생한다.
이를 방지하기 위해서는 응답지연을 유발하는 서비스에게 요청을 더이상 보내지않고 빠르게 실패하게 하여 부하를 겪고있는 서비스가 회복할 수 있게 하고 이러한 응답 지연이 전체서비스로 확산되지 않게 하는것이 중요하다.
이를 서킷 브레이크라고 부른다.
또한 내부 서비스간의 서킷 브레이킹도 중요하지만 근원적인 트래픽을 발생시키는 Client에게 백프리셔를 빠르게 주기위해서는 게이트웨이에서 서킷 브레이킹을 거는것이 중요하다.
서킷 브레이크를 적용하는 방법엔 Istio 를 활용한 이프라 레이어의 서킷 븍레이킹 혹은 Resiljence4, Hystrix와 같은 라이브러리를 이용한 애플리케이션 레이어의 서킷 브레이킹이 있습니다.
각 방법에는 장단점이 존재한다.
Istio 활용한다면 호스트 단위로 쉽고 빠르게 전체 적용이 가능 애플리케이션의 개발 주기와 독립적으로 관리될 수 있다는 장점이 있지만, Istio 는 호스트 단위로만 서킷 브레이킹 설정이 가능하며 설정할 수 있는 룰에도 한계가 있다.
각 애플리케이션이나 gateway에 서킷브레이킹을 적용함으로써 호스트나 라우트 단위 혹은 기능단위로 정교하게 서킷 브레이킹을 걸고있다.
아직 다른것들은 실제로 많이 와닿는다 라는 느낌이 없지만, 공통로직이나 User처리 부분은 프로젝트에 적용할 수 있는 부분이 꽤많다고 느낀다.
이를 더 공부해야겠다는 생각이 들었다.
특히나 Passport 개념이라던가, internalHeader에 정보를 담겨서 넘기는 방식 등 이런것들을 잘 활용해서 프로젝트에 녹이면 될것같다.
'개발관련' 카테고리의 다른 글
Netfilx는 PassPort ? (1) | 2024.09.27 |
---|---|
<캡슐화> JPA 엔티티 생성시 Setter를 지양하는이유 (0) | 2024.09.24 |
MSA 기반 물류관리 및 배송시스템 프로젝트를 마치며... (0) | 2024.09.24 |
Gateway 에 관하여 내가 프로젝트를 진행하면서 해야할것 (2) | 2024.09.13 |
[Spring Security] @EnableMethodSecurity와 @EnableGlobalMethodSecurity (0) | 2024.09.10 |