PostgreSQL 권한 모델 — 롤이 전부다
PostgreSQL에는 "사용자"와 "그룹"이 따로 없습니다. 둘 다 롤(role) 하나로 통합되어 있습니다. 로그인할 수 있으면 우리가 흔히 부르는 "유저", 다른 롤을 멤버로 담으면 "그룹"처럼 쓰일 뿐, 내부적으로는 같은 객체입니다.
LOGIN속성이 있는 롤 = 접속 계정(User)LOGIN없는 롤 = 권한 묶음(Group)- 권한은 롤에
GRANT로 부여하고, 멤버십으로 상속됩니다.
CREATE USER는 사실 CREATE ROLE ... LOGIN의 별칭입니다. 문서와 실무에서 "user"라고 불러도 실체는 롤이라는 점을 알면 권한 체계가 훨씬 명확해집니다.
롤 생성
-- 로그인 계정 (애플리케이션용)
CREATE ROLE app_user LOGIN PASSWORD 'S3cr3t!23';
-- 권한 묶음(그룹) — 로그인 불가
CREATE ROLE readonly;
CREATE ROLE readwrite;
-- 관리용 속성
CREATE ROLE analyst LOGIN PASSWORD '...'
CONNECTION LIMIT 5 -- 동시 접속 제한
VALID UNTIL '2027-01-01'; -- 만료일주요 속성: LOGIN, SUPERUSER(전권, 남발 금지), CREATEDB, CREATEROLE, REPLICATION, CONNECTION LIMIT, VALID UNTIL.
ALTER ROLE app_user CONNECTION LIMIT 20; -- 속성 변경
ALTER ROLE app_user PASSWORD 'new_pw'; -- 비밀번호 변경권한의 계층 — 3단계로 이해하기
PostgreSQL 권한은 위에서 아래로 층을 이룹니다. 상위 층 권한이 있어야 하위에 접근할 수 있습니다.
| 층 | 권한 예 | 없으면 |
|---|---|---|
| 데이터베이스 | CONNECT, CREATE | 접속·스키마 생성 불가 |
| 스키마 | USAGE, CREATE | 스키마 안 객체를 "볼" 수 없음 |
| 테이블/객체 | SELECT, INSERT, UPDATE, DELETE | 데이터 조작 불가 |
핵심 함정: 테이블에 SELECT를 줘도 그 테이블이 속한 스키마에 USAGE가 없으면 조회가 안 됩니다. 두 층을 모두 부여해야 합니다.
GRANT / REVOKE 실전
읽기 전용 롤을 제대로 구성하는 전체 흐름입니다.
-- 1. 데이터베이스 접속 허용
GRANT CONNECT ON DATABASE appdb TO readonly;
-- 2. 스키마 사용 허용 (이걸 빼먹는 실수가 가장 많다)
GRANT USAGE ON SCHEMA public TO readonly;
-- 3. 기존 테이블 전체에 SELECT
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
-- 4. 시퀀스 조회(필요 시)
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO readonly;쓰기 롤은 여기에 DML을 더합니다.
GRANT USAGE ON SCHEMA public TO readwrite;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO readwrite;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO readwrite; -- SERIAL/자동증가용권한 회수는 REVOKE로 대칭적으로 합니다.
REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM app_user;그룹 멤버십으로 관리 단순화
계정마다 일일이 GRANT하지 말고, 권한은 그룹 롤에 모으고 계정은 그룹에 넣는 방식이 유지보수에 유리합니다.
-- 권한은 그룹에
GRANT readonly TO analyst; -- analyst가 readonly의 모든 권한 상속
GRANT readwrite TO app_user;
-- 멤버십 확인 / 회수
REVOKE readwrite FROM app_user;이제 readonly에 권한을 추가/제거하면, 그 그룹에 속한 모든 계정에 즉시 반영됩니다.
DEFAULT PRIVILEGES — 미래 테이블까지 자동 부여
GRANT SELECT ON ALL TABLES는 실행 시점에 존재하는 테이블에만 적용됩니다. 이후 새로 만든 테이블에는 권한이 없어, 배포할 때마다 조회가 깨지는 사고가 흔합니다. ALTER DEFAULT PRIVILEGES로 앞으로 만들 객체에도 자동 적용되게 합니다.
-- 앞으로 app_owner가 public에 만드는 모든 테이블에 readonly가 SELECT 갖도록
ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA public
GRANT SELECT ON TABLES TO readonly;
ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA public
GRANT SELECT ON SEQUENCES TO readonly;FOR ROLE을 지정하면 그 롤이 새로 만드는 객체에만 적용됩니다. 마이그레이션을 실행하는 소유자 롤을 정확히 지정해야 합니다. 생략하면 명령을 실행하는 현재 롤 기준입니다.
PUBLIC 스키마 함정 — 반드시 알아둘 것
PostgreSQL 14 이하에서는 모든 롤이 기본적으로 public 스키마에 CREATE·USAGE 권한을 갖습니다. 즉 아무 계정이나 public에 테이블을 만들 수 있는 상태가 기본값이었습니다. 하드닝하려면 명시적으로 회수합니다.
-- 아무나 public에 객체 생성하지 못하게
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
-- (선택) 새 DB 자동 접속도 차단
REVOKE ALL ON DATABASE appdb FROM PUBLIC;PostgreSQL 15부터는 이 기본 CREATE 권한이 제거되어 더 안전해졌습니다. 운영 중인 버전을 SELECT version();으로 확인하세요.
권한 조회 — psql 메타 명령
\du -- 롤 목록과 속성
\du+ app_user -- 특정 롤 상세(멤버십 포함)
\dp public.* -- 테이블별 권한(access privileges)
\dn+ -- 스키마 권한특정 롤이 특정 테이블에 무엇을 할 수 있는지 함수로 직접 확인할 수도 있습니다.
SELECT has_table_privilege('readonly', 'public.orders', 'SELECT'); -- t / f최소권한 체크리스트
- 애플리케이션 계정에
SUPERUSER·CREATEDB·CREATEROLE를 주지 않는다. - 앱은 대개
readwrite그룹이면 충분하다. 스키마 변경(DDL)은 별도 마이그레이션 계정으로 분리. - 분석·리포팅 계정은
readonly로만. ALTER DEFAULT PRIVILEGES로 미래 테이블 권한을 미리 설계한다.public스키마의 기본CREATE를 회수해 무단 객체 생성을 막는다.
PostgreSQL 권한은 "롤 = 유저이자 그룹", "권한은 DB→스키마→테이블 3층", "미래 객체는 DEFAULT PRIVILEGES"라는 세 축만 잡으면 대부분의 실전 요구를 깔끔하게 설계할 수 있습니다.
이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.
질문 & 답변 (Q&A)
이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.