9.2 Role 관리(선언적)
PostgreSQL의 role은 접속과 권한의 주체다. 전통적으로는 CREATE ROLE·ALTER ROLE·DROP ROLE을 손으로 실행해 관리하지만, CloudNativePG에서는 Cluster CRD의 .spec.managed.roles에 원하는 role의 상태를 적어 두면 Operator가 catalog와 주기적으로 비교해 그 상태로 맞춘다. role의 생성·수정·삭제가 매니페스트에 코드로 남으므로, 누가 어떤 권한을 가졌는지가 Git 이력에 그대로 드러난다.
managed.roles 구조
role은 .spec.managed.roles 아래에 리스트로 선언한다. 각 항목은 PostgreSQL의 role 속성을 그대로 필드로 옮긴 형태다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg
spec:
managed:
roles:
- name: dante
ensure: present
comment: application role
login: true
superuser: false
createdb: false
createrole: false
inherit: true
connectionLimit: 10
inRoles:
- pg_monitor
- pg_signal_backend
passwordSecret:
name: pg-dante주요 필드는 다음과 같다.
| 필드 | 의미 | 기본값 |
|---|---|---|
name | role 이름 (필수) | — |
ensure | present(생성·유지) 또는 absent(삭제) | present |
login | 로그인 가능 여부 | false |
superuser | superuser 권한 | false |
createdb | database 생성 권한 | false |
createrole | role 생성 권한 | false |
inherit | 소속 role의 권한 상속 | true |
connectionLimit | 최대 동시 접속 수 (-1은 무제한) | -1 |
validUntil | 비밀번호 만료 시각 | 없음(무기한) |
inRoles | 소속시킬 role 그룹 목록 | 빈 목록 |
passwordSecret | 비밀번호를 담은 Secret 참조 | 선택 |
disablePassword | 비밀번호를 NULL로 설정 | false |
조정 흐름
DBA가 managed.roles를 수정하면 Operator가 이를 PostgreSQL catalog와 비교해 부족한 것은 만들고, 다른 것은 고친다.
flowchart TD
DBA["DBA"] -->|edit managed.roles| CR["Cluster CRD"]
OP["Operator"] -->|주기 비교| CR
OP -->|현재 상태 조회| CAT["pg_authid<br/>(catalog)"]
OP --> DEC{"ensure 값?"}
DEC -->|present| UPSERT["CREATE·ALTER ROLE"]
DEC -->|absent| DROP["DROP ROLE"]
classDef node fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
class DBA,CR,OP,CAT,UPSERT,DROP node
비밀번호 관리
role의 비밀번호는 매니페스트에 평문으로 적지 않고, kubernetes.io/basic-auth 타입의 Secret을 참조한다.
apiVersion: v1
kind: Secret
type: kubernetes.io/basic-auth
metadata:
name: pg-dante
labels:
cnpg.io/reload: "true"
data:
username: ZGFudGU=
password: <base64-encoded-password>Operator는 기본적으로 비밀번호를 클라이언트 측에서 SCRAM-SHA-256으로 해시한 뒤 PostgreSQL에 보낸다. 그래서 평문이 서버 로그에 남지 않는다. cnpg.io/reload: "true" label이 붙은 Secret은 비밀번호 변경이 즉시 반영되고, 없으면 다음 조정 주기에 반영된다.
validUntil— 비밀번호 만료 시각을 지정한다. 생략하면 Operator가 만료되지 않도록(VALID UNTIL 'infinity') 유지한다.disablePassword: true— 비밀번호를 NULL로 만든다.passwordSecret과 함께 쓸 수 없다.
제약과 주의점
선언적 관리라 해도 PostgreSQL 자체의 규칙은 그대로 적용된다.
- 삭제 제약 — role이 객체를 소유하고 있으면
DROP ROLE이 실패한다. Operator는 소유 객체를 자동으로 지우지 않으므로, DBA가 먼저 소유권을 옮기거나 객체를 정리해야 한다. - 실현 불가능한 설정 — 존재하지 않는 그룹에 소속시키는 등 PostgreSQL이 거부하는 요청은 조정에 실패한다. 이런 role은 아래 status의
cannotReconcile에 나타나며 사람의 개입을 요구한다. - 예약 role —
postgres,streaming_replica,cnpg_pooler_pgbouncer는 Operator가 관리하는 예약 role이라 선언적 관리로 삭제할 수 없다.
status로 상태 확인
Cluster의 .status.managedRolesStatus에서 각 role의 조정 결과를 확인할 수 있다.
status:
managedRolesStatus:
byStatus:
reconciled:
- dante
reserved:
- postgres
- streaming_replica
cannotReconcile:
petrarca:
- 'could not perform UPDATE_MEMBERSHIPS: role "poets" does not exist'reconciled— 매니페스트대로 반영된 rolereserved— Operator가 관리하는 시스템 rolecannotReconcile— 해결되지 않은 오류로 개입이 필요한 role
cannotReconcile에 role이 남아 있다면 그 role의 상태는 매니페스트와 다르다는 뜻이다. 메시지에 적힌 원인(위 예시에서는 존재하지 않는 poets 그룹)을 먼저 해소해야 조정이 완료된다.정리
- role은
.spec.managed.roles에 리스트로 선언. Operator가 catalog와 주기적으로 비교 ensure: present는 생성·유지,absent는 삭제- 매니페스트에 없는 role은 건드리지 않아 점진적 도입이 가능
- 비밀번호는
basic-authSecret으로 참조, 기본은 SCRAM-SHA-256 해시로 전달 - 객체를 소유한 role은 삭제 실패, 예약 role은 관리 대상에서 제외
- 조정 결과는
.status.managedRolesStatus의reconciled·cannotReconcile로 확인
다음 절(9.3)에서는 role이 접속할 대상인 database를 선언적으로 관리하는 Database CRD를 본다.