권한 관리, 언제까지 if-else로 땜빵할 거야? (RBAC부터 Zanzibar 찍먹까지)

2025. 12. 8. 18:50·Development
TeoConf에서 '권한 관리' 세션을 듣고 작성하는 포스팅.
개념은 알고 있었지만 설명할 정도가 되지 않기 때문에 학습용으로 공부하기 위해 정리하는 글이다.

 

들어가며

얼레벌레 개발 5년 차. 이제 로그인(Authentication)은 '익숙한 고통' 정도다. JWT? OAuth2? 여전히 설정할 때마다 삽질은 좀 하지만, 그래도 라이브러리가 워낙 잘 되어 있고 레퍼런스도 넘쳐나니 어떻게든 구현은 된다.

근데 진짜 빌런은 항상 '권한(Authorization)'이다. 처음엔 `user.role === 'ADMIN'` 한 줄이면 세상 평화로웠는데, 기획자가 갑자기 이런다.

관리자, 사용자 역할별로 분리해주세요. 사용자는 관리자, 사용자 역할 모두 가질 수 있어요

그리고 이게 끝이 아니었다.
프로젝트 초기에는 단순히 관리자/사용자 두 가지만 있었는데, 점점 복잡해졌다:

- 역할 구분(Role Group): 관리자(ADM), 사용자(USR), 프로젝트(PRJ), 특수(EXT) - 4가지 카테고리
- 각 구분 안의 역할: 각 역할 구분 안에 N개의 역할이 존재 (예: "프로젝트 관리자", "프로젝트 멤버" 등)
- 다중 역할 권한 병합: 사용자가 여러 역할을 가질 수 있고, 여러 역할의 권한을 OR 연산으로 병합 (하나라도 권한 있으면 접근 가능)
- 코드 기반 권한: 같은 역할이라도 코드별로 다른 권한 부여
- 컴포넌트 레벨 권한: 메뉴 접근뿐만 아니라 페이지 내 버튼별 조회/수정 권한까지 제어

결국 `user.role === 'ADMIN'` 한 줄로는 해결이 안 되고, 역할-사용자-메뉴-페이지-컴포넌트 등를 모두 고려한 다차원 권한 체계가 필요해졌다.

그리고 권한이 하나라도 없으면 메뉴 접근도 안 되고, 페이지도 튕겨야 한다. (실제로 `/unauthorized`로 리다이렉트된다)

...이때부터 DB 테이블 조인하고, 비즈니스 로직에 if문 덕지덕지 바르기 시작하면 코드가 스파게티가 되는 건 시간문제다.
 

 
그래서 오늘은 이 지긋지긋한 권한 관리의 역사를 훑어보고, 구글이 "우린 이렇게 해"라고 답지를 던져준 Zanzibar와, 그걸 우리가 써먹을 수 있게 만든 OpenFGA까지 정리해 보려 한다.
 
 
 
 

1. 우리가 흔히 쓰던 방식: RBAC과 ABAC

우리가 숨 쉬듯이 짜왔던 권한 로직들이다. 얘네가 나쁜 건 아닌데, 요즘 트렌드랑은 좀 안 맞을 때가 있다.

RBAC (Role-Based Access Control)

  • 한줄 요약: "너 팀장 명찰 달았네? 프리패스."
  • 특징: 사용자에게 Role(역할)을 주고, 그 역할에 권한을 매핑한다.
  • 현실: B2B 백오피스 같은 데선 여전히 국룰이다. 근데 "내 글은 나만 수정 가능" 같은 소유권 개념이 들어가거나, 역할이 애매하게 쪼개지기 시작하면 답이 없다. Super_Admin, Semi_Admin, Manager_But_Cannot_Delete... 역할 이름 짓다가 하루 다 감.

 

 

ABAC (Attribute-Based Access Control)

  • 한줄 요약: "지금 9시 넘었고 너 개발팀이니까 통과."
  • 특징: 누가(User), 무엇을(Resource), 어떤 환경에서(Env) 같은 속성(Attribute)들을 조합해서 판단한다. AWS IAM이 딱 이거다.
  • 현실: 유연하긴 한데, 정책(Policy) 관리가 헬이다. 조건이 복잡해지면 "대체 이 사람 왜 접근 안 됨?" 하고 디버깅하다가 밤샌다. 그리고 무엇보다 '관계'를 계산하기엔 연산 비용이 너무 비싸다.

 
 
 

2.  관계가 곧 권한이다: ReBAC의 재발견

사실 ReBAC이라는 개념 자체가 막 엄청난 최신 기술은 아니다.
우리가 맨날 쓰는 인스타그램(팔로워 공개), 구글 드라이브(폴더 공유)가 다 ReBAC이다. 예전엔 그냥 "소셜 그래프 구현"이라고 퉁쳤던 걸, 요즘 들어서 "관계를 기반으로 권한을 제어하자"라고 시스템화해서 부르기 시작한 거다.
핵심은 "데이터 간의 관계(Graph)를 따라가면 권한이 보인다"는 것.

  • 철수는 A폴더의 소유자다. (관계)
  • B파일은 A폴더 안에 있다. (관계)
  • 결론: 철수는 B파일도 볼 수 있다. (권한 상속)

이걸 SQL로 짜면 JOIN 지옥이 펼쳐지는데, 이걸 그래프 탐색 문제로 풀어버리면 훨씬 깔끔해진다.
 
 
 

3. 구글이 선택한: Zanzibar (잔지바르)

구글은 유튜브, 드라이브, 캘린더 같은 괴물 같은 서비스를 돌린다. 사용자는 수십억 명이고, 객체는 수조 개다. 기존 방식으론 절대 감당이 안 됐을 거다.
그래서 2019년에 "우린 Zanzibar라는 거 만들어서 쓴다"라고 USENIX에 논문을 냈다.

Zanzibar의 핵심: 튜플(Tuple)

구글은 모든 권한을 주어-동사-목적어 형태의 튜플로 저장한다.

 

doc:readme.md # viewer @ user:me

(readme.md 문서의 뷰어는 나다)

group:dev_team # member @ user:kim

(개발팀 그룹의 멤버는 김씨다)

 

이 튜플들이 모여서 거대한 방향성 그래프(Directed Graph)를 만든다. 그리고 "김씨가 이 문서 볼 수 있어?"라고 물으면, Zanzibar는 그래프를 타고 타고 내려가서 "어, 볼 수 있어"라고 10ms 만에 답해준다.
이게 바로 ReBAC을 아키텍처 레벨로 끌어올린 시초이자, 현재 권한 관리 시스템의 사실상 표준(De facto Standard)이 됐다.
 
 
 

4. 우리가 쓸 수 있는 거: OpenFGA

"와 구글 쩐다. 근데 우리 회사엔 구글 엔지니어가 없잖아?"
Zanzibar 논문 보고 침만 흘리던 개발자들을 위해, Auth0(Okta) 형님들이 총대 메고 만든 오픈소스가 바로 OpenFGA다. (CNCF 프로젝트라 믿고 쓸 만함)

왜 OpenFGA인가?

  1. Zanzibar 모델 그대로: 튜플 기반 저장, 그래프 탐색 로직을 거의 그대로 구현했다.
  2. 모델링 언어(DSL) 지원: 복잡한 코딩 없이 스키마 파일 하나로 권한 모델을 정의할 수 있다.Protocol Buffers(대충 owner면 viewer 권한도 자동으로 먹는다는 뜻. 직관적이다.)
  3. type document relations define owner: [user] define viewer: [user] or owner
  4. 무료(Apache 2.0): 도커로 띄워서 쓰면 공짜다. 폐쇄망이든 로컬이든 상관없음.

 
 
 

5. 마무리하며

예전엔 권한 체크 로직 짠다고 하면 서비스 코드 곳곳에 if문 박느라 바빴다.
근데 이제 MSA로 서비스가 쪼개지고 권한이 복잡해지면서, "권한 로직은 애플리케이션에서 떼어내서(Decoupling) 전담 서버에 맡기는" 추세로 가고 있다.
ReBAC이나 Zanzibar가 만능키는 아니겠지만, 적어도 "상위 폴더 권한 상속"이나 "조직도 기반 권한" 때문에 골머리 앓고 있다면 찍먹해 볼 가치는 충분하다.
 
 

결론:

복잡한 JOIN 쿼리 짜면서 고통받지 말고, 이제 그래프로 권한 관리 좀 세련되게 해보는건 어떨까

'Development' 카테고리의 다른 글

[Cursor] Playwright로 테스트부터 디버깅까지 한번에 끝내기  (0) 2025.11.11
[CS] "나누기 0"은 왜 어떤 언어에선 에러가 나고, 어떤 언어에선 무한대(Infinity)가 될까?  (1) 2025.11.03
[React] 배포 후 간헐적으로 개발 서버에서 화면 에러가 뜨는 이유  (0) 2025.10.14
[Web] 브라우저 “탭( Tab )”을 노리는 공격, Tabnabbing  (0) 2025.10.13
[C언어] return 0, 그리고 0과 1의 진짜 의미  (0) 2025.10.06
'Development' 카테고리의 다른 글
  • [Cursor] Playwright로 테스트부터 디버깅까지 한번에 끝내기
  • [CS] "나누기 0"은 왜 어떤 언어에선 에러가 나고, 어떤 언어에선 무한대(Infinity)가 될까?
  • [React] 배포 후 간헐적으로 개발 서버에서 화면 에러가 뜨는 이유
  • [Web] 브라우저 “탭( Tab )”을 노리는 공격, Tabnabbing
곽진돔
곽진돔
Developer
  • 곽진돔
    echo "곽박한 세상";
    곽진돔
  • 전체
    오늘
    어제
    • 분류 전체보기 (203)
      • Development (74)
        • Linux (13)
        • k8s (3)
        • Docker (5)
        • AWS (1)
        • PHP (35)
        • Python (21)
        • Java (1)
        • SpringBoot (4)
        • JavaScript (2)
        • React (10)
        • MySql (19)
        • MongoDB (1)
      • Daily (6)
      • Study (7)
        • TIL (2)
        • license (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
    • 설정
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    SQL
    CentOS
    리눅스
    정규표현식
    MySQL
    docker
    인코딩
    nodejs
    error
    php
    Linux
    db
    스프링부트
    크롤링
    윈도우
    ssh
    react
    CentOS7
    UTF8
    HTML
    chromedriver
    Python
    JavaScript
    Java
    date
    springboot
    IP
    Selenium
    Shell
    리액트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
곽진돔
권한 관리, 언제까지 if-else로 땜빵할 거야? (RBAC부터 Zanzibar 찍먹까지)
상단으로

티스토리툴바