1. 내가 왜 Zanzibar를 찾게 되었는가?
우리 프로젝트는 현재 두 가지의 권한을 가지고 있다. 관리자와 일반 사용자인지를 구분하는 Admin 권한과 우리 서비스에서 관리하는 프로젝트 별로 권한을 관리하여 서비스를 이용할 수 있는지는 확인하는 프로젝트 접근 권한. 이렇게 두 가지가 존재한다. Admin인지를 확인하는 방법은 간단했다. 우리는 SpringSecurity를 통해서 RequestURI에 admin으로 시작한다면, JWT Filter에서 등록한 인증 객체가 Admin 권한을 가지고 있는지 확인하도록 만들었다. 하지만 프로젝트 별로 해당 행동을 할 수 있는지 없는지를 구분하기 위해서는 조금 더 고려해야 할 것이 있어 보였다.
지금 당장 내가 선택한 방법은 @PreAuthorize 어노테이션에서 SpEL을 사용하여 특정 메서드를 실행하도록 하는 방법이었다. 인증 객체와 접근하려고 하는 프로젝트의 아이디를 매개변수로 하여 해당 프로젝트에 접근할 수 있는 사람인지를 확인한 후 반환하는 방법을 사용했다.
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@projectAuthorizationCheckService.checkApprover(principal.id, #projectId) or hasRole('ADMIN')")
public @interface ApproverAuthorize {
}
위 어노테이션을 붙인 메서드에 접근하려고 할 때, 해당 사용자가 관리자거나 이 프로젝트의 승인권자인지를 확인하도록 만들었다. 이렇게 했을 때, 만약에 승인권자가 아니라면 AccessDeniedException이 발생하게 된다. 해당 Exception은 GlobalExceptionHandler에서 응답을 처리한 후 반환하도록 한다.
이렇게 구현했을 때 잘 작동하는 것을 확인했지만, 한 걸음 더 나아가면 발생할 수 있는 문제가 떠올랐다.
'만약에, 프로젝트와 게시글의 모듈이 분리되면 어떻게 하지?'
그래서 나는 이 문제를 해결할 수 있는 방법을 찾게 되었다.
2. Zanzibar란 무엇인가?
Zanzibar란 구글에서 만든 사용자와 리소스 간의 복잡한 권한 관계를 효과적으로 관리하기 위해 개발한 분산형 권한 관리 시스템이다. 그리고 Zanzibar는 관계 기반 접근 제어 모델을 사용하기 때문에 권한 설정이 자유롭다는 장점이 있다.
이렇게 말하면 너무나도 어려운 말이니 조금 더 설명을 상황에 맞춰서 해보겠다. 이게 무슨 말일까?
현재 구글은 다양한 서비스를 동시에 가지고 있다. 그 중에서 두 가지를 가지고 예를 들어보도록 하겠다.
현재 구글 메일에서 메일을 보내려고 할 때, 다음 사진처럼 우리들은 구글 드라이브에 있는 파일을 들고와서 첨부할 수 있다.
하지만 어떻게 gmail은 해당 문서를 공유할 수 있는 사람인지 알 수 있을까? 지메일의 개발자는 어떻게 구글 드라이브에서 저렇게 빠르게 자신이 공유할 수 있는 파일들을 가져올 수 있을까?
그 방법이 바로 Zanzibar 사용한 것이다.
Zanzibar는 구글이 사용하고 있는 모든 서비스의 권한 정보를 관리하는 하나의 서비스이다. 그리고 api를 통해서 해당 권한이 존재하는지 확인할 수 있는 API를 통해서 해당 행동을 할 수 있는 방법을 사용한다. 그렇기에 이 파일을 첨부할 수 있는 사람인지 확인하는 것을 구글 드라이브에 물어보지 않아도 되는 것이다. 구글 드라이브 역시 파일을 관리할 수 있는지를 이 Zanzibar에게 물어보면서 처리한다.
3. Zanzibar가 권한을 저장하는 방법
Zanzibar는 권한을 튜플을 통해서 저장한다.
권한을 위와 같이 저장하게 되는데, 왼쪽에는 접근하고자 하는 리소스를, 우측에는 해당 회원이 ID를, 그리고 가운데에는 관계를 적는다. 이렇게 했을 때 좋은 점은 권한명을 마음대로 설정할 수 있다는 것이다. 결국 권한명에 맞는 것을 찾기 때문에 권한명에 구애받지 않고서 권한을 설정할 수 있다는 장점이 있다.
이것이 바로 관계 기반 접근 제어 모델입니다.
document:A#읽기전용@User1
위 내용은 User1은 document:A에 관해서 오로지 읽기만 할 수 있다는 것이다.
그렇다면 역할 기반 접근 제어와 관계 기반 접근 제어 간의 차이는 무엇일까?
역할 기반 접근 제어는 특정 행동을 할 수 있는 권한을 미리 제작자가 정의해 둔 후에 사용자에게 해당 권한을 부여하면서 권한을 설정하는 방식입니다. 이것을 쉽게 풀어쓰자면, 사전에 통행증을 만들어둔 다음에 그 통행증을 회원에게 부여해서 인증을 하게 하는 것입니다.
역할 기반 접근 제어는 이런 특징 때문에 역할에 대한 권한이 변경될 경우 해당 권한을 가진 모든 인원의 역할이 변경되게 됩니다. 통행증을 통해서 할 수 있는 일의 범위가 변경되는 게 특징입니다. 모든 역할을 통합해서 관리할 수 있다는 점과 미리 만들어둔 권한에 따라서 작동한다는 점이 장점입니다. 하지만 변경이 까다롭고, 포괄적이기에 세세한 접근 제어를 할 수 없다는 단점이 있습니다.
반면, 관계 기반 접근 제어는 사용자의 관계에 따라 권한이 실시간으로 달라질 수 있다는 점이 특징입니다. 또한 관계 기반 접근 제어는 자원과 사용자 간의 관계를 나타냅니다. 예를 들어 구글 드라이브의 파일과 사용자, 유튜브 영상과 사용자 등이 이에 해당합니다. 이렇기 때문에 각각의 자원마다 다른 관계를 맺어주면서 세밀하게 제어할 수 있지만, 하나씩 관계를 맺어주기 때문에 역할 기반 접근 제어보다 관리하는 것이 힘든 것이 단점입니다.
4. 어떻게 이렇게 빠르게 처리할 수 있을까?
그렇다면 이 수십억의 인구가 사용하는 서비스들이 하나의 서비스에 권한을 확인하는 요청을 보내고 있는데, 이것을 어떻게 효과적이고 빠르게 처리해서 결과를 보내줄 수 있는 것일까?
거기에 대한 해답으로 Zanzibar는 분산 아키텍처를 사용한다.
분산 아키텍처란 여러 대의 컴퓨터가 하나의 서비스를 나눠서 처리하는 방식으로 중앙 아키텍처와 반대되는 말이다.
특징 | 중앙 아키텍처 | 분산 아키텍처 |
---|---|---|
구성 | 단일 서버 또는 중앙 집중식 데이터 센터에서 관리 | 여러 노드와 서버에 분산되어 구성 |
확장성 | 주로 수직 확장(서버 성능 업그레이드)에 의존 | 주로 수평 확장(노드 추가)으로 처리 능력 향상 |
고가용성 | 단일 장애점(SPOF)이 존재할 수 있어 장애 발생 시 전체 시스템 영향 | 여러 노드가 분산되어 있으므로 일부 노드 장애에도 전체 시스템은 계속 운영 가능 |
내결함성 | 장애 발생 시 전체 서비스 중단 가능 | 장애 조치 및 데이터 복제를 통해 일부 노드에 문제가 있어도 시스템 전체가 정상 동작 |
데이터 일관성 | 중앙 집중식 관리로 일관성 유지가 상대적으로 용이 | 데이터 복제와 네트워크 지연 등으로 일관성 유지에 추가적인 고려가 필요 |
성능 | 모든 요청이 중앙 서버에 집중되어 과부하 시 성능 저하 가능 | 요청이 여러 노드에 분산되어 병렬 처리로 고부하 상황에서도 성능 향상 |
유지보수 | 중앙에서 집중적으로 관리하므로 상대적으로 관리 및 유지보수가 용이 | 분산 환경의 특성상 각 노드 관리, 네트워크 문제 등 복잡한 운영 및 모니터링 필요 |
여러 개의 데이터센터에 저장되어 있는 권한들을 여러 개의 컴퓨터가 처리하도록 하여 속도를 확실하게 한 것이다.
이때, 구글은 권한이 제대로 유지되도록 최신화에 신경쓴다.
5. 결론
이번에는 여러 개의 마이크로 서비스를 사용할 때, 어떻게 권한을 사용할 수 있는지에 대해서 공부해보기 위해서 Zanzibar에 대해서 이야기해보았다. Zanzibar를 실제로 구현한 오픈 소스에서는 SpiceDB가 존재하는데, 여기에 대해서는 추가로 공부해보면 좋을 것 같다.
지금 현재 우리의 서비스는 각각의 서비스들을 분리한 형태가 아니기 때문에 조금 더 좋은 방법이 있을지 고민해보아야겠지만, 이번에는 이런 방법이 존재한다는 것을 배우고자 이 글을 작성하게 되었다. 추후에 마이크로 서비스 간의 권한 설정을 역할 기반 권한 설정으로 해결하지 못할 때 한 번 사용해보면 좋을 것 같다.
Reference
- https://www.usenix.org/conference/atc19/presentation/pang (구글 학술 검색 - Zanzibar)
- https://www.youtube.com/watch?v=eyDSR_0WG4I&t=172s (구글이 100억개의 권한 관리하는 법 - 코딩애플)
- https://tech.hanbiro.com/hanbiro-kr/ (Google Zanzibar (ReBAC 적용))