백엔드 데이터 인프라 44편. PostgreSQL 사용자·역할 관리 — CREATE ROLE·GRANT·REVOKE·기본 권한·운영 표준 풀어쓴 학습 노트.
이 글은 백엔드 데이터 인프라 시리즈 70편 중 44편이에요. PG(PostgreSQL 약칭) 보안의 토대 — ROLE 관리.
ROLE = USER + GROUP
PG 8.1+ 부터 "USER" 와 "GROUP" 이 ROLE 하나로 통합됐다. LOGIN 권한이 있으면 "사용자", 없으면 "그룹" (멤버십) 으로 동작한다.
CREATE ROLE alice LOGIN PASSWORD 'strongpass'; -- 사용자
CREATE ROLE app_readonly NOLOGIN; -- 그룹
GRANT app_readonly TO alice; -- alice 가 그룹에 가입
CREATE ROLE 옵션
CREATE ROLE name [
LOGIN | NOLOGIN
SUPERUSER | NOSUPERUSER
CREATEDB | NOCREATEDB
CREATEROLE | NOCREATEROLE
INHERIT | NOINHERIT
REPLICATION | NOREPLICATION
BYPASSRLS | NOBYPASSRLS
CONNECTION LIMIT n
PASSWORD 'value'
VALID UNTIL 'timestamp'
IN ROLE other_role, ...
];
실무에서 자주 쓰는 네 가지 형태.
-- 일반 앱 사용자
CREATE ROLE app_user LOGIN PASSWORD 'pass' CONNECTION LIMIT 50;
-- 읽기 전용
CREATE ROLE analyst LOGIN PASSWORD 'pass';
-- 관리자
CREATE ROLE admin LOGIN PASSWORD 'pass' SUPERUSER;
-- 임시 (만료)
CREATE ROLE temp_dev LOGIN PASSWORD 'pass' VALID UNTIL '2026-12-31';
GRANT·REVOKE
테이블 권한
GRANT SELECT ON users TO analyst;
GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_user;
GRANT ALL ON ALL TABLES IN SCHEMA public TO app_user;
REVOKE INSERT ON users FROM analyst;
스키마 권한
GRANT USAGE ON SCHEMA public TO analyst; -- 스키마 안 객체 보기
GRANT CREATE ON SCHEMA public TO app_user; -- 새 객체 만들기
데이터베이스 권한
GRANT CONNECT ON DATABASE mydb TO analyst;
GRANT CREATE ON DATABASE mydb TO app_user; -- 새 스키마
컬럼 권한 — 세밀
GRANT SELECT (id, name, email) ON users TO analyst;
-- email 만 보고 password 컬럼 안 보임
DEFAULT PRIVILEGES — 새 객체 자동 권한
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO analyst;
이렇게 걸어두면 이후 생기는 모든 테이블에 analyst 가 자동으로 SELECT 를 받는다. 운영 표준.
ALTER DEFAULT PRIVILEGES IN SCHEMA public FOR ROLE app_user
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
FOR ROLE 을 붙이면 그 ROLE 이 만드는 객체로 범위가 좁혀진다.
그룹 멤버십
-- 그룹 만들기
CREATE ROLE readonly NOLOGIN;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO readonly;
-- 사용자 추가
GRANT readonly TO alice;
GRANT readonly TO bob;
GRANT readonly TO charlie;
그룹에 권한을 박아두면 사용자가 자동으로 상속한다. 권한 관리 표준.
INHERIT vs NOINHERIT
CREATE ROLE alice LOGIN INHERIT; -- 기본
CREATE ROLE bob LOGIN NOINHERIT;
GRANT readonly TO alice;
GRANT readonly TO bob;
INHERIT 면 readonly 권한이 자동 적용되고, NOINHERIT 면 SET ROLE readonly 로 명시적으로 전환해야 한다. 거의 항상 기본값 INHERIT.
ALTER ROLE
ALTER ROLE alice PASSWORD 'newpass';
ALTER ROLE alice VALID UNTIL '2026-12-31';
ALTER ROLE alice CONNECTION LIMIT 100;
ALTER ROLE alice NOLOGIN; -- 로그인 막기
ALTER ROLE alice RENAME TO new_name;
DROP ROLE
DROP ROLE alice;
-- ERROR: role "alice" cannot be dropped because some objects depend on it
ROLE 이 "소유한 객체" 가 있으면 못 지운다. 소유권을 옮긴 뒤 지워야 한다.
REASSIGN OWNED BY alice TO new_owner;
DROP OWNED BY alice; -- alice 의 권한·소유 제거
DROP ROLE alice;
운영 권한 패턴 — 4 ROLE 모델
-- 1. 슈퍼유저 (DBA)
CREATE ROLE dba SUPERUSER;
-- 2. 읽기 전용 (분석가)
CREATE ROLE readonly NOLOGIN;
GRANT USAGE ON SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO readonly;
-- 3. 앱 사용자 (CRUD)
CREATE ROLE app_user NOLOGIN;
GRANT USAGE, CREATE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
-- 4. 마이그레이션 (DDL)
CREATE ROLE migrator NOLOGIN;
GRANT app_user TO migrator;
GRANT ALL ON SCHEMA public TO migrator;
-- 개별 사용자 = 그룹 멤버십
CREATE ROLE alice LOGIN PASSWORD 'pass';
GRANT app_user TO alice;
CREATE ROLE bob LOGIN PASSWORD 'pass';
GRANT readonly TO bob;
각 환경(개발·운영) 의 표준 ROLE 셋. 신규 사용자는 그룹에 가입만 시킨다.
Row-Level Security (RLS)
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY orders_owner ON orders
FOR ALL
TO PUBLIC
USING (user_id = current_setting('app.user_id')::BIGINT);
SET app.user_id = '1';
SELECT * FROM orders; -- user_id = 1 인 행만 자동 필터
PG 9.5+ 에서 도입된 "행 단위 권한". 멀티 테넌트 시스템에 강력하다.
비밀번호 모범 사례
-- scram-sha-256 강제 (postgresql.conf)
password_encryption = scram-sha-256
-- 만료 정책
CREATE ROLE alice LOGIN PASSWORD 'pass' VALID UNTIL NOW() + INTERVAL '90 days';
-- 강한 비밀번호
SELECT * FROM gen_random_uuid(); -- 또는 외부 secret manager
scram-sha-256(암호 해시 표준) 을 강제하고, 운영에서는 AWS Secrets Manager·HashiCorp Vault 같은 비밀 관리 서비스를 쓴다.
Spring 백엔드 — 환경별 사용자 분리
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://prod.example.com/mydb
username: app_user_prod
password: ${DB_PASSWORD}
# application-readonly.yml (보고서·분석 서비스)
spring:
datasource:
url: jdbc:postgresql://replica.example.com/mydb
username: readonly_prod
password: ${RO_DB_PASSWORD}
읽기 전용 사용자로 Read Replica(읽기 전용 복제본) 에 접근시켜 운영 사용자와 분리한다.
권한 확인
-- 사용자 권한
\dp users -- psql 메타
\dn+ public -- 스키마 권한
-- 시스템 카탈로그
SELECT * FROM information_schema.role_table_grants
WHERE grantee = 'analyst';
-- 멤버십
SELECT * FROM pg_roles WHERE rolname IN ('alice', 'app_user');
\du+ -- 모든 ROLE
함정 5가지
(1) 앱이 슈퍼유저로 접속
DB 가 통째로 위험해진다. 앱은 무조건 전용 사용자.
(2) DEFAULT PRIVILEGES 안 박음
새 테이블마다 GRANT 를 박아야 하는데 잊기 쉽다. DEFAULT 를 표준으로.
(3) 모든 사용자에게 직접 GRANT
10명 직원에 100 권한이면 GRANT 1000개. 그룹 멤버십이 표준.
(4) DROP ROLE 의 의존성
ROLE 이 소유한 객체가 있으면 못 지운다. REASSIGN OWNED 와 DROP OWNED 로 정리.
(5) 비밀번호 평문
.env 나 코드에 박아두면 위험. Secrets Manager 로 옮긴다.
4 그룹 + 개별 사용자. dba(SUPERUSER) · readonly · app_user · migrator. 사용자는 그룹에 가입만. DEFAULT PRIVILEGES 로 새 테이블 자동. 비밀번호 = Secrets Manager.
한 줄 정리 — PG ROLE = USER + GROUP 통합. LOGIN 가진 ROLE = 사용자. GRANT·REVOKE·DEFAULT PRIVILEGES. 4 그룹 모델 (dba·readonly·app·migrator) + 사용자는 그룹 가입. scram-sha-256·Secrets Manager·RLS 운영 표준.
시험 직전 한 번 더 — ROLE 입문자가 매번 헷갈리는 것
- ROLE = USER + GROUP 통합
- LOGIN ROLE = 사용자
- NOLOGIN ROLE = 그룹
- CREATE ROLE name LOGIN PASSWORD '...' CONNECTION LIMIT N
- 옵션 = SUPERUSER·CREATEDB·CREATEROLE·INHERIT·REPLICATION·BYPASSRLS
- VALID UNTIL = 만료
- GRANT 권한 ON 객체 TO ROLE
- 권한 = SELECT·INSERT·UPDATE·DELETE·USAGE·CREATE·ALL
- 객체 = TABLE·SCHEMA·DATABASE·FUNCTION·COLUMN
- DEFAULT PRIVILEGES = 새 객체 자동 권한
ALTER DEFAULT PRIVILEGES IN SCHEMA ...- FOR ROLE = 그 ROLE 가 만드는 객체
- 그룹 멤버십 = GRANT group_role TO user_role
- INHERIT (기본) = 자동 상속
- NOINHERIT = SET ROLE 명시
- 4 그룹 모델 = dba·readonly·app_user·migrator
- ALTER ROLE = 변경
- DROP ROLE = 의존성 정리 (REASSIGN·DROP OWNED)
- Row-Level Security = 행 단위 권한
- CREATE POLICY 사용 = 멀티 테넌트
- scram-sha-256 = PG 10+ 표준
- password_encryption 설정
- 운영 비밀번호 = Secrets Manager
- 앱 슈퍼유저 X
- \du = ROLE 목록
- \dp = 테이블 권한
- information_schema 권한 뷰
- 한국 운영 = 그룹 + DEFAULT PRIVILEGES + Secrets Manager
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 39편 — 전문 검색 to_tsvector to_tsquery
- 40편 — EXPLAIN 쿼리 계획 읽기
- 41편 — 성능 팁 종합
- 42편 — 운영 설치 바이너리·Docker·관리 서비스
- 43편 — postgresql.conf 핵심 설정
다음 글: