PostgreSQL:Grant
GRANT 와 RLS 의 관계
PostgreSQL에서 테이블 접근은 두 단계로 제어됩니다.
- 1단계: GRANT (테이블 수준 권한)
- "이 역할이 이 테이블에 접근할 수 있는가?"
- GRANT가 없으면 해당 역할은 테이블 자체에 접근할 수 없습니다. 문 앞에서 차단되는 것과 같습니다.
- 2단계: RLS (행 수준 권한)
- "접근이 허용된 역할 중, 어떤 행을 볼/수정할 수 있는가?"
- RLS는 GRANT를 통과한 후에 적용됩니다. 문 안에 들어온 사람 중 누가 어떤 방에 들어갈 수 있는지 정하는 것입니다.
Supabase의 역할 구조
- anon - 로그인하지 않은 사용자 (API 키만으로 접근)
- authenticated - 로그인한 사용자 (auth.uid()가 존재)
- service_role - 서버 측 관리자 — RLS를 무시함
테이블에 GRANT가 없으면:
GRANT를 추가하면:
각 권한의 의미
GRANT SELECT, -- 조회 (SELECT 쿼리)
INSERT, -- 삽입 (다른 관리자 추가)
UPDATE, -- 수정
DELETE -- 삭제
ON public.my_table -- 테이블 이름
TO authenticated; -- 로그인한 사용자 역할에게
요약:
- GRANT 없이 RLS만 → 아무도 접근 불가
- GRANT만 있고 RLS 없음 → authenticated 전원이 모든 행에 접근 가능
- GRANT + RLS → authenticated 중 정책을 만족하는 사용자만 접근 가능
테이블의 grant 가 뭔지 확인하는 방법
SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_schema = 'public'
AND table_name = 'admins';
GRANT가 없는 경우:
GRANT가 있는 경우:
grantee | privilege_type
----------------+---------------
authenticated | SELECT
authenticated | INSERT
authenticated | UPDATE
authenticated | DELETE
Supabase 의 GRANT 자동 적용
Supabase는 기본적으로 public 스키마에 다음과 같은 기본 권한이 설정되어 있습니다.
이 설정 때문에 public에 새 테이블을 만들면 anon과 authenticated에 자동으로 GRANT가 적용됩니다.
보안 관점에서, 비로그인 사용자가 테이블에 접근할 이유가 없다면, anon 역할의 권한을 제거하는 것이 더 적절합니다.
PUBLIC grantee
PostgreSQL의 모든 역할을 의미하는 가상 그룹입니다.
- PUBLIC에 GRANT → 현재 + 미래의 모든 역할이 해당 권한을 가짐
- PUBLIC에서 REVOKE → 그 기본 권한을 제거
PostgreSQL은 함수를 생성하면 자동으로 "GRANT EXECUTE TO PUBLIC" 을 적용합니다. 그래서 명시적으로 REVOKE 하지 않으면 anon 포함 누구나 실행할 수 있었던 것입니다.