> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# TLS でクラスターを保護する

> cert-manager を使用して ClickHouse クラスターを TLS で保護する方法を説明します。クライアント接続と Keeper の暗号化も含みます。

このガイドでは、ClickHouse クラスター全体をエンドツーエンドで暗号化する手順を説明します。具体的には、[cert-manager](https://cert-manager.io/) による証明書の発行、クラスターでの TLS の有効化、セキュアなポート経由でのクライアント接続、さらに Keeper の協調通信への暗号化の適用を扱います。

このガイドは、実際の作業手順に沿って構成されています。`spec.settings.tls` のフィールドごとのリファレンスについては、
[Configuration → TLS/SSL 設定](/docs/ja/products/kubernetes-operator/guides/configuration#tls-ssl-configuration)
および [API リファレンス](/docs/ja/products/kubernetes-operator/reference/api-reference#clustertlsspec) を参照してください。

<div id="prerequisites">
  ## 前提条件
</div>

* オペレーターによって管理されている稼働中の ClickHouse クラスター ([Introduction](/docs/ja/products/kubernetes-operator/guides/introduction)を参照) 。
* クラスターに [cert-manager](https://cert-manager.io/docs/installation/) がインストールされていること。
* クラスターのネームスペースに `kubectl` でアクセスできること。

オペレーター自体は証明書を生成しません。代わりに、ユーザーが用意した Kubernetes の
`Secret` を利用します。cert-manager はその `Secret` の生成とローテーションに推奨される方法ですが、想定された形式で `Secret` を書き込めるツールであればどれでも利用できます。

<div id="secret-format">
  ## オペレーターが想定する証明書の形式
</div>

TLS は、サーバーの鍵ペアを含む Secret を `spec.settings.tls.serverCertSecret` で指定することで有効になります。

| Secret キー | 内容                  | 必須 |
| --------- | ------------------- | -- |
| `tls.crt` | PEM エンコードされたサーバー証明書 | はい |
| `tls.key` | PEM エンコードされた秘密鍵     | はい |

これは cert-manager が `Certificate` リソースに書き込む形式と完全に同じなので、変換は不要です。オペレーターはこの鍵ペアを各ポッドの
`/etc/clickhouse-server/tls/` にマウントし、ClickHouse の `openSSL` 設定に組み込みます。

<Note>
  `tls.enabled: true` の場合、`serverCertSecret` は **必須** です。validating
  webhook は、これが設定されていない状態で TLS を有効にしたクラスターを拒否し、`enabled: true`
  でない限り `required: true` も拒否します。
</Note>

<Steps>
  <Step title="cert-manager で CA をブートストラップする" id="step-1-ca">
    最も再現性の高い構成は、自己署名 CA を作成し、その CA でサーバー
    証明書に署名する方法です。これにより、クライアントが信頼できる固定の `ca.crt` を用意できます。

    ```yaml theme={null}
    # A self-signed issuer used only to mint the CA certificate
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: selfsigned-bootstrap
      namespace: <namespace>
    spec:
      selfSigned: {}
    ---
    # The CA certificate itself
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: clickhouse-ca
      namespace: <namespace>
    spec:
      isCA: true
      commonName: clickhouse-ca
      secretName: clickhouse-ca
      privateKey:
        algorithm: ECDSA
        size: 256
      issuerRef:
        name: selfsigned-bootstrap
        kind: Issuer
    ---
    # A CA issuer that signs leaf certificates from the CA above
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: clickhouse-ca-issuer
      namespace: <namespace>
    spec:
      ca:
        secretName: clickhouse-ca
    ```

    本番環境では、自己署名のブートストラップを実際の issuer (社内 CA、Vault、ACME など) に置き換えてください。変更が必要なのはステップ 2 だけで、クラスターの接続構成は同一です。
  </Step>

  <Step title="サーバー証明書を発行する" id="step-2-cert">
    CA issuer からリーフ証明書をリクエストします。`dnsNames` には、クライアントが
    ポッドのアドレス指定に使用する名前を含める必要があります。オペレーターは
    `<cluster-name>-clickhouse-headless` という名前の単一の **ヘッドレス** Service を作成し、
    各レプリカ ポッドには
    `<cluster-name>-clickhouse-<shard>-<index>-0.<cluster-name>-clickhouse-headless.<namespace>.svc.cluster.local`
    でアクセスできます。
    ヘッドレス Service ドメインに対するワイルドカードを使用すると、すべてのレプリカをカバーできます。

    ```yaml theme={null}
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: clickhouse-server
      namespace: <namespace>
    spec:
      secretName: clickhouse-cert        # <-- the Secret the operator will read
      duration: 8760h                    # 1 year
      renewBefore: 720h                  # rotate 30 days early
      issuerRef:
        name: clickhouse-ca-issuer
        kind: Issuer
      dnsNames:
        - "*.<cluster-name>-clickhouse-headless.<namespace>.svc"
        - "*.<cluster-name>-clickhouse-headless.<namespace>.svc.cluster.local"
        - "localhost"
    ```

    <Note>
      オペレーターは、クラスター全体で利用できる (ロードバランシングされた) Service を**作成しません**。接続先として単一の安定したエンドポイントが必要な場合は、クラスターのポッドを選択する独自の `クラスタIP` Service を作成し、その DNS 名を上記の `dnsNames` に追加してください。
    </Note>

    cert-manager は `tls.crt`、`tls.key`、`ca.crt` を含む `clickhouse-cert` Secret を作成し、有効期限が切れる前に更新します。存在することを確認してください。

    ```bash theme={null}
    kubectl -n <namespace> get secret clickhouse-cert -o jsonpath='{.data}' | jq 'keys'
    # ["ca.crt","tls.crt","tls.key"]
    ```
  </Step>

  <Step title="クラスターでTLSを有効にする" id="step-3-enable">
    クラスターが Secret を参照するように設定します:

    ```yaml theme={null}
    apiVersion: clickhouse.com/v1alpha1
    kind: ClickHouseCluster
    metadata:
      name: <cluster-name>
      namespace: <namespace>
    spec:
      settings:
        tls:
          enabled: true
          required: true            # disable the insecure ports entirely
          serverCertSecret:
            name: clickhouse-cert
    ```

    ### オペレーターが行うこと

    `tls.enabled: true` の場合、オペレーターは次のことを行います。

    * すべてのポッドとヘッドレス Service で **セキュア ポート** `9440`
      (native TLS) および `8443`  (HTTPS) を開きます。これらは既存のポートに追加されます。
    * `/etc/clickhouse-server/tls/` に **Secret をマウント** し、
      `verificationMode: relaxed`、
      `disableProtocols: sslv2,sslv3`、`preferServerCiphers: true` を含む
      ClickHouse の `openSSL` ブロックを生成します。これらは
      デフォルトです。上書きするには、[TLS 設定のカスタマイズ](#custom-tls-settings) を参照してください。

    さらに `required: true` も設定すると、オペレーターは追加で次のことを行います。

    * **非セキュア ポート** `9000`  (native) と `8123`  (HTTP) を削除します。TLS
      バリアントだけが残るため、平文クライアントは接続できなくなります。
    * **ポッドの liveness probe** をセキュアな native ポート `9440` に切り替えるため、
      平文 listener がなくてもヘルスチェックは引き続き機能します。

    <Note>
      TLS ポート `8443` と `9440` は、TLS が無効な場合でも webhook によって **無条件に**
      予約されるため、後から `tls.enabled` を切り替えても
      `spec.additionalPorts` のエントリと競合することはありません。詳細は
      [Configuration → `additionalPorts`](/docs/ja/products/kubernetes-operator/guides/configuration#additional-ports)
      を参照してください。
    </Note>
  </Step>

  <Step title="TLS で接続する" id="step-4-connect">
    `required: true` を設定すると、クライアントはセキュアなポートを使用し、CA を信頼する必要があります。特定のレプリカ ポッドには、ヘッドレス Service (または、作成した独自の `クラスタIP` Service) を介してアクセスします。

    **ネイティブプロトコル** (`clickhouse-client`, ポート `9440`):

    ```bash theme={null}
    clickhouse-client --secure \
      --host <cluster-name>-clickhouse-0-0-0.<cluster-name>-clickhouse-headless.<namespace>.svc.cluster.local \
      --port 9440 \
      --ca-certificate /path/to/ca.crt \
      --query "SELECT 1"
    ```

    **HTTPS** (ポート `8443`):

    ```bash theme={null}
    curl --cacert /path/to/ca.crt \
      "https://<cluster-name>-clickhouse-0-0-0.<cluster-name>-clickhouse-headless.<namespace>.svc.cluster.local:8443/?query=SELECT%201"
    ```

    ローカルでのテスト用に、Secret から `ca.crt` を直接取得します:

    ```bash theme={null}
    kubectl -n <namespace> get secret clickhouse-cert \
      -o jsonpath='{.data.ca\.crt}' | base64 -d > ca.crt
    ```
  </Step>
</Steps>

<div id="keeper-tls">
  ## Keeper トラフィックの暗号化
</div>

ClickHouse クラスターで TLS を有効にしても、Keeper との接続は**暗号化されません**。
`KeeperCluster` 側でも個別に有効にしてください — Keeper
サービス用の証明書を発行し (Keeper サービスの `dnsNames` を使って手順 1～2 を実施) 、それを参照してください:

```yaml theme={null}
apiVersion: clickhouse.com/v1alpha1
kind: KeeperCluster
metadata:
  name: <keeper-name>
  namespace: <namespace>
spec:
  settings:
    tls:
      enabled: true
      required: true
      serverCertSecret:
        name: keeper-cert
```

Keeper は、セキュアなクライアントポートを `2281` で公開します。Keeper で TLS を有効にすると、**ClickHouse
クラスターは自動的に TLS 経由で Keeper に接続します**。ClickHouseCluster 側で追加の設定を行う必要は
ありません。ClickHouse は、システムのトラストストアに加えて、設定した
[`caBundle`](#custom-ca) を使用して Keeper の証明書を検証します。

<div id="custom-ca">
  ## カスタム CA バンドル
</div>

既定では、ClickHouse は接続先のピア (他のレプリカ、Keeper、HTTPS
Dictionary ソース、S3 など) を **システムのトラストストア** に対して検証します。システムストアにルート証明書が含まれていない自己署名 CA や社内 CA などのプライベート CA も **追加で** 信頼するには、
`caBundle` を指定します。

```yaml theme={null}
spec:
  settings:
    tls:
      enabled: true
      serverCertSecret:
        name: clickhouse-cert
      caBundle:
        name: <ca-secret-name>
        key: ca.crt
```

オペレーターはこのバンドルをマウントし、`openSSL` クライアントのトラストストア
(`caConfig`) に追加します。システムのトラストストアも引き続き有効であり、プライベート CA はパブリック
ルートに**加えて**信頼されるため、パブリックエンドポイントへの接続もそのまま機能します。自己署名の
セットアップでは、cert-manager が書き込んだ同じ Secret の `ca.crt` キーを `caBundle` で参照してください
(`cluster_with_ssl` の例のとおり)。

<div id="custom-tls-settings">
  ## TLS 設定のカスタマイズ
</div>

オペレーターが生成する `openSSL` ブロックはデフォルト設定であり、上限ではありません。これは
メインのサーバー設定に書き込まれます。`spec.settings.extraConfig` 配下の内容はすべて
`config.d/99-extra-config.yaml` にレンダリングされ、ClickHouse はそれを**最後に**マージするため、
生成された値を上書きします。

デフォルトを強化するには — たとえば、厳格なピア検証を必須にし、最小
プロトコルを TLS 1.2 に引き上げるには — 変更したい `openSSL.server` のキーを設定します:

```yaml theme={null}
spec:
  settings:
    extraConfig:
      openSSL:
        server:
          verificationMode: strict
          disableProtocols: "sslv2,sslv3,tlsv1,tlsv1_1"
```

マージはキー単位で行われます。置き換えられるのは設定した値のみで、生成されたキーのうち
省略したもの (証明書のパス、CA の設定) は保持されます。使用可能なオプションについては
[`openSSL` サーバー設定](/docs/ja/reference/settings/server-settings/settings#openssl)
を、`extraConfig` がどのようにマージされるかについては
[設定 → 埋め込みの追加設定](/docs/ja/products/kubernetes-operator/guides/configuration#embedded-extra-configuration)
を参照してください。

<div id="troubleshoot">
  ## 確認とトラブルシューティング
</div>

**ヘッドレス Service でセキュアポートが有効になっていることを確認します。**

```bash theme={null}
kubectl -n <namespace> get svc <cluster-name>-clickhouse-headless \
  -o jsonpath='{.spec.ports[*].name}'
# expect: ... tcp-secure http-secure   (and NO tcp/http when required: true)
```

**証明書がポッドにマウントされていることを確認します。**

```bash theme={null}
kubectl -n <namespace> exec <pod> -- ls /etc/clickhouse-server/tls/
# clickhouse-server.crt  clickhouse-server.key   (plus custom-ca.crt when caBundle is set)
```

| 症状                                   | 考えられる原因                                                                                                                                                                                                                      |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TLS を有効にした後、ポッドが起動しない / ボリュームマウントエラー | 参照先の Secret が存在しないか、`tls.crt`/`tls.key` が不足しています (または、`caBundle` が設定されている場合は、それが参照する Secret またはキーが不足しています) 。オペレーターは Secret の内容を検証しないため、キー不足は専用の status 条件ではなく、ポッドのボリュームマウント失敗として表面化します。`kubectl describe pod` でポッドを確認してください。 |
| Webhook がクラスターを拒否する                  | `enabled: true` を設定せずに `required: true` を設定しているか、`serverCertSecret` を設定せずに `enabled: true` を設定しています。                                                                                                                         |
| クライアントで `certificate verify failed`  | クライアントが CA を信頼していません。Secret の `ca.crt` を渡すか、証明書の `dnsNames` に接続先のホストが含まれていることを確認してください。                                                                                                                                      |
| 平文クライアントが突然接続できなくなる                  | `required: true` により、ポート `9000`/`8123` が使えなくなっています。クライアントを `9440`/`8443` に切り替えるか、移行中も安全でないポートを開けたままにするには `required: false` を設定してください。                                                                                        |

<div id="see-also">
  ## 関連項目
</div>

* [設定 → TLS/SSL 設定](/docs/ja/products/kubernetes-operator/guides/configuration#tls-ssl-configuration) — フィールドのリファレンス
* [設定 → `additionalPorts`](/docs/ja/products/kubernetes-operator/guides/configuration#additional-ports) — 予約済みポート
* [API リファレンス → ClusterTLSSpec](/docs/ja/products/kubernetes-operator/reference/api-reference#clustertlsspec)
* [`openSSL` サーバー設定](/docs/ja/reference/settings/server-settings/settings#openssl) — `extraConfig` で上書き可能な TLS オプション
