멀티테넌트 SaaS 권한을 조직·팀·역할·소유권 규칙과 체크리스트, 예제로 쉽게 설명해 안전하게 확장하는 방법을 정리합니다.

권한 문제는 보통 작은 불편함으로 시작합니다. 티켓이 하나 올라옵니다: "저는 관리자인데 청구서가 보이지 않아요." 또 하나: "왜 동료가 설정을 수정할 수 있죠?" 사람들은 여기저기 클릭해 보고, 추측하고, 때로는 접근을 정리하는 것보다 빠르니 단일한 "오너" 로그인을 공유합니다.
그다음 우회책이 쌓입니다. 팀은 "Admin 2"나 "Manager (no delete)" 같은 역할을 만들어 냅니다. 엔지니어는 "사용자가 Sales에 속하면 내보내기 허용" 같은 일회성 체크를 추가합니다. 하루는 고쳐지지만 한 달 후에는 어떤 규칙이 의도된 것인지, 어떤 것이 사고인지 아무도 모릅니다.
고객이 늘어나면 상황은 더 나빠집니다. 한 계정에서 괜찮았던 규칙("관리자는 모든 데이터를 본다")이 수백 개 조직에서 각기 다른 기대치를 만났을 때 깨집니다. 어떤 고객은 부서 간 엄격한 분리를 원하고, 다른 고객은 공유 워크스페이스를 원합니다. 어떤 고객은 계약자가 특정 프로젝트만 접근하길 원합니다. 모델이 명확하지 않으면 새 고객마다 예외를 만들어야 합니다.
목표는 간단합니다: 1분 안에 설명할 수 있는 예측 가능한 접근 규칙. 예: "조직이 데이터를 소유한다. 팀은 사람을 묶는다. 역할은 행위를 정의한다. 리소스는 조직에 속하거나 때로는 팀에 속한다. 공유는 몇 가지 기본 규칙을 따른다." 명확하게 말할 수 없다면, 만들기 어렵고 테스트하기 어렵고 변경이 두려워집니다.
지킬 만한 약속은: 역할은 적게, 소유권은 명확하게, 기본값은 안전하게. 실제 직무에 연결된 작은 역할 집합으로 시작하고, 모든 리소스에 대해 소유권을 분명히 하며 기본적으로 최소 권한을 적용하세요. 그다음 의도적으로 공유를 허용하고, 우연히 공유되는 일이 없게 하세요.
앱이 둘 이상의 고객을 제공한다면 규칙을 만들기 전에 개념 지도를 정확히 잡으세요. 멀티테넌트 SaaS 권한에서 대부분의 혼란은 같은 단어가 제품의 다른 부분에서 다른 의미를 가질 때 옵니다.
테넌트 경계에 대해 하나의 의미를 정하고 지키세요. 많은 제품은 "조직(organization)"을 테넌트로 사용합니다: 모든 데이터가 조직 내부에 있고 명시적으로 공유를 만들지 않는 한 그 선을 넘지 않습니다.
성장해도 명확하게 유지되는 간단한 어휘:
"한 사람이 여러 조직에 속하는" 것은 정상입니다. 컨설턴트는 세 개의 고객 조직에 각각 다른 역할로 속할 수 있습니다. 그래서 "user"와 "membership"은 분리되어야 합니다. 실제 권한 체크는 보통 멤버십을 기반으로 합니다.
팀은 "지원팀"이나 "재무팀"처럼 실제 그룹을 반영할 때 도움이 됩니다. 팀이 두 번째 권한 시스템이 되면 노이즈가 됩니다. 팀을 설명할 때 특정 기능 규칙을 언급하지 않고 한 문장으로 설명할 수 있으면 유용한 테스트입니다.
예: Maria는 한 번 로그인한 뒤 Org A와 Org B를 전환합니다. Org A에서는 재무팀에 속해 청구서를 볼 수 있고, Org B에서는 뷰어라서 프로젝트만 읽을 수 있습니다. 같은 사용자, 다른 멤버십, 일관된 리소스 유형, 명확한 경계입니다.
멀티테넌트 SaaS 권한은 세 가지를 분리하면 이해하기 쉽습니다:
RBAC(역할 기반 접근 제어)는: 사용자에게 역할을 부여하면 그 역할이 허용된 행동을 부여한다는 뜻입니다. 역할 이름은 상태가 아니라 책임을 설명해야 합니다. "Billing Admin"은 명확합니다. "Power User"는 보통 논쟁을 만듭니다.
권한은 동사처럼 다루고 제품 전반에서 일관되게 유지하세요:
그다음 같은 동사가 다른 곳에 적용될 수 있게 범위를 추가하세요. 이렇게 하면 비슷한 역할을 20개 만드는 일을 피할 수 있습니다.
읽기 쉬운 일반적인 범위:
"Project Editor"와 "Project Editor (Own)" 같은 역할을 만들고 있다면 보통 역할 문제가 아니라 범위 문제입니다.
예: CRM에서는 "Sales Rep"가 거래를 생성하고 수정하게 하되 범위를 "own items"로 제한하세요. "Sales Manager"는 유사한 동사를 유지하되 범위를 "team-only"나 "org-wide"로 두세요. 역할 수는 줄고 규칙은 명확해지며 누군가 팀을 바꿀 때 놀라움이 줄어듭니다.
견고한 기본 원칙: 역할은 동사를 부여하고, 소유권(또는 할당)이 그 동사가 어디에서 작동하는지 제한합니다.
한 고객에게는 잘 작동하던 모델이 열 개에서 깨진다면 아마도 "누가 볼 수 있는가"와 "누가 할 수 있는가" 그리고 "누가 소유하는가"를 섞어버린 것입니다. 이들을 분리하면 시스템은 예측 가능하게 유지됩니다.
확장 가능한 규칙 세트:
예: Sam은 Org A와 Org B에 속합니다. Org A에서는 멤버라서 자신의 보고서를 생성·수정할 수 있지만 청구 관련 변경은 할 수 없습니다. Org B에서는 Billing Manager라서 결제 수단을 업데이트하고 청구서를 다운로드할 수 있지만, 멤버십이 해당 영역을 포함하지 않는 한 비공개 프로젝트는 볼 수 없습니다.
이렇게 하면 성장이 건조하게(좋은 의미로) 됩니다. 새 조직을 추가하는 것은 멤버십과 역할을 추가하는 일일 뿐입니다. 핵심 규칙은 그대로입니다.
동료가 2분 안에 읽을 수 있는 한 페이지를 작성하세요. 코드 열지 않고 권한을 설명할 수 있다면 좋은 출발입니다.
구성 요소를 작게 유지하세요:
권한 폭발을 피하려면 범위를 사용하세요. 많은 제품은 세 가지 범위만으로 충분합니다: own, team, org.
| Role | View | Edit | Invite users | Billing | Scope note |
|---|---|---|---|---|---|
| Owner | Yes | Yes | Yes | Yes | Org-wide, can transfer ownership |
| Admin | Yes | Yes | Yes | No/Yes | Org-wide, no ownership changes |
| Member | Yes | Limited | No | No | Own + team (where assigned) |
| Viewer | Yes | No | No | No | Read-only in assigned scope |
건강성 검사: 이 페이지를 비기술 동료에게 보여주고 "Support 멤버가 Sales 보고서를 수정할 수 있나요?"라고 물어보세요. 주저하면 범위나 팀 정의가 명확하지 않은 것입니다.
권한을 이해하기 쉽게 유지하려면 각 리소스의 소유자를 결정하고 공유 옵션을 제한하세요.
대부분의 리소스는 조직 소유로 만드세요. 고객은 회사 관점으로 생각하는 경우가 많습니다: 청구서, 프로젝트, 연락처, 티켓, 자동화는 조직에 속합니다.
팀은 여전히 유용할 수 있지만, 팀을 워크플로우 라벨(라우팅 및 가시성 기본값)로 취급하고 비밀스러운 보안 로직으로 만들지는 마세요. 팀 태그는 필터, 대시보드, 알림, 큐를 구동할 수 있고, 접근은 여전히 역할과 범위에서 옵니다.
사용자 소유 리소스는 예외로 두고 진정으로 개인적인 항목(초안, 개인 노트, 저장된 뷰, API 토큰, 개인 설정)에만 허용하세요. 사용자가 떠날 때는 삭제할지, 이전할지, 개인으로 유지할지 결정하세요.
읽기 쉬운 작은 공유 규칙 집합:
누군가 "접근이 필요해요"라고 하면 어떤 수준인지 물어보세요: 개인 항목인지, 팀 업무인지, 조직 전체인지. 세 가지에 맞지 않으면 보통 범위가 명확하지 않다는 신호입니다.
예: 고객 지원 티켓은 조직 소유일 수 있고(관리자가 모든 티켓을 리포트할 수 있게), Support로 팀 태그되어 올바른 큐에 보이며, Jordan에게 할당되어 책임을 명확히 합니다. 할당은 다른 허용된 역할이 보는 것을 막아서는 안 됩니다.
권한은 보통 사람 관련 이벤트: 초대, 팀 이동, 접근 제거 시 깨집니다. 이런 흐름은 모델을 예측 가능하게 할지 여부를 결정합니다.
초대는 멤버십 생성 요청으로 처리하세요. 초대 자체가 접근을 주는 것이 아닙니다. 초대는 수락 시 부여될 조직, 팀(선택 사항), 역할을 명시해야 합니다.
규칙을 엄격히 하세요:
임시 접근은 여기서 다룹니다. "임시 사용자" 역할을 만들기보다 역할 부여에 종료 날짜를 두세요. 만료되면 접근이 자동으로 제거되어 감사 기록이 깔끔합니다.
누군가 조직을 떠날 때 그들의 리소스를 임의로 처리하지 마세요. 규칙이 "리소스는 조직 소유"라면 그걸 지키세요. 기록상 작성자는 남을 수 있지만 소유권은 조직에 남습니다.
사용자 소유 리소스가 있다면 민감한 항목(프로젝트, 문서, API 키 등)은 제거 전 이전을 요구하세요.
한 로그인은 여러 조직에 속할 수 있지만 앱은 항상 하나의 "현재 조직(current org)"을 가져야 합니다. UI에서 분명히 보여주고 모든 행동의 범위를 그것으로 제한하세요.
비활성화(deactivation)는 보통 삭제보다 낫습니다. 지금 접근을 제거하면서 과거 기록은 감사 가능하게 유지합니다.
대부분의 권한 모델은 규칙보다 빠르게 성장해서 실패합니다. 기본(테넌트 경계, 소유권, 범위)을 보호하고 나머지는 세부사항으로 취급하세요.
역할 폭발(Role explosion) 은 전형적인 함정입니다. 예외가 생기면 새 역할을 만들지 말고 더 명확한 권한이나 범위를 만들세요. 몇 달 지나면 아무도 "Manager Plus"가 무엇인지 모릅니다. 자주 필요한 경우에는 이를 일급 퍼미션으로 만드세요. 드물면 만료되는 임시 부여로 처리하세요.
권한 표류(Permission drift) 는 조용하지만 더 위험합니다. 누군가 "한 가지 예외만" 추가하고 모델 문서를 업데이트하지 않으면 1년 후에는 문서와 실체가 일치하지 않습니다. 먼저 모델을 업데이트한 뒤 구현하세요.
팀을 가짜 보안 경계로 사용하는 것 은 지속적인 혼란을 만듭니다. 조직 안에서 팀 간 공유가 가능하면 명확히 밝히세요. 불가능하면 이름으로만 말하지 말고 코드로 강제하세요.
초기에 잡아야 할 레드 플래그들:
지원팀이 고객을 돕기 위해 "잠깐 전역 관리자 권한을 주자"고 하면 이는 테넌트 유출 위험입니다. 대신 명시적이고 로깅되는 접근을 선호하세요(하나의 조직, 특정 시간창, 특정 행동).
모든 요청은 먼저 활성 조직을 결정해야 합니다(서브도메인, 헤더, 세션, 라우트 등에서). 일치하지 않으면 거부하세요.
조직 컨텍스트 다음에는 일관된 순서로 체크를 유지하세요: 먼저 멤버십(이 조직에 속했나?), 그다음 역할(이 조직에서 무엇을 할 수 있나?), 마지막으로 소유권이나 공유(이 레코드에 접근 권한이 있나?)를 확인하세요. 소유권을 멤버십보다 먼저 체크하면 존재 여부에 관한 정보 유출이 발생할 수 있습니다.
실제 계정을 사용하는 소규모 엔드투엔드 테스트를 수행하세요(단위 테스트만이 아님):
역할 변경, 멤버십 제거, 내보내기, 삭제, 설정 업데이트 같은 권한을 바꾸거나 데이터를 이동하는 행동에 기본적인 감사 이벤트를 추가하세요. 처음부터 완벽할 필요는 없지만 "누가 언제 무엇을 했나"에 답할 수 있어야 합니다.
기본값을 검토하세요. 새 조직과 새 멤버는 성공에 필요한 최소 접근으로 시작해야 합니다. 지원과 영업을 위한 내부 권한 FAQ를 짧게 만들어 두면 도움이 됩니다(예: "팀 리더가 다른 팀을 볼 수 있나요?", "제거 후 접근은 어떻게 되나요?").
작고 현실적인 설정으로 시작하세요: 한 고객 회사(한 조직)에 두 팀, Sales와 Ops. 모두 한 번 로그인한 뒤 속한 조직을 선택합니다. Sales는 고객 기록과 견적이 필요하고 Ops는 청구와 내부 설정이 필요합니다.
팀을 그룹화와 워크플로우로 유지하세요. 권한의 주된 스위치가 되게 하지 마세요. 기본값과 라우팅에 영향을 줄 수 있지만 유일한 접근 게이트가 되어서는 안 됩니다.
Admin, Member, Viewer 같은 작은 역할 집합을 고르고 기능이 추가되어도 안정적으로 유지하세요. 역할은 "이 조직에서 무엇을 할 수 있는가?"를 답하고 범위는 "어디에서 할 수 있는가?"를 답합니다.
한 가지 소유권 규칙을 추가하세요: 각 리소스는 조직과 소유자(대개 생성자)를 가진다. 편집은 Admin이거나 소유자이며 역할에 "자신의 항목 편집(edit own)"이 포함된 경우 허용합니다. 보기 권한은 역할에 해당 리소스 타입에 대한 "view"가 포함될 때 허용합니다.
예: Sales 멤버가 견적을 생성합니다. 다른 Sales 멤버는 그것을 볼 수는 있지만 팀과 공유되거나 재할당되지 않는 한 수정할 수 없습니다. Ops 뷰어는 규칙이 Ops가 Sales 리소스를 보도록 허용하는 경우에만 볼 수 있습니다.
200개의 고객 조직을 온보딩할 때도 같은 역할과 같은 소유권 규칙을 재사용합니다. 변경하는 것은 멤버십뿐이지 모델 자체를 바꾸지 않습니다.
지원 요청 "X에 접근 권한을 줄 수 있나요?"는 체크리스트가 됩니다: 조직과 리소스를 확인, 사용자의 그 조직에서의 역할 확인, 소유권과 공유 확인, 그런 다음 역할 변경이나 리소스 공유를 수행하세요. 일회성 예외를 피하고 감사 메모를 남기세요.
한 페이지 모델을 계약으로 다루세요. 모든 API 호출과 UI 화면에서 시행할 수 있는 규칙만 구현하세요. 그렇지 않으면 권한은 "경우에 따라 다름"으로 흐릅니다.
작게 시작하세요: 몇 가지 역할, 명확한 범위, 단순한 소유권. 새 요청("Editor-Manager 역할을 추가할 수 있나요?")이 들어오면 먼저 소유권이나 범위를 조정하세요. 새 역할은 드물어야 합니다.
새 리소스를 추가할 때마다 기본을 일관되게 만드세요:
org_id를 저장(팀이 적용되면 team_id도)가장자리 케이스를 다듬기 전에 실제 흐름(invites, 조직 전환, 관리자 페이지, 누군가 중간에 접근을 잃었을 때)을 테스트하세요.
챗 기반 앱 빌더로 개발 중이라면 권한 모델을 먼저 평이한 언어로 작성하고 제품 사양 옆에 두는 것이 도움이 됩니다. On Koder.ai (koder.ai), Planning Mode와 스냅샷 및 롤백은 이러한 시나리오를 시험하고 웹, 백엔드, 모바일 전반에서 규칙이 동일하게 작동하는지 확인하는 실용적인 방법입니다.