PostgreSQL RLS 적용과 사례별 예제
PostgreSQL Row Level Security(RLS)의 기본 개념부터 정책 설계, 접근 제어 구현, 실무 예제와 적용 예시 모음
목차
개요
Row Level Security(RLS)는 테이블의 행 단위로 접근을 통제하는 PostgreSQL 기능이다. 다중 테넌시 환경이나 민감한 데이터에서 유용하다. 이 글은 초심자도 이해할 수 있도록 개념 설명부터 설정 예제, 정책 설계 사례와 테스트 방법을 차근히 다룬다.
RLS 기본 개념
왜 RLS가 필요한가
애플리케이션 레벨에서 필터링을 해도 개발 실수로 데이터가 노출될 위험이 있다. RLS는 DB 레벨에서 보안을 강화한다. 권한을 가진 사용자만 특정 행을 조회·수정·삭제하도록 정책을 정의할 수 있다.
주요 용어
- policy: 행 접근 규칙
- role: PostgreSQL 사용자 또는 그룹
- using / with check: select/insert/update 시 조건
기본 설정 절차
다음 순서로 진행하면 기본 RLS 준비가 완료된다.
- 테이블 생성
- RLS 활성화(ALTER TABLE ... ENABLE ROW LEVEL SECURITY)
- 정책 생성(CREATE POLICY)
- 권한 부여(GRANT)
간단한 예제: 테넌트 기반 접근 제어
테넌트별로 tenant_id 컬럼을 두고, 세션 설정으로 현재 테넌트를 지정하는 방식이 흔하다. 아래 예제는 tenant_id 컬럼을 통해 select/insert/update를 제한한다.
CREATE TABLE orders (
id serial PRIMARY KEY,
tenant_id int NOT NULL,
owner_id int NOT NULL,
amount numeric
);
-- RLS 활성화
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
-- 기본 policy: 세션 변수 current_tenant 에 맞는 행만 보기
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.current_tenant')::int)
WITH CHECK (tenant_id = current_setting('app.current_tenant')::int);
-- 권한 부여: 애플리케이션 역할에 대해 SELECT/INSERT/UPDATE 권한 부여
GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_role;
세션에서 현재 테넌트를 설정한 뒤 접속하여 쿼리하면 해당 테넌트 행만 보인다.
-- 세션에서 현재 테넌트 지정
SET app.current_tenant = '42';
-- 이제 SELECT는 tenant_id = 42 인 행만 반환
SELECT * FROM orders;
정책 설계 사례
사례 1: 소유자 기반 접근 제어
사용자별로 owner_id가 일치하는 행만 수정·삭제하도록 할 때 유용하다. SELECT는 공용 정보로 허용하고 UPDATE/DELETE는 소유자만 가능하게 설정한다.
-- SELECT는 모두 허용, UPDATE/DELETE는 owner만
CREATE POLICY owner_select ON orders FOR SELECT USING (true);
CREATE POLICY owner_modify ON orders FOR UPDATE, DELETE
USING (owner_id = current_setting('app.current_user_id')::int)
WITH CHECK (owner_id = current_setting('app.current_user_id')::int);
사례 2: 관리자 예외 처리
관리자 역할은 모든 행에 접근해야 할 때가 있다. policy에 역할 조건을 추가하면 된다.
CREATE POLICY admins_full_access ON orders
USING (
current_setting('app.current_user_role', true) = 'admin'
OR tenant_id = current_setting('app.current_tenant')::int
);
테스트 방법과 유의사항
테스트 절차
- 세션 변수로 사용자, 테넌트 값을 설정
- 권한이 없는 사용자로 접속해 결과 확인
- 관리자 예외, 조인 시 동작을 점검
주의할 점
- DEFAULT ROLE 권한으로 우회할 수 있는지 확인
- 테이블에 존재하지 않는 컬럼을 조건에 쓰면 정책이 예기치 않게 동작
- 함수 사용 시 SECURITY DEFINER의 권한 상승 여부 검토
조인과 서브쿼리 처리
RLS는 각 테이블에 대해 정책을 적용한다. 따라서 조인 시 조인 대상 테이블의 정책도 만족해야 행이 반환된다. 복잡한 뷰나 서브쿼리에서는 성능 및 의도치 않은 필터링이 발생할 수 있어 주의가 필요하다.
트러블슈팅
대표적 문제와 해결
- 쿼리가 빈 결과를 반환: 세션 변수 미설정 또는 정책 조건 불일치 확인
- 관리자도 접근 불가: current_setting의 세컨드 인자(true)로 없을 때 기본값 처리 검토
- 함수 내부에서 권한 상승: SECURITY DEFINER 사용 시 정책 우회 여부 확인
실무 적용 팁
전체 시스템에 RLS를 도입할 때는 단계적으로 적용한다. 먼저 읽기 정책을 적용하고, 로그 및 테스트를 통해 예상된 결과를 검증한 뒤 쓰기 정책을 도입한다. 또한 정책은 가능한 단순하게 유지하여 유지보수성을 높인다.
마무리
PostgreSQL RLS는 데이터베이스 수준에서 강력한 접근 제어를 제공한다. 이 글에서 다룬 postgres rls 설정 예제, row level security postgres 사용법, rls 정책 postgres 사례를 바탕으로 정책을 설계하면 안전한 다중 테넌시 및 사용자 권한 관리를 구현할 수 있다. 초기에는 작은 테이블부터 적용해 테스트를 충분히 수행하는 것을 권장한다.