CodeGym /행동 /SQL SELF /행 단위 접근 제어: Row-Level Security (RLS)

행 단위 접근 제어: Row-Level Security (RLS)

SQL SELF
레벨 47, 레슨 3
사용 가능

롤이나 테이블 단위 권한이 "입구에 있는 경비원"이라면, Row-Level Security는 각 방마다 들어갈 수 있는지 체크하는 개인 경비원이야.

RLS는 유저가 테이블에서 허용된 행만 다룰 수 있게 도와줘. 예를 들어:

  • 온라인 쇼핑몰에서 매니저는 자기 주문만 볼 수 있어야 해.
  • CRM 플랫폼에서는 직원이 자기 팀의 고객만 볼 수 있어.
  • 은행 시스템에서는 고객이 자기 계좌만 접근할 수 있어야 해.

RLS가 어떻게 동작하는지

RLS의 핵심은 접근 정책이야. 정책은 어떤 행이 롤이나 유저에게 보이고, 어떤 행이 수정(INSERT, UPDATE, DELETE) 가능한지 정해줘.

기본적으로 RLS는 꺼져있어서, 직접 켜줘야 해.

테이블에 RLS 켜기

온라인 쇼핑몰의 주문을 저장하는 orders 테이블을 만들어보자:

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    user_id INT NOT NULL,
    product_name TEXT NOT NULL,
    price NUMERIC NOT NULL
);

테스트용 데이터도 좀 넣어보자:

INSERT INTO orders (user_id, product_name, price)
VALUES
    (1, '스마트폰', 500),
    (2, '노트북', 1000),
    (1, '이어폰', 100),
    (3, '키보드', 50);

이제 이 테이블에 RLS를 켜보자:

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

뭐가 바뀐 거냐면, 이제 RLS 메커니즘이 활성화됐지만, 정책은 아직 없어. 정책을 만들기 전까지는 RLS가 실제로 접근에 영향을 주지 않아.

접근 정책 만들기

접근 제어 규칙을 추가하려면 이 명령어를 써:

CREATE POLICY 정책_이름
ON 테이블
[FOR { SELECT | INSERT | UPDATE | DELETE }]
TO 롤
USING (접근_조건)
WITH CHECK (체크_조건);
  • FOR: 어떤 작업에 정책을 적용할지 정해 (SELECT, INSERT, UPDATE, DELETE). 생략하면 모든 작업에 적용돼.
  • TO: 어떤 롤에 정책이 적용되는지 지정. 생략하면 모든 롤에 적용돼.
  • USING: 이 조건을 만족하는 행만 유저가 볼 수 있어.
  • WITH CHECK: INSERT나 UPDATE할 때 체크할 조건이야.

예시: 자기 주문만 볼 수 있게

유저가 자기 주문만 볼 수 있게 하는 정책을 만들어보자. 현재 유저의 아이디가 테이블의 user_id랑 같아야 해:

CREATE POLICY user_can_view_own_orders
ON orders
FOR SELECT
USING (user_id = current_user::INT);

여기서 무슨 일이 일어나냐면:

  • 정책 이름은 user_can_view_own_orders야.
  • SELECT 작업에 적용돼.
  • user_id가 현재 유저의 아이디(current_user)랑 같을 때만 행이 보여.

즉, user_id = 1인 유저로 로그인하면 자기 주문만 볼 수 있어.

RLS 동작 확인하기

user1과 user2라는 두 유저를 만들어보자.

CREATE ROLE user1 LOGIN PASSWORD 'password1';
CREATE ROLE user2 LOGIN PASSWORD 'password2';

이 롤들에게 테이블 접근 권한을 주자:

GRANT SELECT ON orders TO user1, user2;

이제 user1로 전환해서 쿼리를 날려보자:

SELECT * FROM orders;

결과: user_id = 1인 행만 보여.

INSERT 정책

유저가 자기 주문만 추가할 수 있게 하고 싶다고 해보자 (user_id가 현재 유저 아이디랑 같아야 함).

INSERT에 대한 정책을 만들어보자:

CREATE POLICY user_can_insert_own_orders
ON orders
FOR INSERT
WITH CHECK (user_id = current_user::INT);

이제 user1이 user_id가 1이 아닌 주문을 추가하려 하면 에러가 나.

UPDATE와 DELETE 정책

데이터 수정이나 삭제도 비슷하게 정책을 만들 수 있어. 예를 들어:

자기 데이터만 수정할 수 있게:

CREATE POLICY user_can_update_own_orders
ON orders
FOR UPDATE
USING (user_id = current_user::INT)
WITH CHECK (user_id = current_user::INT);

자기 데이터만 삭제할 수 있게:

CREATE POLICY user_can_delete_own_orders
ON orders
FOR DELETE
USING (user_id = current_user::INT);

여러 정책 적용하기

한 테이블에 여러 정책을 만들 수 있어. 전부 동시에 적용돼. 한 롤에 여러 규칙이 있으면 PostgreSQL이 전부 체크해 (AND 조건).

RLS 확인 및 디버깅

테이블에 어떤 정책이 있는지 확인하려면 이 명령어를 써:

\di+ 테이블_이름

RLS를 잠깐 끄고 싶으면(예: 관리자용), 이렇게 해:

ALTER TABLE orders DISABLE ROW LEVEL SECURITY;

관리자 롤인 SUPERUSER는 기본적으로 RLS에 제한받지 않아서 모든 데이터를 볼 수 있어.

RLS 설정할 때 흔한 실수

이런 걸 까먹으면 에러가 날 수 있어:

  • ALTER TABLE ... ENABLE ROW LEVEL SECURITY로 RLS를 켜는 걸 잊음.
  • 모든 작업(SELECT, INSERT, UPDATE, DELETE)에 정책을 안 만듦.
  • USING이나 WITH CHECK 조건을 제대로 안 씀. 예를 들어 user_id 체크를 빼먹으면 모든 행에 접근 열릴 수도 있어.

Row-Level Security는 PostgreSQL에서 가장 강력한 보안 도구 중 하나야. 행 단위로 접근을 세밀하게 설정할 수 있고, 접근 제어를 자동화할 수 있어서, 데이터 보호가 중요한 복잡한 앱에 특히 좋아.

2
과제
SQL SELF, 레벨 47, 레슨 3
잠금
복합 정책: 읽기 및 편집 권한 부여
복합 정책: 읽기 및 편집 권한 부여
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION