본 포스팅은 SSO 구축기 시리즈의 2편이다.
SSO 구축을 위해 사용할 OAuth 2.0 Protocol에는 인증을 담당하는 Authorization Server가 있다.(자세한 내용은 1편 참고)
SSO를 위해 첫 번째로 해야 할 일은, Authorization Server를 구축하는 것이다.
당시 논의한 Authorization Server의 기준은 아래와 같았다.
1. SSO 지원
2. OAuth 2.0, OpenID Connect Protocol 지원
3. 빠른 구축
4. 무료 라이센스
5. 사용자 커뮤니티의 규모 및 꾸준한 업데이트, 높은 성숙도
위 내용들을 고려하여 리서치 한 결과, 아래와 같은 두 가지 후보가 도출되었다.
Spring Authorization Server는 Spring Security 프로젝트에 소속되어 개발되다가, 프로젝트가 중단된 이후 Spring Comnunity의 항의로 인해 2020년 4월 15일에 별도 프로젝트로 분리되어 개발되기 시작한 프레임워크이다.
2021년 8월 19일에 Production 버전인 0.2.0이 릴리즈 되었고, 2022년 11월에 GA버전인 1.0이 출시될 예정이라고 한다.
Feature List는 아래와 같다.
Keycloak은 IAM(Identity and Access Management) Open Source로서 2014년 9월에 Production 버전이 릴리즈되었다.
Red Hat SSO의 Upstream 프로젝트로써 사용되며, 무료 라이센스이고 꾸준한 업데이트가 이루어지고 있다.
Feature List는 아래와 같다.
OAuth 2.0, OpenID Connect 1.0 Protocol은 두 프로젝트 모두 지원했지만, Keycloak의 경우 자체적인 Browser 기반 Session 관리를 통한 SSO를 지원하기도 하고, 역사가 8년 이상 되다 보니 Document와 Reference 또한 Spring Authorization Server에 비해 풍부했다.
또한 GUI 기반 Admin Console의 제공과 Two-factor Authentication 지원 등 추후 보안을 강화하기 위해 필요한 기능들까지 제공하고, 무엇보다 위 Authorization Server 선정 기준으로 잡은 5가지 항목에 모두 적합하여 Keycloak으로 최종 선정하였다.
Keycloak Server Guides에서 여러 환경(OpenJDK, Docker, k8s, ..)에서의 Keycloak을 시작하기 위한 가이드를 제공하여 쉽게 development mode로 시작해 볼 수 있다.
Keycloak을 시작하기 전에, 핵심 용어를 먼저 간단하게 알아보자.
Keycloak을 설치하고 각 환경에서의 가이드대로 서버를 띄우면, 기본적으로 8080 포트로 서버가 실행된다.
기본으로 제공되는 Master Realm은 Keycloak 관리를 위해 사용되므로, 별도의 Realm을 생성하여 사용해야 한다.
Realm, Client, User 생성 등은 Keycloak getting-started 링크에서 확인할 수 있다.
Keycloak을 Production 에서 띄우기 위해서는 외부 DB 연결, Hostname 설정 등 추가 구성이 필요한데, 관련 내용은 all-config, configuration-production 문서에서 찾을 수 있다.
Istio같은 서비스 메시나 nginx 등을 사용하여 reverse proxy를 구성할 때는,
proxy edge, hostname에 domain name 설정, http-relative-path를 proxy 설정에 맞게 적용해줘야 한다.
Keycloak Admin Console에서 제공되는 대부분의 기능은 Keycloak Admin REST API 에서 Http Endpoint로 별도 제공된다.
이를 호출하려면 Keycloak Token Endpoint에서 Password Grant Type으로 Admin 계정의 Access Token을 발급받아 헤더에 넣어야 한다.
이를 이용해서 Admin Console같은 페이지를 만들 수도 있고, 다른 비지니스 로직과 조합하여 사용할 수 있다.
Java 개발자는 Keycloak Java Adapter를 사용할 수 있다.
Java 코드로 Keycloak Admin REST API를 조작할 수 있고, Admin 계정의 Access Token이 필요하지 않다.
사내에서는 해당 어댑터를 사용하여 Keycloak API와 비즈니스 로직을 조합하여 사용하였다.
샘플 코드는 Github에서 확인할 수 있다.
마냥 장점만 있는 것 같은 Keycloak도 Open Source가 가지는 특유의 단점들이 존재한다.
필요에 따른 데이터를 추가로 저장하기 위해 Attributes라는 기능을 제공하는데, 이에 대한 암호화는 지원하지 않는다.
예를 들어, 카드 번호나 지갑 주소 등을 저장해야 하는 경우, Attribute 암호화를 지원하지 않아 문자열을 그대로 DB에 저장해야 하는데, 이는 정보통신망법 등에 위배된다.
위 예시처럼 관련 법에 따라 암호화가 의무화된 데이터를 저장해야 한다면, 해당 컬럼만 별도의 DB에 암호화하여 저장해야 하는 일이 발생한다.
기획된 프로세스가 Keycloak에서 지원되지 않는 경우, 문제를 해결하기가 까다롭다.
예를 들어, 회원가입 프로세스 도중 Email 인증을 해야만 회원가입이 완료되도록 기획이 나왔다면, Keycloak을 사용해서 해결하기는 힘들 것이다.
Keycloak에서 제공하는 Email 인증 API는 이미 존재하는 회원에 한하여 가능한데, 회원가입 도중 이메일 인증을 선행하려면 회원가입 API -> Email 인증 API -> 이메일 인증 미시행 시 회원 탈퇴 등 여러 API를 하나의 트랜잭션으로 묶어 별도의 서버에서 조합하여 호출하는 방식으로 해결하거나, Keycloak 내부 코드를 변경해야 한다.
하지만 Keycloak 내부 코드를 변경하는 방법은, 레거시 코드를 변경하는 일이라서 난이도가 높기도 하고, 변경하는 순간 버전 업그레이드가 불가능해지기 때문에 최악의 방법이라고 생각한다.
Keycloak Admin REST API의 테스트 코드 작성이 어렵다.
회원을 생성하는 Keycloak Admin REST API와 회원의 카드 번호를 암호화하여 별도 DB에 저장하는 로직을 조합하여 제공하는 API가 있다고 가정하자.
해당 API의 테스트 코드를 작성한다고 했을 때, 호출한 Keycloak API를 롤백시키기가 무척 어렵다.
Keycloak 내부 코드를 변경하여 테스트를 위한 Api Call이 들어왔을 때는, 모종의 규칙을 정해 보상 트랜잭션이 발생하도록 구성하거나, 혹은 테스트만을 위한 별도의 Keycloak 서버를 두어야 할 것이다.(그마저도 롤백이 가능한 것은 아니라서, 테스트 실행 시 마다 테스트 데이터가 쌓일 것이다.)
위에 나열한 문제 중 1, 2번 문제를 해결하기 위해, 프로필 서버라는 별도의 서버를 구성하기로 하였다.
Keycloak과 프로필 서버의 관계는 아래와 같다.