PostgreSQL Role management

注釈

CloudNativePGは、当初から、PostgreSQLインスタンスで必要な特定のロールの作成を管理してきました。

  • postgres スーパーユーザー、streaming_replica 、cnpg_pooler_pgbouncer などの一部の予約済みユーザーPgBouncer Pooler を使用する場合

  • アプリケーションデータベースの低特権の所有者として設定されたアプリケーションユーザー

このプロセスは、 Bootstrap セクションで説明しています。

CloudNativePGは、PostgreSQLデータベースロールの完全なライフサイクル管理を提供します。ロールは次のいずれかで定義できます。

  1. as standalone `DatabaseRole resources <#the-databaserole-resource>` 推奨 、または

  2. the `managed stanza within the Cluster spec <#inline-managed-roles>` 経由 。

共存と優先

2つの方法は相互排他的ではありません。それぞれで異なるロールを同時に管理できます。これが、インラインスタンザからDatabaseRole リソースへの段階的な移行が可能です。同じロール名が両方の場所で定義されている場合のルールのみが必要です。

その場合、 クラスター仕様``managed.roles`` が常に優先されます 。 DatabaseRole はリコンサイル化されず、そのステータスの競合を報告します :ref:``DatabaseRole` リソースのステータス <DatabaseRole リソースのステータス>` を参照してください。

重要

宣言的ロール管理は、データベースには存在するが、クラスター仕様にも`DatabaseRole` にも含まれていないロールを無視します。これらのロールのライフサイクルはPostgreSQL内で引き続き管理されるため、都合の良いときにこの機能を採用できます。


一般的なロール構成の注意事項

使用される管理方法に関係なく、ロール仕様は PostgreSQL structure and naming conventions に従います。

Tip

API Reference を参照してください。

属性の完全なリストについては、

いくつかの点に注意してください。

  1. ensure 属性はPostgreSQLの ではありません 。宣言的ロール管理がロールを作成する present デフォルト absent を有効にし、インライン managed.roles スタンザで のみ 使用できます。 DatabaseRole はensure をサポートしていません。代わりに :ref:``delete` 再利用ポリシーを介した削除 <delete 再利用ポリシーを介した削除>` を介してロールの削除を表現します。

  2. inherit 属性は、PostgreSQLの規則に従って、デフォルトでtrueです。

  3. connectionLimit 属性は、PostgreSQLの規約に従って、デフォルトの-1に設定されます。

  4. inRoles のロールメンバーシップは、デフォルトでメンバーシップなしです。


DatabaseRole リソース

DatabaseRole カスタムリソースは、PostgreSQLデータベースロールを管理する専用のKubernetesネイティブ方法を提供します。

これは、クラスターインフラストラクチャからロールのライフサイクルを分離するため、最新の環境とGitOpsワークフローに推奨されるアプローチです。

注釈

DatabaseRole は、仕様またはパスワードのSecretが変更されたときに適用されます。手動`ALTER ROLE` など、データベースに直接行われた変更は、次回リソースが適用されるまで検出または元に戻されません。対照的に、インライン管理ロールは定期的にデータベースカタログと比較され、仕様に戻されます。 ::

DatabaseRole リソースへのアクセスを許可することのRBACの影響については、 CloudNativePGとCiliumを使用したポッド間のネットワークセキュリティ を参照してください。

DatabaseRole は名前空間スコープです。リソース、spec.cluster を介して参照するCluster 、および消費するpasswordSecret はすべて同じ名前空間に存在する必要があります。

マニフェストの例

apiVersion: postgresql.cnpg.io/v1
kind: DatabaseRole
metadata:
  name: role-dante
spec:
  cluster:
    name: cluster-example
  name: dante
  comment: "Dante Alighieri"
  login: true
  superuser: false
  createdb: true
  databaseRoleReclaimPolicy: delete
  inRoles:
    - pg_monitor
  passwordSecret:
    name: cluster-example-dante

ロール定義のマニフェストの例は、ファイル role-examples.yaml にあります。

ロール再利用ポリシー

databaseRoleReclaimPolicy フィールドは、 DatabaseRole カスタムリソースがKubernetes APIから削除されるときのオペレーターの「最終動作」を定義します。これは、Kubernetesの永続ボリュームの動作を反映しています。

  • ``retain`` デフォルト ロールはデータベースに残ります。これは運用環境にとって最も安全な設定であり、マニフェストが誤って削除された場合でも、データベースユーザーおよびその所有するオブジェクトは変更されないままです。

  • ``delete`` : オペレーターは、Kubernetesオブジェクトがファイナライズされる前に、PostgreSQLでDROP ROLE を実行しようとします。これは、一時的な環境または自動化された環境に最適です。

注釈

ロールがオブジェクトテーブル、スキーマなどを所有している場合、DROP ROLE は失敗し、DatabaseRole は`Terminating` に残り、これらのオブジェクトが再割り当てまたは削除されるまで定期的に再試行されます。オペレーターは、あなたに代わって所有オブジェクトをドロップすることはありません。PostgreSQLでそれらを再割り当てまたはドロップするか、retain に切り替えて、削除を完了します。 ::

ロールの削除

ロールを削除する方法は、ロールの作成方法によって異なります。

  • ``DatabaseRole`` によって作成されます リソースを削除します。ロールがPostgreSQLから削除されるかどうかは、その :ref:``delete` 再利用ポリシーを介した削除 <delete 再利用ポリシーを介した削除>` によって制御されます。

  • 既存の、または他の場所で管理されている DatabaseRole は、ドロップするツールではありません。インライン managed.roles を介してabsent を宣言します

スタンザを削除するか、 DROP ROLE を直接実行します。

警告

既に存在するロールの`DatabaseRole` を作成する adopts it:オペレーターは、**すべての**属性がマニフェストと一致するように既存のロールを変更します。省略した属性を含み、デフォルトに強制的に戻されます。特に、inRoles にリストされていないメンバーシップは取り消され、省略された`connectionLimit` は`-1` 無制限にリセットされ、ロールに有効期限がある場合、省略された`validUntil` は`infinity` になります。ロールを採用する前に、ロールの現在の属性とメンバーシップを確認し、削除する前に変更されるため、ドロップするだけのロールで`DatabaseRole` をポイントしないでください。

DatabaseRole リソースのステータス

DatabaseRole リソースには、ロールごとの可観測性のための専用のstatus セクションが含まれています。

status:
  applied: true
  observedGeneration: 3
  conditions:
    - lastTransitionTime: "2026-04-04T15:06:23Z"
      message: "2051"
      reason: ChangeDetected
      status: "True"
      type: PasswordSecretChange

PasswordSecretChange 条件は、インスタンスマネージャーの内部信号としてオペレーターによって維持されます。そのメッセージには、オペレーターが最後に観察したパスワードシークレットのresourceVersion が含まれ、その値の変更がパスワードの再適用をトリガーします。この条件は、パスワードシークレットが使用されると表示され、 passwordSecret が仕様から削除されると削除されます。

DatabaseRole がクラスター仕様で既に管理されている名前をターゲットとしている場合 共存と優先 を参照してください、 applied フィールドはfalse になり、次のメッセージが表示されます。

database role is already managed by the CNPG cluster

レプリカクラスター では、ロールはプライマリクラスターが所有し、ローカルにリコンサイルされません。その場合、インスタンスマネージャーは、ロールをfailedではなく_unknown_として報告します。applied フィールドは説明メッセージとともに設定されないnil のままです。クラスターがプライマリに昇格すると、ロールは通常調整されます。

クライアント証明書の生成

DatabaseRole リソースは、クラスターのクライアントCAによって署名され、Kubernetes Secretに保存されているTLSクライアント証明書のオプトイン生成をサポートしています。これにより、 PostgreSQL `cert authentication <https://www.postgresql.org/docs/current/auth-cert.html>`_ が有効になります

パスワードの代替として パスワードを手動でローテーションする必要はなく、プライベートキーはKubernetes Secretとして保存され、クラスターの外部に送信されることはありません。

これを有効にするには、clientCertificate ブロックを仕様に追加します。

apiVersion: postgresql.cnpg.io/v1
kind: DatabaseRole
metadata:
  name: role-dante
spec:
  cluster:
    name: cluster-example
  name: dante
  login: true
  clientCertificate:
    enabled: true
  databaseRoleReclaimPolicy: retain

ブロックが存在する場合、clientCertificate.enabled はデフォルトのtrue になるため、 clientCertificate: {} はそれを有効にすることと同じです。 enabled: false を設定して、ブロックを維持したまま発行をオフにします。

重要

login: true は、 clientCertificate 発行が有効になっている場合に必要です。オペレーターは検証を介してこれを適用し、それ以外の場合はリソースを拒否します。

生成されたシークレット

オペレーターは、同じ名前空間に<databaserole-name>-client-cert という名前のシークレットを作成します。これには2つのキーが含まれています。

Key

Contents

tls.crt

PEM-encoded client certificate, signed by the cluster's client CA

tls.key

PEM-encoded private key

証明書の有効期限はstatus.clientCertificate.expiration に表示されます。

status:
  clientCertificate:
    expiration: "2026-07-01T12:00:00Z"

pg_hba.conf の構成

オペレーターは証明書を生成しますが、 pg_hba.conf は自動的に変更されません**。ロールが認証できるようにするには、 cert メソッドを使用してhostssl ルールをクラスターに追加する必要があります。

spec:
  postgresql:
    pg_hba:
      - hostssl all dante all cert

生成されたシークレットを使用した作業的な接続文字列は次のようになります。

psql "host=<cluster>-rw.<namespace>.svc port=5432 dbname=<db> user=dante \
  sslcert=/path/to/tls.crt sslkey=/path/to/tls.key \
  sslrootcert=/path/to/ca.crt sslmode=verify-full"

リニューアル

クライアント証明書は、オペレーターのグローバル証明書設定を継承します。デフォルトで 90日 の有効期間で発行され、有効期限から 7日 以内になると自動的に更新されます。どちらの値もオペレーター全体で、 CERTIFICATE_DURATION およびEXPIRING_CHECK_THRESHOLD オペレーター設定を介して構成できます。 DatabaseRole ごとに構成はできません。

更新はリコンサイルループによって駆動されます。オペレーターは、証明書の有効期限が近づいているかどうかを確認し、必要に応じて再署名します。 clientCertificate 発行が有効になっている場合、リコンサイルは少なくとも1時間に1回スケジュールされるため、トリガーイベントがなくても有効期限のかなり前に更新が発生します。現在の有効期限は常にstatus.clientCertificate.expiration に反映されます。

削除とオプトアウト

Scenario

Result

clientCertificate.enabled set to false, or the clientCertificate block removed

The cert Secret is deleted; status.clientCertificate is cleared

DatabaseRole deleted

The cert Secret is garbage-collected via owner reference, regardless of databaseRoleReclaimPolicy

注釈

databaseRoleReclaimPolicy: retain は、生成されたシークレットではなく、PostgreSQLロールを保持します。シークレットは、オペレーターがロールを管理しているときにのみ意味があるため、削除時に常にクリーンアップされます。

Bring-your-own-CAの制限

クラスターのクライアントCAシークレットにプライベートキーが含まれていない場合つまり、 spec.certificates.clientCASecret を介して独自のCAを指定した場合、オペレーターは新しい証明書に署名できません。 status.clientCertificate.message に理由を記録し、再試行を停止します。

status:
  clientCertificate:
    message: client CA secret "my-ca" has no private key; bring-your-own-CA
      clusters require manual certificate management

この場合、クライアント証明書を手動で発行および更新する必要があります。

注釈

CNPGは、証明書失効リストCRLを管理しません。証明書の有効期限が切れる前に無効にする必要がある場合は、クラスターのクライアントCAをローテーションします。次のリコンサイルで、オペレーターは、既存の証明書が現在のCAによって署名されていないことを検出し、すべての管理対象クライアント証明書を再発行します。または、証明書のシークレットを削除して、現在のCAによって署名された新しいものをオペレーターに発行させます。


インライン管理対象ロール

クラスター仕様のmanaged スタンザを使用すると、CloudNativePGは.spec.managed.roles で指定されたロールの管理を提供します。この機能により、既存のロールの宣言的管理と、新しいロールがまだ存在しない場合は作成が可能になります。

マニフェストの例

宣言的ロール管理を使用するクラスターのマニフェストの例は、ファイル cluster-example-with-roles.yaml にあります。

次に、そのファイルからの抜粋を示します。

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
spec:
  managed:
    roles:
      - name: dante
        ensure: present
        comment: Dante Alighieri
        login: true
        superuser: false
        inRoles:
          - pg_monitor
          - pg_signal_backend

インライン管理対象ロールのステータス

インラインメソッドを使用する場合、Cluster ステータスには包括的な概要が含まれます。

status:
  managedRolesStatus:
    byStatus:
      reconciled:
        - dante
      reserved:
        - postgres
        - streaming_replica
    cannotReconcile:
      petrarca:
        - could not perform UPDATE_MEMBERSHIPS on role petrarca: role "poets" does not exist

データベースおよびCloudNativePGが受け入れられない操作、および人間の介入を必要とする操作用の特別なサブセクションcannotReconcile に注意してください。

このセクションでは、オペレーター使用のために予約されているロールと、宣言的管理の下ではない**ロールをカバーし、データベースインスタンスのロールの包括的なビューを提供します。

Kubectl Plugin は、 status サブコマンドで管理対象ロールのステータスも表示します。

Managed roles status
Status                  Roles
- -----                  -----
pending-reconciliation  petrarca
reconciled              app,dante
reserved                postgres,streaming_replica

Irreconcilable roles
Role      Errors
- ---      ------
petrarca  could not perform UPDATE_MEMBERSHIPS on role petrarca: role "poets" does not exist

インライン管理ロールからDatabaseRole への移行

ロールをインラインmanaged.roles スタンザからスタンドアロンのDatabaseRole に中断せずに移動できます。

  1. 目的の仕様でDatabaseRole を作成します。両方のメソッドは同じを共有します RoleConfiguration

構造なので、スタンザをそのままコピーできます。

  1. Cluster マニフェストの.spec.managed.roles から一致するエントリーを削除します。

  2. オペレーターは変更を検出し、管理をDatabaseRole に引き継ぎます。

両方が存在する間はクラスター仕様が優先されるため 共存と優先 を参照してください、ハンドオーバーはインラインエントリがなくなったときにのみ発生するため、ロールが非管理のままになるウィンドウはありません。

インラインスタンザがensure: absent で削除したロールを変換する場合、DatabaseRole はensure: absent をサポートしていないことに注意してください。代わりに :ref:delete` 再利用ポリシーを介した削除 <`delete` 再利用ポリシーを介した削除>` を介した高速削除。\ ``databaseRoleReclaimPolicy: delete でリソースを削除してロールを削除するか、デフォルトのretain をそのままにしておきます。完全な動作については、 ロールの削除 を参照してください。


パスワード管理

宣言的ロール管理機能 DatabaseRole およびインラインmanaged.roles スタンザの両方を使用する場合には、ロールパスワードの調整が含まれます。管理対象ロール構成では、オプションでユーザー名とパスワードが保存される シークレット の名前を指定できます。

passwordSecret:
  name: cluster-example-dante

シークレットのタイプはkubernetes.io/basic-auth である必要があります。ユーザー名Kubernetesで通常のように_Base64_でエンコードされたは、パスワードを設定しているロールと一致する必要があります。例

apiVersion: v1
data:
  username: ZGFudGU=
  password: ZGFudGU=
kind: Secret
metadata:
  name: cluster-example-dante
  labels:
    cnpg.io/reload: "true"
type: kubernetes.io/basic-auth

重要

上記のように、シークレットに`cnpg.io/reload: "true"` のラベルを付けます。ラベル付きシークレットのパスワードの変更はすぐに適用されますが、ラベルのないシークレットの変更は、後続の調整時、たとえば、オペレーターが内部キャッシュを更新するときのみに適用されます。

passwordSecret が指定されない場合、インスタンスマネージャーはPostgreSQLの規約に従って、パスワードを使用してロールをCREATE/ALTER しようとしません。

重要

passwordSecret を使用せずに作成された新しいロールは、PostgreSQL内に`NULL` パスワードがあります。

パスワードの無効化

PostgreSQLでパスワードをNULL に明示的に設定するにはパスワードの更新を単に省略することと区別され、 disablePassword フィールドを使用します。

disablePassword: true

注釈

特定のロールで`passwordSecret` と`disablePassword` の両方を設定するのはエラーです。

パスワードの有効期限 VALID UNTIL

PostgreSQLのVALID UNTIL ロール属性は、パスワードの有効期限を制御します。 VALID UNTIL を指定せずに作成されたロールは、PostgreSQLでデフォルトでNULLを取得します。これは、パスワードの有効期限が無期限であることを意味します。

PostgreSQLは、 VALID UNTIL のタイムスタンプタイプを使用します。これには、パスワードの有効期限が無期限であることを示す値'infinity' のサポートが含まれます。 PostgreSQL documentation を参照してください。

参考までに。

宣言的ロール管理では、管理対象ロールのvalidUntil 属性がパスワードの有効期限を制御します。 validUntil は以下のみを取ることができます。

  • Kubernetesタイムスタンプ、または

  • 省略しますデフォルトnull

最初のケースでは、指定されたvalidUntil タイムスタンプは、ロールのVALID UNTIL 属性としてデータベースに設定されます。

2番目のケースvalidUntil 省略 オペレーターは、パスワードの有効期限が決してないことを保証し、PostgreSQLの動作をミラーリングします。具体的には

  • 新しいロールの場合、ロール作成ステートメントのVALID UNTIL 句を省略します

  • 既存のロールの場合、データベースでVALID UNTIL がNULL に設定されていない場合、VALID UNTIL をinfinity に設定します。これは、PostgreSQLがALTER ROLE SQLステートメントでVALID UNTIL NULL を許可していないためです。

事前ハッシュされたパスワード

MD5 / SCRAM-SHA-256ハッシュ形式でパスワードを指定することにより、事前に暗号化されたパスワードを提供することもできます。

kind: Secret
type: kubernetes.io/basic-auth
metadata:
  name: cluster-example-cavalcanti
  labels:
    cnpg.io/reload: "true"
apiVersion: v1
stringData:
  username: cavalcanti
  password: SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>

警告

上記の例では、 stringData: を使用します。ここで、Kubernetesは値をエンコードします。これは、事前にハッシュされたパスワードの最も安全なパスです。 data: を使用する必要がある場合は、printf '%s' "$hash" | base64 または`echo -n "$hash" | base64` でバイトを正確にエンコードします。単純な`echo "$hash" | base64` の末尾の改行により、値はSCRAM / MD5シャドウフォーマットチェックをミスします。そのため、オペレーターはそれを平文として扱うことにフォールバックして再ハッシュし、ログインは機能を停止します。

クリアテキストパスワードを送信する際の安全性

ロールパスワードは、Kubernetesでシークレットを使用して安全に管理されますが、オペレーターとPostgreSQL間のSQLパスも懸念されます。 PostgreSQL documentation で述べたように

パスワードは平文でサーバーに送信され、 > クライアントのコマンド履歴またはサーバーログに記録される場合があります

CloudNativePGは、2つの補完的な方法でこのパスを保護します。

  1. CREATE / ALTER ROLE ... PASSWORD '...' を発行する前に、オペレーターSCRAM-SHA-256は、クリアテキストパスワードをオペレーターサイドPostgreSQLの観点からクライアントサイドでエンコードします。これは、サーバーログとpg_stat_statements またはpgaudit のような拡張機能からクリアテキストを保持するための標準のPostgreSQL実践であり、 psql \password およびlibpqのPQencryptPasswordConn が実行するエンコードと同じです。 PostgreSQLが受け取るリテラルは、pg_authid.rolpassword に保存されているSCRAM-SHA-256ベリファイアです。 MD5またはSCRAM-SHA-256シャドウフォームで既に提供されているパスワードは、変更せずに転送されます。

  2. 同じCREATE /ALTER ROLE ステートメントは、ステートメントログlog_statement とエラーステートメントログlog_min_error_statement の両方を一時的に抑制するトランザクション内で実行され、成功と失敗の両方のシナリオでのPostgreSQLログへの漏洩を防ぎます。

クラスターのStatusセクションは、管理対象ロール操作のクエリステートメントを出力しません。

オペレーターサイドのエンコーディングのオプトアウト

パスワードをハッシュする方法を決定するために演算子ではなくPostgreSQLが必要な場合たとえば、 password_encryption = md5 を実行しているクラスターで、basic-authシークレットにアノテーションcnpg.io/passwordPassthrough: "enabled" を設定します。オペレーターは、パスワード値をそのまま転送します。

警告

cnpg.io/passwordPassthrough アノテーションは、Cluster リソースではなく、**basic-auth Secret**自分自身に設定する必要があります。 Cluster に配置しても効果はなく、オペレーターはPostgreSQLに送信する前にパスワードにSCRAM-SHA-256エンコードを適用し続けます。

オプトインはシークレットごとであり、オペレーターが使用するすべての基本認証シークレット管理対象ロールシークレット、スーパーユーザーおよびアプリケーションユーザーシークレットにも適用されるため、単一のクラスターでパススルーシークレットとオペレーターエンコードされたシークレットを自由に混合できます。 。上記のステートメントロギング抑制レイヤーは、両方のモードに適用されます。

警告

cnpg.io/passwordPassthrough: "enabled" では、オペレーターはシークレットの`password` 値をそのまま転送します。その値がクリアテキストの場合 password_encryption = md5 クラスターでの一般的なケース pg_stat_statements や`pgaudit` などの拡張機能はそれを監視します。これは、PostgreSQLにハッシュ形式を選択させることで予想されるトレードオフです。

実現不可能なロール構成

PostgreSQLでは、場合によっては、コマンドはデータベースが受け入れられず、拒否されます。 PostgreSQL documentation on error codes を参照してください。

詳細については。

ロール操作では、このような基本的なエラーが発生する可能性があります。 2つの例

  • PostgreSQLに、ロールグループpoets のメンバーとしてロールpetrarca を作成するように依頼しますが、 poets は存在しません。

  • PostgreSQLにロールdante を削除するように求めますが、ロールdante はデータベースinferno の所有者です。

これらの基本的なエラーは、人間の管理者の説明がない限り、データベースまたはCloudNativePGオペレーターによって修正できません。上記の2つの例は、それぞれロールpoets を作成するか、データベースinferno を削除することにより修正できますが、それらは人的エラーが原因で発生した可能性があり、そのような場合、提案された「修正」は間違ったものである可能性があります。

CloudNativePGは、 インライン管理対象ロールのステータス で説明しているように、このような基本的なエラーが発生したときを記録し、クラスターステータスに表示します。