04.인증 및 인가 처리
인가처리
글1
- 일반적으로 MS를 위한 인증 및 인가를 API gateway에게 위임한다.
- 이 때, 악의적으로 망을 우회하여 MS로 직접 접근을 하는 것을 방지하기 위해 추가적인 작업이 필요하다
- 각 MS에서 특정 API gateway에서만 온 요청을 처리하도록 접근 가능한 호스트 IP를 제한한다.
- 그리고 각 MS에서는 API gateway에서 처리한 불필요한 작업(사용자 DB조회, 인가 서비스 호출)을 최소화하는 것이고, 필요에 따라 추가 인증 및 인가 처리를 해야한다
- 또한 API GW뿐만 아니라 MS간 통신, 즉 server-to-server에 대한 인증을 구현할 필요도 있다.
- 그리고 사용자의 정보를 인증 토큰에 담아서 보내기도 하는데 이 때 그 데이터를 읽으려면 MS에서 서명된 토큰을 검증하는 작업 등이 필요할 수 있다
글2
- API GW는 클라이언트로부터 요청을 받아 인증 및 인가 로직을 처리하고, 실제 MS에 대한 호출을 중개하는 역할을 수행한다.
- GW를 우회하여 직접 MS에 접근하는 위험이 있을 수 있다.
- 따라서 MS에서도 적절한 인가 체계를 구현해야 한다.
- GW에서는 요청을 검증하고 필요한 인가 체계를 적용한 후, 검증된 요청만이 MS로 전달된다.
- MS에서는 요청을 받아들이기 전에 추가적인 인가 로직을 수행할 수 있다.
- MS에서 추가적인 인가 로직을 위해 OAuth, JWT(Json Web Tokens), API토큰 등을 사용하여 인증과 인가를 구현할 수 있다.
- 또한 필요에 따라 API GW와 MS 간에 보안 프로토콜(예:HTTPS)를 사용하여 통신을 암호화 할 수도 있다.
글3
- 토큰 기반 인증 절차
- 서비스 사용자는 자신의 신원을 증명하기 위해서 인증 서비스로부터 토큰을 발급받는다.
- 사용자는 발급받은 토큰을 서비스 요청 명령에 첨부하여 서비스에게 전달한다.
- 명령을 수신한 서비스는 첨부된 토큰을 확인하여 인증 절차를 수행하고 사용자 인증 정보를 확인한다.
- 토큰 기반의 인증 방식은 크게 위의 절차를 따른다.
- 이 절차는 토큰의 종류와 처리방식에 따라 인증 서비스와 다른 서비스 간의 의존성 정도에도 큰 차이가 나타날 수 있다.
- 몇 가지 토큰과 다른 처리 방식을 알아보고 의존성에 어떠한 변화가 있는지 확인해보자
- 사용자 인증 정보는 인증을 통해 얻을 수 있는 사용자 정보로 단순 사용자ID부터 권한 및 다양한 사용자 메타 정보까지, 시스템에 구현된 인증 서비스에 따라 다양할 수 있다.
엑세스 토큰(Access Token)인증
- 엑세스 토큰은 사용자를 특정하기 위해 인증 서비스가 랜덤하게 생성한 고유 식별자로, 엑세스 토큰 자체로는 어떠한 정보도 담고 있지 않다
- 그러나 인증 서비스는 토큰 발급 시 생성된 엑세스 토큰과 사용자 인증 정보를 맵핑하여 저장하기 때문에 엑세스 토큰을 키로 하여 사용자 정보를 확인할 수 있다.
- 인증 절차
- 사용자는 엑세스 토큰을 첨부하여 서비스에게 명령을 요청
- 서비스는 엑세스 토큰을 인증 서비스에게 전달하여 사용자 인증 정보 확인을 요청
- 인증 서비스는 수신된 엑세스 토큰에 맵핑된 사용자 인증 정보를 서비스에게 전달
- 서비스는 인증 서비스로부터 전달받은 사용자 인증 정보를 기반으로 요청을 처리
- 단점으로는
- 서비스는 요청된 모든 명령 처리를 위해 인증 서비스에 질의 해야 하며 그에 따라 강한 의존성을 갖게 된다.
- 이러한 상황에서 인증 서비스에 장애가 발생하면 전체 서비스로 장애가 전파될 수 있다.
JWT(Json Web Tokens) 인증
- 엑세스 토큰과 다르게 JWT는 토큰 스스로가 사용자 인증 정보를 가지고 있다
- 인증 서비스는 토큰 발급 시 Base64로 인코딩된 json 형식의 사용자 인증 정보와 해당 인증 저보의 위변조 검증을 위한 시그니처(Signature)를 토큰에 첨부하여 함께 제공
- 첨부된 시그니처는 인증 서비스가 발급한 공개-키(Public-key)를 통해 검증 가능하다.
- JWT 검증 절차
- 사용자는 JWT를 첨부하여 서비스에게 명령을 요청
- 서비스는 미리 발급받은 공개-키를 사용해 JWT의 유효성을 검증
- 서비스는 유효성이 검증된 JWT를 Base64를 이용해 사용자 인증 정보를 디코드한다
- 서비스는 디코드 된 사용자 인증 정보를 기반으로 요청을 처리
- 토큰 스스로가 사용자 정보를 포함하고 있는 덕분에 서비스들은 인증 서비스와 별도의 의존성을 갖지 않게 되었다.
- 반면 이러한 특성으로 발생할 수 있는 문제점 또한 존재한다
- 발급된 토큰 관리의 어려움,
- 엑세스 토큰의 경우, 인증 서비스가 발급된 토큰 정보를 중앙에 저장, 관리하고 있으며 각 서비스들은 토큰 검증을 위해서 인증 서비스에 질의해야하는 반면
- JWT의 경우 한번 발급된 토큰은 분산되어 의존성 없이 스스로 인증되기 때문에 비교적 관리에 어려움이 있다.
- 1) 접근제어, 이미 토큰이 발급된 특정 사용자의 접근을 제재하려고한다.
- 엑세스 토큰의 경우 인증 서비스에 저장된 토큰 정보를 삭제함으로써 더이상 해당 토큰의 사용이 불가능 하도록 할 수 있다.
- JWT의 경우 토큰에 명시된 만료 시간 전까지는 제어가 불가능하다
- 2) 변경된 정보 적용, 토큰이 발급된 사용자의 권한 정보가 변경되었다.
- 엑세스 토큰의 경우 토큰에 맵핑된 정보를 수정하여 즉시 변경 적용이 가능하다
- JWT의 경우 접근 제어와 마찬가지로 JWT에 명시된 만료 시간 전까지는 잘봇된 정보로 서비스에 접근할 수 있다.
- 이러한 관리 어려움으로 JWT는 가능한 토큰의 만료 시간을 짧게 가져가는 것이 좋다
- 하지만 토큰 만료시간이 짧아질 수록 토큰 갱신을 위해 발생하는 비용이 커지기 때문에 적절한 시간 선택이 중요하다
- JWT를 사용함으로써 인증 서비스와 다른 서비스 간에 많은 의존성을 줄였지만, 여전히 각 서비스들은 인증 서비스가 발급한 공개-키를 관리해야 하며 JWT라는 인증 방식에 묶여있다.
API Gateway를 활용한 공통 인증
- MSA에서 API GW는 여러 분리된 서비스 환경에서 사용자에게 하나의 엔드포인트를 제공하기 위해 사용되는 패턴이다.
- API GW는 서비스 최전방에 위치하며, 모든 사용자 요청은 API GW를 통해서만 각 서비스에 접근 가능하게 된다.
- 따라서 API GW는 서비스 전체에 미들웨어 계층으로써 공통된 로직을 처리할 수 있으며, 인증도 API GW가 처리할 수 있는 공통 로직 중 하나이다.
- API GW 인증 절차
- 사용자는 JWT를 첨부하여 API GW를 통해 서비스에게 명령을 요청한다
- API GW는 요청된 명령을 수신하여 JWT 인증 로직을 수행한다.
- 인증된 사용자 정보를 요청에 추가로 첨부하여 뒷단 서비스에게 전달한다.
- 서비스는 API GW가 첨부한 사용자 인증 정보를 기반으로 요청을 처리한다
- 앞단에 API GW가 공통된 인증 절차를 수행하면서 뒷단의 서비스들은 인증 방식으로부터 완전히 독립되어 인증 서비스와 의존성이 사라지게 되었다.
- 이후 인증 절차에 어떠한 변화에도 다른 서비스들은 영향이 없다.
- JWT 인증 방식이 엑세스 토큰 인증으로 변경되어도 API GW가 동일한 사용자 인증 정보를 반환할 수 있다면 뒷단의 다른 서비스들은 어떠한 변경 사항도 없을 것이다.
- 모든 서비스의 요청은 API GW를 통해 각 서비스에 전달된다.
- 이러한 구조로 API GW의 장애로 서비스 전체가 먹통이 되는 SPOF(Single Point Of Failure)가 될 수 있다.
- 따라서 이러한 상황에 대비하기 위해 API GW 도입 시에는 철저한 이중화가 준비되어야 한다
인증 캐시
- 토큰을 이용한 사용자 인증 결과는 가변성이 크지 않은 데이터이다.
- 방금 막 유효성이 확인된 토큰이 다음 요청에 대한 결과로 변경되어 있을 가능성이 크지 않다.
- 이러한 데이터 성격으로 토큰을 키로 하여 사용자 인증 데이터를 캐시하여 재사용할 수 있다.
- 재사용된 캐시 데이터는 아래의 이점을 갖는다
- 1) 통신 오버해드 감소, 캐시 데이터를 재사용함으로써 반복되는 인증 오버해드(엑세스 토큰:통신 오버해드, JWT: 시그니처 검증 연산 오버해드)를 줄일 수 있다
- 2) 장애 전파 최소화, 인증 서비스 장애 발생 시에도 캐시 데이터를 사용함으로써 장애 영향도를 최소화할 수 있다.
- 그러나 캐시의 사용은 상황에 따라 이미 내용이 변경되어 유효하지 않은 데이터를 참조할 수도 있다.
- 따라서 각 서비스 성격과 정책에 따라 알맞는 캐시 만료 시간이 설정되어야 하며, 일부 인증의 유효성 판단이 크리티컬한 경우, 캐시 사용을 배제해야 한다.
결론
- 핵심은 서비스 전반으로 사용될 인증 서비스 기능과 다른 서비스의 의존성을 줄이는 것이다.
- JWT를 적용하여 인증 서비스와의 의존성을 줄이고 각 서비스가 스스로 사용자 인증을 수행한다
- API GW는 공통 인증 절차를 수행하여 각 서비스에서 사용할 인증 로직에 대해 추상화를 한다
- 인증 캐시를 사용하여 반복되는 인증 절차를 줄일 수 있다.