PROD주권 유럽 BaaS 플랫폼대시보드 열기 →

공학 · 10분 읽음

RLS vs 프로젝트별 전용 데이터베이스

Affane Daylami · Fondateur · 2026년 7월 27일

블로그로 돌아가기

"RLS 다중 테넌트 포스트그레스"를 검색하면 거의 모든 곳에서 동일한 스키마(공유 데이터베이스,tenant_idcolumn, 행을 필터링하는 정책)를 발견하게 됩니다. 이는 Aurabase가 프로젝트를 서로 분리하기 위해 사용하는 모델이 아닙니다. 각 프로젝트는 다른 클라이언트와 절대 공유되지 않는 자체 Postgres 16 데이터베이스를 받습니다. RLS는 거기에 남아 있지만 다른 층, 즉 귀하의 사용자를 위해 데이터베이스에 있습니다.

이 영어 텍스트는 프랑스어 원본에서 자동으로 생성되었으며 아직 검토되지 않았습니다.
이 페이지는 자동으로 번역되었습니다. 영어 버전은 권위가 있습니다.

"RLS"와 "다중 테넌트"는 해당 주제에 대해 이미 게시된 거의 모든 콘텐츠에서 나란히 발견됩니다. 이는 많은 SaaS 아키텍처에 대한 합법적인 선택이지만, 자체 클라이언트를 서로 분리하려는 Aurabase의 선택은 아닙니다. 이번 포스팅에서는 단순화된 마케팅 설명이 아닌, 실제 프로비저닝 엔진과 실제로 적용된 RLS 정책과의 차이점을 설명합니다. Aurabase의 Managed Postgres 엔진이 격리를 넘어 다루는 내용에 대한 개요는 데이터베이스설명서를 참조하세요.

필수사항

  • 프로젝트 간에 Aurabase는 RLS 단독이 아닌 전용 Postgres 기반으로 격리합니다. 각 프로젝트는 전용 CNPG 클러스터(회사 수준) 또는 자체 조직(무료/프로/팀)의 CNPG 클러스터에 자체 물리적 기반을 가지며 다른 조직과 공유하지 않습니다.
  • RLS(auth.uid(), auth.role(), auth.jwt())는 활성 상태로 유지되며 자체 사용자를 격리하기 위해 기반 내에서 권장됩니다(Supabase와 동일한 규칙).
  • service_role 및 프로젝트 기반 관리 역할은 설계상 RLS를 우회합니다(BYPASSRLS): 결함이 아닌 서버 운영을 위한 가정된 아키텍처 선택입니다.
  • 이 저장소에서 이미 수정된 회귀(이전 공유 스키마에서 오류로 부여된 PUBLIC 권한)는 기본 수준의 경계가 순전히 애플리케이션 경계보다 더 잘 저항하는 이유를 구체적으로 보여줍니다.
#
기본 모델

대부분의 다중 테넌트 RLS 가이드가 취하는 지름길

다중 테넌트 Postgres에 대해 가장 문서화된 패턴은 단일 베이스, 각 테이블의 tenant_id 열, 이 열을 JWT에서 추출된 값과 비교하는 RLS 정책의 세 줄로 구성됩니다. 연결 풀, 다이어그램, 실행할 단일 인스턴스 등 경제적이며 테넌트가 많고 작으며 개별 지분이 낮은 경우에 잘 작동합니다.

타협은 현실입니다. 두 클라이언트 사이의 경계는 테이블별로 평가되는 SQL 표현식이 됩니다. 새 테이블에서 잊혀진 정책, 수퍼유저 역할로 실행되는 연결, 실시간으로 실행되는 디버그 스크립트 등 이러한 각 사건은 비록 작동상 사소한 것일지라도 동시에 모든 테넌트의 라인을 자동으로 노출할 수 있습니다. 보안 경계와 기술 경계(기본)는 정확히 동일합니다.

정보

이는 그 자체로는 나쁜 선택이 아니며 많은 제품에 대한 올바른 절충안입니다. 이 게시물의 요점은 다른 곳에 있습니다. 이는 Aurabase가 자체 클라이언트(잠재적으로 규정 준수 요구 사항이 다른 전체 프로젝트)를 서로 분리하기 위해 만든 타협이 아닙니다.

#
코드에서

두 개의 아키텍처, 프로젝트 간에 공유되는 기반 없음

최근 프로비저너 통합(코드에 "작업 12"로 표시됨) 이후 Aurabase의 활성 Postgres 프로젝트는 정확히 두 가지 아키텍처에 속합니다. 여러 프로젝트 간에 실제로 공유되는 베이스가 있는 이전 모델은 프로비저닝 경로에서 제거되었습니다.

provisioning/instances.rsrust
pub enum ProjectInstanceKind {
    /// 이 유일한 프로젝트 전용 CNPG 클러스터(회사 수준).
    FullyDedicated,

    /// 프로젝트의 CNPG 클러스터에 있는 데이터베이스 ORGANIZATION —
    /// 동일한 조직의 다른 프로젝트와 공유됨,
    /// 절대 제3자 조직과 함께 하지 마세요.
    SharedClusterDedicated,
}

프로젝트 수준에 따라 두 가지 중 어느 것이 적용되는지 결정됩니다. 대시보드에서 선택한 상자가 아니라 결정하는 것은 코드입니다.

provisioning/rules.rsrust
fn should_provision_dedicated(engine: &str, db_url_encrypted: &Option<String>, plan: &str) -> bool {
    matches!(engine, "postgres" | "postgresql")
        && plan == "enterprise"
        && !non_empty(db_url_encrypted)
}

// should_route_to_fleet(): 회사가 아닌 모든 계층(무료/프로/팀)
// 귀하의 조직의 CNPG 클러스터로 라우팅하지 마십시오.
// 다른 것에서 — 마이그레이션 073, 2개 아키텍처로의 통합을 참조하세요.
치수FullyDedicated(회사)SharedClusterDedicated(무료/프로/팀)
CNPG 클러스터이 하나의 프로젝트에 전념공유되지만 두 조직 간에는 공유되지 않음
포스트그레스 데이터베이스앱, 그 앱에서만 프로젝트 가능project_<uuid>, 클러스터의 프로젝트당 하나
PostgreSQL 로그인클러스터의 단일 프로젝트: 멤버 간 위험 없음프로젝트별 로그인(F-013), 해당 역할의 구성원이 테넌트_<uuid>

두 아키텍처 모두에서 기본 또는 클러스터는 서로 다른 두 조직을 호스팅하지 않습니다. 따라서 문제는 "데이터가 격리되어 있습니까?"가 아니라 "프로젝트에 컴퓨팅 CloudNativePG이 모두 자체적으로 포함되어 있습니까, 아니면 동일한 조직의 다른 프로젝트와 공유합니까?"입니다.

두 아키텍처의 이러한 통합은 최근에 이루어졌습니다. 이전에 코드는 두 개의 추가 경로, 즉 여러 프로젝트가 동일한 데이터베이스에 공존하고 다이어그램으로만 격리된 "공유 마스터"와 postgrest_dedicated_shared_db변형을 전달했습니다. 전용 마이그레이션을 통해 이를 제거하고 projects 테이블의 제약 조건을 나머지 두 값으로만 ​​강화했습니다. 이는 공유 스키마 모델이 아래 설명된 버그의 소스였기 때문입니다.

#
보안 경계

전용 기반이 고객 간에 공유되는 EPIRB보다 뛰어난 이유

별도의 Postgres 데이터베이스는 행 수준 경계가 아닌 연결 수준 경계입니다. 프로젝트 A의 데이터베이스에 연결된 애플리케이션 역할은 프로젝트 B의 테이블을 쿼리할 수 없습니다. 즉, 열려 있는 세션이 없습니다. 이 속성은 RLS 정책이 제대로 작성되지 않았거나, 테이블에서 누락되었거나, 높은 역할에 의해 우회된 경우에도 유지됩니다. 최악의 경우는 단일 데이터베이스 내에 국한됩니다.

이 보증금에는 반대 위험을 보여주는 실제 버그의 흔적도 있습니다. 이전 공유 스키마 모델(철회 이후)에서 provision_postgres_schema는 실수로 각 프로젝트 스키마에 GRANT ALL ... TO PUBLIC 권한을 부여했습니다. PUBLIC는 멤버십 조건 없이 데이터베이스의 모든 역할에 적용되며 프로젝트별로 격리된 로그인은 다른 스키마를 읽고 쓸 수 있습니다. 수정 마이그레이션(066)을 통해 기존 권한에서 이러한 권한이 제거되었습니다.

배운 교훈

패치는 누출을 막기 위해 RLS 정책을 하나 더 추가하지 않았습니다. 두 프로젝트가 데이터베이스를 공유할 가능성을 제거했습니다. 현재 두 가지 아키텍처에 대해 provisioning.rs의 주석은 이를 흑백으로 문서화합니다. "각 프로젝트에는 이미 자체 물리적 Postgres 데이터베이스가 있습니다." 기본 수준 경계는 항상 올바르게 작성되는 모든 정책에 의존하는 대신 이러한 버그의 전체 클래스에 도달할 수 없도록 만듭니다.

2026년 8월 23일의 패치는 같은 방향으로 진행됩니다. 프로비저너가 무조건 배치한 REVOKE ALL ON SCHEMA public는 이전 공유 데이터베이스 모델에 대한 실제 격리만 제공했기 때문에 토폴로지에서 조건부로 만들어졌습니다. 현재 두 아키텍처에서는 public.<table>을 명시적으로 참조하는 SQL 덤프 가져오기를 이점 없이 차단했습니다.

#
실제로 RLS

EPIRB는 사용자를 위해 데이터베이스에 그대로 유지됩니다.

위의 어느 것도 EPIRB를 쓸모 없게 만들지 않습니다. 단지 바닥만 바꿀 뿐입니다. 에서 프로젝트 데이터베이스에 들어가면 Aurabase는 Supabase에서 사용하는 PostgREST 규칙을 정확하게 노출합니다. request.jwt.claims의 게이트웨이에서 설정한 JWT 클레임을 읽는 세 가지 SQL 함수입니다.

libs/aura-migrations/golden/auth_global.sqlsql
create function auth.uid() returns uuid
    language sql stable security definer
    set search_path to 'pg_catalog', 'pg_temp'
    as $$
    select nullif(nullif(current_setting('request.jwt.claims', true), '')::json->>'sub', '')::uuid
$$;

이러한 도우미는 귀하를 위해 문서화되는 것이 아니라 Aurabase 자체의 실제 정책에서 사용됩니다. 다음은 저장소에 배치된 storage_objects를 보호하는 정책입니다(읽기 위해 여러 줄로 형식화됨).

libs/aura-migrations/golden/storage.sqlsql
alter table storage_objects enable row level security;

create policy storage_objects_select on storage_objects
  for select using (
    (owner_id = auth.uid())
    or (
      exists (
        select 1 from storage_buckets b
        where (b.name = storage_objects.bucket_name and b.public)
      )
    )
  );

애플리케이션 테이블을 운반하는 자체 project_<uuid>스키마에서 Aurabase는 의도적으로 사용자를 대신하여 어떤 정책도 배치하지 않습니다. 코드는 이를 "Supabase 모델"로 문서화합니다. 테이블의 RLS는 동일한 기능, 동일한 구문을 사용하여 계속해서 사용자의 책임입니다.

#
BYPASSRLS 가정

service_role은 RLS를 우회합니다. 의도적으로 설계된 것이지 우연이 아닙니다.

Postgres는 기본적으로 모든 정책을 무시하는 역할 속성, BYPASSRLS을 제공합니다. Aurabase는 aura_service_role(브라우저 측에 노출되지 않는 서버 역할)와 ALTER SCHEMA ... OWNER TO와 같은 DDL 작업 중에 사용되는 각 프로젝트별 관리 역할이라는 두 가지 역할 계열에서 이를 자발적으로 사용합니다.

provisioning/roles.sqlsql
create role aura_service_role nologin bypassrls;
-- 서버 역할: 브라우저 측에 노출되지 않으며 구성원이 아닙니다.
-- 다른 프로젝트의 역할.

요청을 처리하는 역할 anon/authenticated — tenant_<uuid> —에는 BYPASSRLS이 없습니다. RLS는 예외 없이 정상적으로 적용됩니다. 보너스로, 각 프로젝트에 특정한 시스템 다이어그램(_auth, _storage, _platform)은 정책 없이 활성화된 RLS를 수신합니다. 따라서 기본적으로 우회가 아닌 역할에 대한 전체 거부, 애플리케이션 경로가 어느 날 실수로 액세스하는 경우를 대비한 심층적인 방어입니다.

정보

상승된 서버 역할로 RLS를 우회하는 것은 Aurabase에만 국한된 것이 아닙니다. 이는 Supabase 측의 service_role과 동일한 구성입니다. 요점은 BYPASSRLS을 피하는 것이 아니라 클라이언트에서 액세스할 수 있는 역할에 이를 부여하지 않고 단일 프로젝트로 제한하는 것입니다.

이 서버 역할은 보안 및 RBAC페이지에 자세히 설명된 사전 정의된 역할, 사용자 정의 RBAC, 감사 로그 등 광범위한 상태의 일부입니다.

#
심층 방어

공유 클러스터에서는 데이터베이스가 모든 작업을 단독으로 수행하지 않습니다.

SharedClusterDedicated수준에서는 동일한 조직의 여러 프로젝트가 단일 CNPG 클러스터에 공존합니다. 물리적 데이터베이스는 이미 프로젝트를 서로 분리하지만 PostgreSQL 역할은 데이터베이스가 아닌 클러스터에 대한 전역 개체입니다. 따라서 Aurabase는 프로젝트별로 별도의 PostgreSQL 로그인 계층을 추가합니다.

libs/aura-core/src/lib.rsrust
pub fn project_authenticator_role(project_id: &str) -> String {
    format!("project_{}_authenticator", project_id.replace('-', '_'))
}

// 기본적으로 활성(F013_PER_PROJECT_AUTHENTICATOR), 비활성화 가능
// 명시적으로 비상 탈출로.

각 프로젝트는 자체 로그인으로 연결되며 자체 tenant_<uuid> / tenant_<uuid>_admin 역할의 구성원만 연결되며 동일한 클러스터에 있는 다른 프로젝트의 구성원은 절대 연결되지 않습니다. 데이터베이스는 이미 데이터를 격리합니다. 프로젝트별 이 로그인은 연결되는 ID도 격리하므로 프로젝트의 인시던트는 해당 로그인에 다른 로그인에 상속할 멤버십을 제공하지 않습니다.

#
귀하의 아키텍처를 위해

RLS 단독 또는 전용 기반: 자체 SaaS를 결정하는 방법

Aurabase의 선택은 보편적인 규칙이 아닙니다. 특정 사례에 대한 절충안입니다. 즉, 클라이언트가 제어할 수 없는 플랫폼에서 잠재적으로 서로 다른 규정 준수 요구 사항을 가진 클라이언트를 서로 격리하는 것입니다. 자체 SaaS를 구축하는 경우 다른 규모로 동일한 질문이 발생합니다.

  • RLS(공유 베이스 tenant_id 포함) — 테넌트가 많고 개별적으로 지분이 낮으며 테넌트당 기본 비용이 불균형한 경우에 적합합니다. 예외 없이 각 테이블에서 pg_prove를 사용하여 각 정책을 테스트합니다.
  • 전용 기반 또는 다이어그램 — 테넌트에 자체 규정 준수 문제(의료, HR, 공공 부문)가 있을 때마다 관련되며, 성능 격리를 정당화하는 볼륨 또는 두 특정 클라이언트 간의 누수 비용이 추가 인프라 비용에 비례하지 않습니다.

The Aurabase pricing level applies this same arbitration to its own clients: shared base by organization by default, dedicated cluster when the challenge of the project justifies it. For RLS patterns inside your own database — ownership, multi-tenant by organization, role hierarchy — the RLS guide in production details the three cases with pgTAPtests. And if the auto-generated API on your diagram interests you beyond REST, the comparison on pg_graphql versus Hasura and PostGraphile covers the other half of the Postgres surface exposed by Aurabase.

#
자주 묻는 질문

자주 묻는 질문

단일 Postgres 데이터베이스에서 테넌트를 격리하는 데 RLS만으로도 충분합니까?+
기술적으로 그렇습니다. 각 테이블이 올바른 정책을 전달하고 비우회 역할을 벗어나는 연결이 없다면 가능합니다. 이것이 바로 Aurabase가 서로 다른 프로젝트 간에 감수하지 않기로 결정한 운영 위험입니다. 각 정책 오류는 단일 기반에 국한됩니다. 단일 프로젝트 내에서 자체 테넌트의 경우 RLS + 테넌트_id는 여전히 합법적이고 널리 사용되는 선택입니다.
무료 프로젝트에 엔터프라이즈 계층과 같은 전용 Postgres 클러스터가 없는 이유는 무엇입니까?+
무료 프로젝트를 포함하여 프로젝트당 전용 CloudNativePG 클러스터는 대부분의 실제 사용과 관계없이 예약된 컴퓨팅을 증가시킵니다. 대신 Aurabase는 서로 알려지지 않은 여러 클라이언트 간의 공통 데이터베이스에 있는 스키마가 아닌 각 비엔터프라이즈 프로젝트에 자체 조직의 CNPG 클러스터에 있는 자체 물리적 Postgres 데이터베이스(다른 조직과 절대 공유되지 않음)를 제공합니다.
auth.uid()는 기술적으로 내가 누구인지 어떻게 알 수 있나요?+
Aurabase 게이트웨이는 JWT를 확인한 다음 트랜잭션 기간 동안 Postgres 세션 매개변수 request.jwt.claims에 해당 클레임을 배치합니다. auth.uid()는 이 JSON에서 하위 필드를 추출하고 이를 uuid로 변환하는 것 이상을 수행하지 않습니다. 요청이 이루어지지 않은 경우(익명 요청 또는 게이트웨이 외부의 직접 연결) current_setting()은 NULL을 반환하고 auth.uid()는 NULL을 반환하며 이는 (owner_id = auth.uid())를 사용하여 정책에 대한 액세스를 닫습니다.

배포할 준비가 되셨나요?

5분 만에 백엔드를 완성하세요.

신용카드 불필요 · 500MB 무료 · 50,000 MAU