CloudNativePG 1.30 的一个关键变化,是把应用访问 PostgreSQL 的身份管理往 Kubernetes 原生方向又推了一步:新增 DatabaseRole CRD,并内置 TLS 客户端证书签发能力。结果是,应用团队可以用声明式资源管理数据库角色,并通过客户端证书连接 PostgreSQL,不再把数据库密码复制到工单、Secret 模板或 CI 变量里。
角色不再只是 DBA 手里的 SQL
在传统 PostgreSQL 运维里,创建应用账号通常意味着有人执行一段 SQL:
CREATE ROLE app_user LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE app TO app_user;
这段 SQL 本身不复杂,麻烦在生命周期:谁创建、谁轮换密码、谁回收权限、环境之间如何保持一致、GitOps 如何审计变更。CloudNativePG 1.30 引入 DatabaseRole CRD 后,数据库角色可以像 Deployment、Secret、Service 一样进入 Kubernetes 控制面。
这带来两个实际收益:
- 应用团队可以提交声明式资源,而不是等待人工执行 SQL。
- 权限变化可以通过 Git 审查、CI 校验和 Kubernetes reconcile 流程落地。
需要注意的是,DatabaseRole 不是“权限设计自动正确”的魔法。它解决的是交付和生命周期问题,角色边界、最小权限、默认权限策略仍然需要团队自己设计清楚。
密码从连接路径里消失
CloudNativePG 1.30 同时提供内置 TLS 客户端证书签发。对应用来说,这意味着连接 PostgreSQL 时可以使用客户端证书认证,而不是拿着明文密码或密码 Secret。
这类模式的价值很直接:
- 应用 Pod 不需要读取数据库密码。
- 密钥材料可以跟 Kubernetes Secret 生命周期绑定。
- 证书过期和轮换可以纳入平台自动化。
- 审计时可以把“谁拥有哪个数据库身份”映射到 Kubernetes 资源。
不过,证书认证不是零成本。你需要关心证书有效期、Secret 挂载权限、应用镜像里的 CA 配置,以及连接池是否正确传递 TLS 参数。密码少了,证书治理不能少。
可以这样实践:为应用声明角色并使用 TLS 连接
下面示例用于说明一种可落地的配置形态。不同 CloudNativePG 安装版本和集群命名可能有字段差异,实际落地前请以你集群中的 CRD schema 为准:
kubectl explain databaserole.spec
kubectl explain cluster.spec.certificates
假设已有一个 CloudNativePG PostgreSQL 集群叫 app-db,运行在 default namespace。可以从声明数据库角色开始:
apiVersion: postgresql.cnpg.io/v1
kind: DatabaseRole
metadata:
name: app-readwrite
namespace: default
spec:
cluster:
name: app-db
name: app_readwrite
ensure: present
login: true
comment: "Application role managed declaratively"
保存为 databaserole.yaml 后应用:
kubectl apply -f databaserole.yaml
kubectl get databaserole app-readwrite
如果你的环境启用了 CloudNativePG 1.30 的客户端证书签发能力,可以为应用准备一个包含客户端证书的 Secret。下面命名和字段是示意性质,重点是把证书、私钥和 CA 作为文件挂载进应用容器:
apiVersion: v1
kind: Pod
metadata:
name: app-client
namespace: default
spec:
containers:
- name: psql
image: postgres:16
command: ["sleep", "3600"]
volumeMounts:
- name: pg-client-cert
mountPath: /etc/postgresql/client
readOnly: true
volumes:
- name: pg-client-cert
secret:
secretName: app-readwrite-client-cert
defaultMode: 0400
应用后进入 Pod 测试连接。请把主机名、数据库名和证书文件名改成你环境中的实际值:
kubectl apply -f app-client.yaml
kubectl exec -it app-client -- bash
psql "host=app-db-rw.default.svc port=5432 dbname=app user=app_readwrite sslmode=verify-full sslrootcert=/etc/postgresql/client/ca.crt sslcert=/etc/postgresql/client/tls.crt sslkey=/etc/postgresql/client/tls.key"
如果是应用代码,连接字符串也应显式带上 TLS 参数。例如 Go、Java、Python 的 PostgreSQL 驱动通常都支持 sslmode、sslrootcert、sslcert、sslkey 这类参数。关键点不是语言,而是不要再把密码作为主要认证材料传进运行时。
GitOps 下的权限变更会更像基础设施变更
DatabaseRole 的价值在 GitOps 场景里尤其明显。一次数据库账号变更可以变成一次普通 pull request:
git checkout -b grant-reporting-role
mkdir -p cnpg/roles
cat > cnpg/roles/reporting-readonly.yaml <<'EOF'
apiVersion: postgresql.cnpg.io/v1
kind: DatabaseRole
metadata:
name: reporting-readonly
namespace: default
spec:
cluster:
name: app-db
name: reporting_readonly
ensure: present
login: true
comment: "Readonly reporting role managed by GitOps"
EOF
git add cnpg/roles/reporting-readonly.yaml
git commit -m "Add reporting PostgreSQL role"
这不是说所有数据库授权都应该丢给应用团队自由修改。更健康的做法是分层:平台团队定义集群、安全基线和证书策略,应用团队声明自己需要的角色,DBA 或数据平台团队审查高风险权限。
落地前的检查清单
引入 DatabaseRole 和无密码 TLS 连接时,可以按下面几项推进:
- 确认 CloudNativePG 版本已经升级到 1.30,并检查 CRD schema。
- 把数据库角色命名规则写清楚,避免 namespace、应用名、数据库名混在一起。
- 为客户端证书设置可接受的有效期和轮换流程。
- 限制证书 Secret 的读取范围,只挂载到真正需要连接数据库的工作负载。
- 在应用连接池里测试 TLS 参数,尤其是
sslmode=verify-full下的服务名校验。 - 用审计流程约束高权限角色,不要让声明式配置绕过权限评审。
CloudNativePG 1.30 的方向很明确:让 PostgreSQL 身份从手工 SQL 和密码 Secret,迁移到 Kubernetes 可审计、可协调、可轮换的资源模型。它不会替你设计权限体系,但能把凭据交付这件事从“靠记忆和脚本”变成“靠资源和控制器”。