Confluent Platform への機密データの提供と管理

Confluent for Kubernetes (CFK)には、機密性の高い認証情報と証明書(本ドキュメントでは "シークレット" と呼びます)を Confluent Platform デプロイに安全に提供する機能があります。CFK でサポートされるメカニズムは以下の 2 つです。

  • Kubernetes シークレット

    機密データは Kubernetes シークレットに保管され、Confluent Platform コンポーネントのカスタムリソース(CR)の Kubernetes シークレット(secretRef)を介して参照されます。

  • HashiCorp Vault

    CFK は、厳密なアクセス制御によるセキュアなキーと値のストアを提供する Vault と統合することで、認証情報のセキュリティを強化できます。

    Vault は、コンテナーの特定のディレクトリパスにある CFK または Confluent Platform コンポーネントポッドにシークレットを挿入します。その後、シークレットは Confluent Platform コンポーネントのカスタムリソース(CR)のディレクトリパス(directoryPathInContainer)を介して参照されます。

    シークレットが変更された場合、Vault がポッドでそれらをアップデートし、CFK がアップデートされた情報を動的に読み取ります。

    この機能を使用するには、HashCorp Vault が必要です。

Vault でのシークレットの提供

Vault はシークレットをコンテナーにファイルとして安全に保管し、そのファイルパスを CFK または Confluent Platform ポッドに挿入します。CFK は、ポッドの指定されたディレクトリパスにあるファイルで必要なシークレットを探します。

Vault での認証情報および証明書の提供の包括的なユースケースについては、GitHub の CFK サンプルリポジトリ を参照してください。

注釈

Hashicorp Vault はサードパーティによるソフトウェア製品であり、Confluent ではサポートも販売も一切行っていません。構成の詳細については、製品ドキュメント を参照してください。

すべての CFK の CR とアプリケーション / ワークフローで Vault を利用できます。コンポーネントとアプリケーションは、以下のいずれかのカテゴリに分類されます。

Confluent Platform コンポーネントの CR へのシークレットの提供

Confluent Platform コンポーネントの場合、Vault アノテーションに指定したコンテナーのディレクトリパスにある Confluent Platform コンポーネントポッドにシークレットが挿入されます。

  1. Confluent Platform コンポーネントの CR で、Vault と統合するために 必要なアノテーション を追加します。
  2. Confluent Platform コンポーネントの CR で、directoryPathInContainer プロパティを、Vault の必要なシークレットを含むディレクトリパスに設定します。

Confluent Platform アプリケーションの CR へのシークレットの提供

Confluent Platform アプリケーションのカスタムリソースには関連付けられたポッドがありません。これらのリソースについては、Vault アノテーションを CFK の Helm の値(カスタマイズした Confluent for Kubernetes のデプロイ 内)で構成する必要があります。そのシークレットは、アプリケーションの実行時に CFK ポッドに挿入されます。

以下は、このカテゴリに分類されるアプリケーションリソースです。

  • クラスターリンクの CR
  • スキーマリンクの CR
  • スキーマの CR
  • Kafka のトピックの CR
  • Kafka REST クラスの CR
  • Confluent ロールバインディングの CR
  • コネクターの CR
  1. CFK の Helm values.yaml ファイルで、Vault と統合するために 必要なアノテーション を追加します。
  2. Confluent Platform アプリケーションの CR で、directoryPathInContainer プロパティを、必要なシークレットを含むディレクトリパスに設定します。

CR のない Confluent Platform の処理へのシークレットの提供

There are operations that are not managed with application CRs but are required to use Kafka Admin REST API. Since these operations do not have their own pods, Vault annotations are added to the CFK Helm values (in カスタマイズした Confluent for Kubernetes のデプロイ), their secrets are injected into the CFK pod at runtime for the operations, and CFK defaults to using the same path to search for the credentials in the CFK pod.

以下に、これらの処理の例を示します。

  • クラスターの縮小
  • Kafka のローリング
  • 内部ロールバインディングの作成
  • Connect のステータスでのコネクターの一覧表示
  1. Confluent Platform コンポーネントの CR へのシークレットの提供」の説明に従って、コンポーネントの CR を構成します。

  2. 以下のアノテーションでデフォルトのパスを拡張することもできます。

    platform.confluent.io/directory-path-in-container-suffix=<suffix/path>
    

    前述のアノテーションで、Kafka などの Confluent Platform コンポーネントがシークレットを /vault/secrets に挿入する場合、CFK はポッドの /vault/secrets/suffix/path で同じ認証情報を探します。

    この方法は、コンポーネントのサーバーのシークレットと処理のシークレットの間で、あらゆるパスまたはファイル名の競合を回避する場合にお勧めです。

  3. CFK の Helm values.yaml ファイルで、Vault と統合するために 必要なアノテーション を追加します。

CFK 向けの Vault のアノテーション

HashCorp Vault では、以下のアノテーションが必要です。必要なアノテーションの詳細については、HashCorp Vault のアノテーションに関する説明 を参照してください。

  • vault.hashicorp.com/agent-inject: "true"

    Vault Agent コンテナーをポッドに挿入します。

  • vault.hashicorp.com/agent-inject-status: update

    ローテーション時にシークレットをアップデートします。

  • vault.hashicorp.com/preserve-secret-case: "true"

    シークレットファイルの作成時にシークレット名の大文字小文字を維持します。


挿入対象のシークレットごとに、コンポーネントの CR または CFK の values.yaml ファイルに以下のアノテーションを追加します。アノテーションの詳細については、HashCorp Vault のアノテーションに関する説明 を参照してください。

  • vault.hashicorp.com/agent-inject-secret-<secret-name> = <secret-path>

    Vault の <secret-path> から <secret-name> シークレットを取得する場合に設定します。

  • vault.hashicorp.com/agent-inject-file-<secret-name> = <secret-file>

    <secret-name> が書き込まれる <file name> を設定します。vault.hashicorp.com/agent-inject-secret-<secret-name> アノテーションで使用されているものと同じ <secret-name> を使用してください。

  • vault.hashicorp.com/agent-inject-template-<secret-name> = | {{- with secret “<Vault-secret-path>" -}} {{ .Data.data.data }} {{- end }}

    シークレットのコンテンツ用のテンプレートをフォーマットして作成します。一時的なシークレット名と、指定されたパスにあるシークレットのデータフィールドを使用します。

    vault.hashicorp.com/agent-inject-secret-<secret-name> アノテーションで使用されているものと同じ <secret-name> を使用してください。

    アノテーションを CFK の Helm values.yaml に追加する場合、vault.hashicorp.com/agent-inject-template-<secret-name> アノテーションの値を {{`<value>`}} のように囲みます。

    Confluent Platform の認証情報と証明書に必要な形式については、「Confluent for Kubernetes を使用した認証の構成」および「Confluent for Kubernetes でのネットワーク暗号化の構成」を参照してください。

  • vault.hashicorp.com/secret-volume-path-<secret-name> = <mount-path>

    <secret-name> をポッドのファイルシステムの <mount-path> にマウントします。

    vault.hashicorp.com/agent-inject-secret-<secret-name> アノテーションで使用されているものと同じ <secret-name> を使用してください。

Vault を使用した Confluent Platform にシークレットを提供するための構成

Vault を使用して Confluent Platform にシークレットを提供するには、次の手順に従います。

  1. 必要な認証情報ファイルを作成します。たとえば、Java キーストア形式を使用している場合は、keystore.jkstruststore.jksjksPassword.txt などを作成します。

    必要な Confluent Platform の認証情報と証明書については、「Confluent for Kubernetes を使用した認証の構成」および「Confluent for Kubernetes でのネットワーク暗号化の構成」を参照してください。

  2. Vault を構成します。

    Vault のドキュメントに従って Vault をインストールし、Vault のポリシーと Vault の権限を構成します。

  3. Vault にシークレットを追加します。

    たとえば、Hashicorp Vault の場合、次の手順に従います。

    1. exec コマンドで Vault ポッドに入ります。

      kubectl exec vault-0 sh -it
      
    2. シークレットの値のコンテンツを次のファイルに挿入します。

      cat >  <filename>
      vault kv put secret/<secret-name> data=@<filename>
      
    3. シークレットのコンテンツが想定どおりのものであることを確認します。

      vault kv get secret/<secret-name>
      
  4. Vault がシークレットをポッドに挿入できるようにアノテーションを追加します。必要なアノテーションの一覧については、「CFK 向けの Vault のアノテーション」を参照してください。

  5. コンポーネントまたはアプリケーションの CR で directoryPathInContainer プロパティが Vault のディレクトリパスをポイントするように設定します。

    以下は、「CFK 向けの Vault のアノテーション」の例で指定されているベアラー認証情報を参照する、Kafka REST Class の CR のスニペット例です。

    spec:
      kafkaRest:
        authentication:
          bearer:
            directoryPathInContainer: /vault/secrets
          type: bearer
    

アノテーション例

CFK の values.yaml のアノテーション例:

kind: Deployment
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/agent-inject-file-bearer.txt: bearer.txt
        vault.hashicorp.com/agent-inject-file-c3bearer: bearer.txt
        vault.hashicorp.com/agent-inject-file-connectbearer: bearer.txt
        vault.hashicorp.com/agent-inject-file-fullchain.pem: fullchain.pem
        vault.hashicorp.com/agent-inject-file-krpbearer: bearer.txt
        vault.hashicorp.com/agent-inject-file-ksqldbbearer: bearer.txt
        vault.hashicorp.com/agent-inject-file-privkey.pem: privkey.pem
        vault.hashicorp.com/agent-inject-file-srbearer: bearer.txt
        vault.hashicorp.com/agent-inject-secret-bearer.txt: secret/kafka/bearer.txt
        vault.hashicorp.com/agent-inject-secret-c3bearer: secret/controlcenter/bearer.txt
        vault.hashicorp.com/agent-inject-secret-connectbearer: secret/connect/bearer.txt
        vault.hashicorp.com/agent-inject-secret-fullchain.pem: secret/kafka/fullchain.pem
        vault.hashicorp.com/agent-inject-secret-krpbearer: secret/kafkarestproxy/bearer.txt
        vault.hashicorp.com/agent-inject-secret-ksqldbbearer: secret/ksqldb/bearer.txt
        vault.hashicorp.com/agent-inject-secret-privkey.pem: secret/kafka/privkey.pem
        vault.hashicorp.com/agent-inject-secret-srbearer: secret/schemaregistry/bearer.txt
        vault.hashicorp.com/agent-inject-status: update
        vault.hashicorp.com/agent-inject-template-bearer.txt: |-
          {{- with secret "secret/kafka/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-c3bearer: |-
          {{- with secret "secret/controlcenter/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-connectbearer: |-
          {{- with secret "secret/connect/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-fullchain.pem: |-
          {{- with secret "secret/kafka/fullchain.pem" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-krpbearer: |-
          {{- with secret "secret/kafkarestproxy/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-ksqldbbearer: |-
          {{- with secret "secret/ksqldb/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-privkey.pem: |-
          {{- with secret "secret/kafka/privkey.pem" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-srbearer: |-
          {{- with secret "secret/schemaregistry/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/preserve-secret-case: "true"
        vault.hashicorp.com/role: confluent-for-kubernetes
        vault.hashicorp.com/secret-volume-path-bearer.txt: /vault/secrets
        vault.hashicorp.com/secret-volume-path-c3bearer: /vault/secrets/c3
        vault.hashicorp.com/secret-volume-path-connectbearer: /vault/secrets/connect
        vault.hashicorp.com/secret-volume-path-fullchain.pem: /vault/secrets
        vault.hashicorp.com/secret-volume-path-krpbearer: /vault/secrets/kafkarestproxy
        vault.hashicorp.com/secret-volume-path-ksqldbbearer: /vault/secrets/ksqldb
        vault.hashicorp.com/secret-volume-path-privkey.pem: /vault/secrets
        vault.hashicorp.com/secret-volume-path-srbearer: /vault/secrets/schemaregistry

RBAC、TLS、SASL/PLAIN を構成した Kafka の CR の例:

kind: Kafka
spec:
    authorization:
      superUsers:
      - User:kafka
      type: rbac
    dependencies:
      kafkaRest:
        authentication:
          bearer:
            directoryPathInContainer: /vault/secrets
          type: bearer
    podTemplate:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/agent-inject-file-bearer.txt: bearer.txt
        vault.hashicorp.com/agent-inject-file-jksPassword.txt: jksPassword.txt
        vault.hashicorp.com/agent-inject-file-keystore.jks: keystore.jks
        vault.hashicorp.com/agent-inject-file-ldap.txt: ldap.txt
        vault.hashicorp.com/agent-inject-file-mdsPublicKey.pem: mdsPublicKey.pem
        vault.hashicorp.com/agent-inject-file-mdsTokenKeyPair.pem: mdsTokenKeyPair.pem
        vault.hashicorp.com/agent-inject-file-truststore.jks: truststore.jks
        vault.hashicorp.com/agent-inject-secret-bearer.txt: secret/kafka/bearer.txt
        vault.hashicorp.com/agent-inject-secret-cacerts.pem: secret/cacerts.pem
        vault.hashicorp.com/agent-inject-secret-jksPassword.txt: secret/jksPassword.txt
        vault.hashicorp.com/agent-inject-secret-keystore.jks: secret/kafka-keystore.jks
        vault.hashicorp.com/agent-inject-secret-ldap.txt: secret/kafka/ldap.txt
        vault.hashicorp.com/agent-inject-secret-mdsPublicKey.pem: secret/mdsPublicKey.pem
        vault.hashicorp.com/agent-inject-secret-mdsTokenKeyPair.pem: secret/mdsTokenKeyPair.pem
        vault.hashicorp.com/agent-inject-secret-truststore.jks: secret/kafka-truststore.jks
        vault.hashicorp.com/agent-inject-status: update
        vault.hashicorp.com/agent-inject-template-bearer.txt: |-
          {{- with secret "secret/kafka/bearer.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-cacerts.pem: |-
          {{- with secret "secret/cacerts.pem" -}}
          {{ .Data.data.cacerts }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-jksPassword.txt: |-
          {{- with secret "secret/jksPassword.txt" -}}
          {{ .Data.data.password }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-keystore.jks: |-
          {{- with secret "secret/kafka-keystore.jks" -}}
          {{ .Data.data.keystore | base64Decode }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-ldap.txt: |-
          {{- with secret "secret/kafka/ldap.txt" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-mdsPublicKey.pem: |-
          {{- with secret "secret/mdsPublicKey.pem" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-mdsTokenKeyPair.pem: |-
          {{- with secret "secret/mdsTokenKeyPair.pem" -}}
          {{ .Data.data.data }}
          {{- end }}
        vault.hashicorp.com/agent-inject-template-truststore.jks: |-
          {{- with secret "secret/kafka-truststore.jks" -}}
          {{ .Data.data.truststore | base64Decode }}
          {{- end }}
        vault.hashicorp.com/preserve-secret-case: "true"
        vault.hashicorp.com/role: confluent-operator
        vault.hashicorp.com/secret-volume-path-bearer.txt: /vault/secrets
        vault.hashicorp.com/secret-volume-path-cacerts.pem: /mnt/sslcerts
        vault.hashicorp.com/secret-volume-path-jksPassword.txt: /vault/secrets
        vault.hashicorp.com/secret-volume-path-keystore.jks: /vault/secrets
        vault.hashicorp.com/secret-volume-path-ldap.txt: /vault/secrets
        vault.hashicorp.com/secret-volume-path-mdsPublicKey.pem: /vault/secrets
        vault.hashicorp.com/secret-volume-path-mdsTokenKeyPair.pem: /vault/secrets
        vault.hashicorp.com/secret-volume-path-truststore.jks: /vault/secrets
        vault.hashicorp.com/tls-skip-verify: "true"
    services:
      mds:
        tokenKeyPair:
          directoryPathInContainer: /vault/secrets
    tls:
      directoryPathInContainer: /vault/secrets

Kafka が起動すると、Vault は以下のシークレットを Kafka ポッドに挿入します。

/vault/secrets/bearer.txt
/vault/secrets/cacerts.pem
/vault/secrets/jksPassword.txt
/vault/secrets/keystore.jks
/vault/secrets/ldap.txt
/vault/secrets/mdsPublicKey.pem
/vault/secrets/mdsTokenKeyPair.pem
/vault/secrets/truststore.jks

カスタム Kubernetes シークレットのマウント

Confluent Platform コンポーネントをインストールする場合、Kubernetes シークレット として指定した機密の認証情報の構成値は、Confluent for Kubernetes (CFK)によってセキュアに格納されます。ただし、CFK でシークレットオブジェクトを作成するのではなく、Confluent Platform の構成で使用する既存の独自シークレットを指定する状況が考えられます。そのうち最も一般的なのが カスタム構成オーバーライド の指定というシナリオで、この場合はオーバーライドが CFK によってパススルー構成扱いされ、データがシークレットオブジェクトに属するかどうかは考慮されません。

独自のシークレットオブジェクトを活用するには、シークレットオブジェクトのリストを指定し、Confluent Platform コンポーネントのコンテナーにインメモリーでマウントします。Confluent Platform の シークレットの外部化 機能、およびカスタム構成オーバーライドと組み合わせることで、機密情報を公開することなく、外部ファイルの情報の格納やキーファイルのコンテンツの受け渡しができるよう、独自のシークレットデータを使用して Confluent Platform を構成できます。

マウントされたシークレットを変更すると、クラスターのローリングが行われます。

マウントされたシークレットを指定して使用するには、コンポーネントの CR に以下を追加します。

spec:
  mountedSecrets:
  - secretRef:                                          --- [1]
    keyItems:                                           --- [2]
    - key:                                              --- [3]
      path:                                             --- [4]

  configOverrides:
    server:
      - property=${file:/mnt/secrets/<secretRef>:<key>} --- [5]
  • [1] 使用するシークレットの名前を設定します。コンポーネントのカスタムリソース(CR)の他の部分で参照されているシークレットを使用する必要があります。

  • [2](省略可) keyItems の指定がない場合、シークレットは /mnt/secrets/<secretRef> に格納されます。<secretRef> は [1] で設定された値です。

    詳しくは、『Secret のキーの特定のパスへの割り当て』を参照してください。

  • [3] シークレットキーを設定します。

  • [4] シークレットキー key ([3])の格納先を相対パスで設定します。絶対パスは使用しないでください。文字列 .. も使用しないでください。

    たとえば、secretRefmy-secret-aws に、keycredentials に、pathaws/creds に設定された場合、credentials/mnt/secrets/my-secret-aws/aws/creds/credentials に格納されます。

  • [5] 外部化されるファイルを ${file:/mnt/secrets/<secretRef>:<key>} フォーマットで設定します。

マウントされたシークレットを構成するワークフローの例を以下に示します。

  1. 機密データを含むファイル my_file.txt を作成します。

    username: user1
    password: $ecret_passw0rd
    

    注釈

    The file must use the Linux style line ending that only uses line feed (\n). The Windows style line ending that uses carriage return and line feed (\r\n) does not work in Kubernetes secret files.

  2. 上記のファイルの内容を my_credentials キーに格納するシークレット example-secret を作成します。

    kubectl create secret generic example-secret \
      --from-file=my_credentials=path/to/my_file.txt
    

    my_file.txt の内容が Base64 でエンコードされ、example-secretmy_credentials キーに格納されます。

  3. Kafka の CR で次のように configOverridesmountedSecrets を設定します。

    spec:
      mountedSecrets:
        - secretRef: example-secret
      configOverrides:
        server:
          - kafka.user=${file:/mnt/secrets/example-secret/my_credentials:username}
          - kafka.password=${file:/mnt/secrets/example-secret/my_credentials:password}
    
  4. 次のように Kafka をデプロイします。

    kubectl apply -f <Kafka CR>