CloudNativePG 1.30은 왜 DB 운영을 Kubernetes 리소스 계약으로 바꿀까
PostgreSQL을 Kubernetes 위에서 운영할 때, 우리는 DB 설정을 파일 하나로 끝내도 될까, 아니면 역할·승격·네트워크 경계까지 각각 독립된 운영 계약으로 나눠야 할까?
CloudNativePG 1.30은 왜 DB 운영을 Kubernetes 리소스 계약으로 바꿀까
- 카테고리: infra_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: PostgreSQL을 Kubernetes 위에서 운영할 때, 우리는 “DB 설정”을 파일 하나로 끝내도 될까, 아니면 역할·승격·네트워크 경계까지 각각 독립된 운영 계약으로 나눠야 할까?
- 핵심 출처:
- CloudNativePG 1.30.0 Released! - 2026-06-29, 확인일 2026-07-29
- CloudNativePG v1.30.0 GitHub Release - 2026-06-29, 확인일 2026-07-29
- GHSA-7qwx-x8ff-3px9: Instance manager status-server control endpoints relied on network isolation rather than operator authentication - 2026-06-29, 확인일 2026-07-29
- GHSA-x8c2-3p4r-v9r6 / CVE-2026-55769: fixed search_path for operator-issued connections - 2026-06-29, 확인일 2026-07-29
- GHSA-w3gf-xc94-wvmj / CVE-2026-55765: SCRAM-SHA-256 encoding for role passwords - 2026-06-29, 확인일 2026-07-29
1. 왜 지금 봐야 하나
CloudNativePG 1.30.0이 2026년 6월 29일 공개됐다. 겉으로는 PostgreSQL Operator의 마이너 릴리스다. 하지만 인프라 개발자에게는 “Kubernetes 위에서 DB를 운영한다”는 말이 실제로 무엇을 뜻하는지 보여주는 좋은 사례다.
이번 릴리스의 큰 변화는 세 갈래다.
- PostgreSQL role을
DatabaseRole이라는 독립 Kubernetes 리소스로 관리한다. - primary 승격을 Kubernetes
Lease로 직렬화한다. - operator와 instance manager 사이의 신뢰 경계를 보안 패치로 다시 그린다.
이 셋은 모두 같은 질문으로 이어진다.
DB 운영 자동화는 명령을 대신 실행하는 스크립트가 아니라, 누가 무엇을 소유하고 언제 바꿀 수 있고 실패하면 어떻게 멈출지를 선언하는 계약이어야 한다.
최근 이 공부방의 infra_dev 글은 PostgreSQL 18 논리 복제의 WAL retention, etcd control plane 보안, Kubernetes HPA의 custom metrics, Docker Content Trust 종료를 다뤘다. 오늘은 PostgreSQL 자체 기능이나 Kubernetes 오토스케일링이 아니라 Operator가 데이터베이스 운영 절차를 Kubernetes API 객체로 쪼개면서 생기는 권한·장애·보안 경계를 본다.
2. 핵심 개념
Operator는 “자동화 스크립트”보다 “상태 조정자”에 가깝다
Kubernetes Operator는 사용자가 선언한 원하는 상태(desired state)를 보고 실제 상태(actual state)를 계속 맞춘다. DB Operator도 마찬가지다. Cluster 리소스에 PostgreSQL 버전, replica 수, backup 설정을 적으면 Operator가 Pod, Secret, Service, replication, failover 절차를 조정한다.
문제는 데이터베이스 운영이 하나의 상태로 끝나지 않는다는 점이다.
- 애플리케이션마다 필요한 DB role과 권한이 다르다.
- primary 승격은 동시에 두 노드가 primary가 되면 안 된다.
- backup·WAL archive·status endpoint는 정상 운영에는 필요하지만 공격자에게 열리면 장애 도구가 된다.
- role password 변경은 로그·확장·통계 뷰에 남지 않아야 한다.
즉 Operator가 편해질수록, Operator가 가진 권한도 커진다. 그래서 “자동화가 해준다”에서 멈추면 위험하고, 자동화가 어떤 경계 안에서 어떤 계약을 지키는지 봐야 한다.
DatabaseRole: DB 권한을 애플리케이션 소유 리소스로 분리하기
CloudNativePG 1.30의 대표 기능은 DatabaseRole CRD다. 이전에는 관리 role을 Cluster의 .spec.managed.roles 안에 inline으로 넣었다. 이제는 PostgreSQL role 하나를 독립 Kubernetes 객체로 만들 수 있다.
이 변화가 중요한 이유는 단순한 YAML 정리가 아니다.
- 각 role에 독립 lifecycle이 생긴다.
- 각 role에 status가 붙는다.
- Kubernetes RBAC로 “누가 이 role 정의를 바꿀 수 있는가”를 분리할 수 있다.
- role manifest를 애플리케이션 repo 근처에 둘 수 있어 GitOps 흐름에 맞다.
- 삭제 시 DB role을 남길지 지울지 reclaim policy로 생각할 수 있다.
작은 팀에서는 DB 권한이 종종 “초기에 만든 계정 하나”로 굳는다. 하지만 애플리케이션이 늘면 권한 변경은 배포와 같은 속도로 움직여야 한다. DatabaseRole의 핵심은 DB 계정을 Kubernetes 리소스로 만들었다는 사실보다, DB 권한 변경을 코드 리뷰·소유권·상태 확인 가능한 운영 단위로 쪼갰다는 점이다.
Primary Lease: failover는 속도보다 단일성이다
CloudNativePG 1.30은 primary election을 위해 클러스터 이름의 Kubernetes Lease 객체를 사용한다. instance manager는 primary로 동작하기 전에 이 Lease를 잡아야 한다. 정상 종료 시 Lease가 해제되면 replica는 전체 TTL을 기다리지 않고 더 빨리 승격할 수 있다.
하지만 릴리스 노트는 중요한 한계를 분명히 한다. Lease는 “promotion gate”이지 “fence”가 아니다. 즉 Lease는 동시에 여러 노드가 primary로 승격되는 창을 줄이는 장치지만, 이미 고립된 primary를 확실히 차단하는 fencing 메커니즘 자체는 아니다.
이 차이를 이해해야 한다.
- promotion gate: “새 primary가 되기 전에 통행권을 확인한다.”
- fencing: “옛 primary가 절대 쓰기를 계속하지 못하게 끊는다.”
DB 장애 대응에서 가장 무서운 것은 몇 초 늦는 failover보다 split-brain이다. 두 노드가 서로 primary라고 믿고 쓰기를 받으면 데이터 복구가 훨씬 어려워진다. Lease는 이 위험을 줄이는 한 층이지만, 네트워크 분리·스토리지 접근·서비스 라우팅·클라이언트 재시도 정책까지 함께 봐야 한다.
3. 최신 이슈와 연결
이번 릴리스가 단순 기능 추가가 아닌 이유는 보안 권고들이 함께 나왔기 때문이다.
첫째, GHSA-7qwx-x8ff-3px9는 instance manager의 status server control endpoint가 네트워크 격리에만 의존했다는 문제다. CloudNativePG instance manager는 PostgreSQL Pod마다 TCP 8000 status server를 열고, kubelet probe와 operator용 control endpoint를 함께 제공한다. 취약한 버전에서는 /pg/mode/backup, /update, /pg/archive/partial, /pg/controldata 같은 민감 endpoint가 프로세스 내부 인증 없이 네트워크 격리에 기대고 있었다.
권고문은 영향 범위를 과장하지 않는다. RCE나 secret 유출, 무제한 WAL 고갈은 아니라고 명시한다. 하지만 네트워크에서 해당 포트에 닿을 수 있으면 backup orchestration 방해, 일시적 WAL retention, forced checkpoint I/O, 운영 메타데이터 노출이 가능하다. 1.30.0부터는 operator가 ECDSA P-256 client certificate를 만들고 fingerprint를 cluster status에 기록하며, instance manager가 민감 endpoint 호출을 인증한다. 다만 이 hardening은 backport되지 않으므로 이전 버전은 NetworkPolicy로 status port 접근을 제한해야 한다.
둘째, CVE-2026-55769는 unpinned search_path 문제다. Operator가 superuser connection으로 관리 쿼리를 실행할 때 search_path를 고정하지 않으면, database owner가 public schema에 연산자 overload를 심고 검색 경로를 조작해 operator query가 의도치 않은 함수를 실행하게 만들 수 있다. 패치는 operator connection에 search_path = pg_catalog, public, pg_temp를 고정한다.
셋째, CVE-2026-55765는 role password를 ALTER ROLE ... PASSWORD 같은 utility statement에 cleartext로 넣었을 때 pg_stat_statements.track_utility 구성에서 노출될 수 있는 문제다. 1.30.0과 maintenance release는 operator가 cleartext password 대신 SCRAM-SHA-256 verifier를 보내도록 바꿨다.
이 세 이슈가 함께 말하는 것은 하나다.
운영 자동화의 보안 경계는 “내부망이라 괜찮다”, “쿼리를 schema-qualified 했다”, “로그는 껐다” 같은 단일 가정으로 끝나지 않는다.
4. 개발자 관점 해석
1) DB 권한은 Secret만의 문제가 아니다
많은 팀이 DB 보안을 Secret rotation으로만 생각한다. 하지만 실제 권한 운영은 Secret보다 넓다.
- 어떤 role이 어떤 database owner 권한을 갖는가?
- role을 바꾸는 YAML은 어느 repo에 있고 누가 approve하는가?
- role 삭제가 실제 DB 계정 삭제까지 이어져야 하는가?
- client certificate 기반 인증을 쓰면 Secret lifecycle은 어떻게 바뀌는가?
DatabaseRole은 이 질문을 Kubernetes API 객체로 올린다. 애플리케이션 팀에게 필요한 최소 권한을 PR로 제출하게 하고, 플랫폼 팀은 RBAC와 admission policy로 허용 범위를 제한할 수 있다.
2) Failover는 “자동”보다 “관찰 가능”해야 한다
자동 failover를 켜면 마음이 편해지는 것처럼 보인다. 하지만 운영에서 필요한 것은 “언제 primary가 바뀌었는가”, “왜 승격이 지연됐는가”, “이전 primary는 확실히 쓰기를 멈췄는가”를 확인하는 능력이다.
Lease 기반 promotion은 좋은 신호를 준다. Lease holder, renewal time, operator event, primary status warning을 보면 failover 과정이 보인다. 그러나 이 신호를 알림과 runbook에 연결하지 않으면 여전히 블랙박스다.
3) NetworkPolicy는 방화벽이 아니라 운영 API의 ACL이다
CloudNativePG 권고가 보여준 것처럼 Pod 내부 status port는 “외부에 공개하지 않았으니 안전하다”가 아니다. Kubernetes 클러스터 안에는 batch job, debug pod, compromised workload, CI runner, observability agent 등 다양한 주체가 있다. 같은 namespace나 pod network에서 닿을 수 있다면 내부 API도 공격면이다.
따라서 Operator 계열 컴포넌트의 control port는 항상 질문해야 한다.
- 어떤 endpoint가 probe이고 어떤 endpoint가 control인가?
- control endpoint는 자체 인증이 있는가?
- 없다면 NetworkPolicy가 실제로 operator만 허용하는가?
- metrics/probe endpoint가 운영 메타데이터를 얼마나 노출하는가?
4) PostgreSQL의 search_path는 운영 보안 설정이다
search_path는 보통 SQL 편의 기능처럼 보인다. 하지만 이번 CVE는 검색 경로가 privilege boundary가 될 수 있음을 보여준다. 특히 Operator처럼 높은 권한 connection이 tenant-controlled database에 들어가는 구조에서는, relation 이름을 pg_catalog.pg_extension처럼 schema-qualified 해도 연산자 =와 >가 검색 경로를 탈 수 있다.
개발자는 이 사례를 “Postgres 특이한 취약점”으로만 보지 말고, 자동화가 높은 권한으로 실행하는 모든 코드에서 name resolution, plugin loading, path lookup, shell path를 고정해야 한다는 일반 원리로 봐야 한다.
5. 내 프로젝트에 적용할 체크포인트
CloudNativePG를 직접 쓰지 않아도 아래 체크리스트는 그대로 유효하다.
DB Operator / 관리형 Postgres 점검
- 현재 CloudNativePG 버전이 1.30.0, 1.29.2, 1.28.4 이상인지 확인한다.
- 1.28.x는 EOL에 들어갔으므로 1.29 또는 1.30 업그레이드 계획을 만든다.
-
DatabaseRole도입 후보 role을 고른다. 예: 앱 read/write role, migration role, analytics read-only role. - role manifest 소유 repo와 승인자를 정한다.
- role 삭제 시 DB role을 retain할지 delete할지 정책을 문서화한다.
Failover / HA 점검
- primary 승격 조건과 Lease 설정을 runbook에 적는다.
- Lease holder 변경, primary status warning, failover event를 알림으로 받을 수 있는지 확인한다.
- “Lease는 fence가 아니다”를 전제로 옛 primary 차단 경로를 점검한다.
- 클라이언트 connection retry가 split-brain 상황을 악화시키지 않는지 확인한다.
보안 경계 점검
- instance manager status port TCP 8000에 대한 NetworkPolicy가 있는지 확인한다.
- probe endpoint와 control endpoint가 같은 port를 쓰는 컴포넌트를 목록화한다.
-
pg_stat_statements.track_utility,pgaudit, SQL logging이 role password를 남길 수 있는지 확인한다. - tenant나 앱 owner에게
DATABASE OWNER,pg_monitor,pg_read_all_stats가 과하게 주어졌는지 확인한다. - operator-issued connection에서
search_path나 plugin/path resolution이 고정되는지 확인한다.
6. 오늘 10분 액션
-
버전 표 만들기
운영 또는 staging 클러스터에서 CloudNativePG operator image tag를 확인하고, 1.30.0 / 1.29.2 / 1.28.4 이상인지 표로 적는다. -
status port 접근 경로 확인하기
NetworkPolicy가 없다면 “operator namespace/pod selector만 TCP 8000 접근 허용” 정책을 추가하는 티켓을 만든다. 지금 바로 적용하지 않더라도 owner와 due date를 붙인다. -
DB role 하나를 리소스 계약으로 바꿔보기
가장 단순한 read-only role을 골라DatabaseRole로 옮긴다고 가정하고, role owner, manifest repo, 승인자, 삭제 정책, password/cert 인증 방식을 5줄로 적는다.
7. 더 볼 자료
-
CloudNativePG 1.30.0 Released!
DatabaseRole, primary Lease, 보안 hardening, lifecycle 공지를 한 번에 볼 수 있는 공식 릴리스 글이다. -
CloudNativePG v1.30.0 GitHub Release
immutable cluster reference, Barman Cloud Plugin migration timeline, supported Kubernetes/PostgreSQL 버전, 세부 PR 링크를 확인할 때 유용하다. -
GHSA-7qwx-x8ff-3px9
“내부 control endpoint를 NetworkPolicy에만 맡겨도 되는가”를 점검하는 좋은 보안 사례다. -
GHSA-x8c2-3p4r-v9r6 / CVE-2026-55769
PostgreSQLsearch_path가 어떻게 권한 상승 경로가 되는지 자세히 설명한다. -
GHSA-w3gf-xc94-wvmj / CVE-2026-55765
role password가 로그가 아니라 통계 확장에 남을 수 있는 조건을 확인할 수 있다.
중복 회피 메모
로컬 content/generated와 Supabase 최근 infra_dev 글을 확인했다. 최근 글은 Kubernetes custom metrics 기반 HPA/backpressure, etcd control plane 보안 패치, PostgreSQL 18 logical replication과 WAL retention, Docker Content Trust 종료, Cloud Run multi-region health, GKE rollout sequencing, GitHub Linked Artifacts를 다뤘다. 이번 글은 PostgreSQL과 Kubernetes를 다시 언급하지만, DB 엔진 기능·복제 슬롯·HPA·etcd가 아니라 CloudNativePG 1.30의 DatabaseRole, primary Lease, operator-to-instance-manager 인증, search_path/password handling 보안 경계를 통해 “DB 운영을 Kubernetes 리소스 계약으로 쪼개는 법”에 집중해 중복을 피했다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)