> ## 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.

# Protección de un clúster con TLS

> Cómo proteger un clúster de ClickHouse con TLS mediante cert-manager, incluidas las conexiones de Client y el cifrado de Keeper.

Esta guía explica cómo cifrar un clúster de ClickHouse de extremo a extremo: emitir un
certificado con [cert-manager](https://cert-manager.io/), habilitar TLS en el
clúster, conectar un Client a través de los puertos seguros y extender el cifrado al
tráfico de coordinación de Keeper.

Está orientada a tareas. Para consultar la referencia campo por campo de `spec.settings.tls`, consulta
[Configuración → Configuración de TLS/SSL](/docs/es/products/kubernetes-operator/guides/configuration#tls-ssl-configuration)
y la [Referencia de la API](/docs/es/products/kubernetes-operator/reference/api-reference#clustertlsspec).

<div id="prerequisites">
  ## Requisitos previos
</div>

* Un clúster de ClickHouse en ejecución gestionado por el operador (consulte la [Introducción](/docs/es/products/kubernetes-operator/guides/introduction)).
* [cert-manager](https://cert-manager.io/docs/installation/) instalado en el clúster.
* Acceso con `kubectl` al espacio de nombres del clúster.

El operador no genera certificados por sí mismo, sino que consume un `Secret` de Kubernetes
que usted proporciona. cert-manager es la forma recomendada de generar y
rotar ese `Secret`, pero cualquier herramienta que escriba un `Secret` en el formato esperado funciona.

<div id="secret-format">
  ## Cómo debe ser el formato de los certificados para el operador
</div>

TLS se habilita haciendo que `spec.settings.tls.serverCertSecret` apunte a un Secret que
contiene el par de claves del servidor:

| Clave del Secret | Contenido                              | Obligatorio |
| ---------------- | -------------------------------------- | ----------- |
| `tls.crt`        | Certificado de servidor en formato PEM | Sí          |
| `tls.key`        | Clave privada en formato PEM           | Sí          |

Este es exactamente el formato que cert-manager genera para un recurso `Certificate`, por lo que no
hace falta ninguna conversión. El operador lo monta en cada pod de Kubernetes en
`/etc/clickhouse-server/tls/` y lo incorpora a la configuración `openSSL` de ClickHouse.

<Note>
  `serverCertSecret` es **obligatorio** cuando `tls.enabled: true`. El webhook de
  validación rechaza un clúster que habilita TLS sin él, y rechaza `required: true`
  salvo que `enabled: true`.
</Note>

<Steps>
  <Step title="Preparar una CA con cert-manager" id="step-1-ca">
    La configuración más reproducible es una CA autofirmada que luego firma el certificado del servidor.
    Así obtienes un `ca.crt` estable en el que los clientes pueden confiar.

    ```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
    ```

    En producción, reemplaza el Bootstrap autofirmado por tu emisor real (una
    CA corporativa, Vault, ACME, etc.). Solo cambia el Paso 2: la configuración del clúster es
    idéntica.
  </Step>

  <Step title="Emitir el certificado del servidor" id="step-2-cert">
    Solicita un certificado de entidad final al emisor de la CA. Los `dnsNames` deben cubrir la forma en que
    los clientes acceden a los pods de Kubernetes. El operador crea un único Service **headless** llamado
    `<cluster-name>-clickhouse-headless`, y cada pod de Kubernetes de réplica es accesible en
    `<cluster-name>-clickhouse-<shard>-<index>-0.<cluster-name>-clickhouse-headless.<namespace>.svc.cluster.local`.
    Un comodín para el dominio del servicio headless cubre todas las réplicas:

    ```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>
      El operador **no** crea un Service para todo el clúster (con balanceo de carga). Si
      quieres un único endpoint estable al que conectarte, crea tu propio Service de tipo `ClusterIP`
      que seleccione los pods de Kubernetes del clúster y añade su nombre DNS a `dnsNames` más arriba.
    </Note>

    cert-manager crea el Secret `clickhouse-cert` con `tls.crt`, `tls.key` y
    `ca.crt`, y lo renueva antes de que caduque. Verifica que exista:

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

  <Step title="Habilitar TLS en el clúster" id="step-3-enable">
    Configura el clúster para que use el 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
    ```

    ### Lo que hace el operador

    Cuando `tls.enabled: true`, el operador:

    * **Abre los puertos seguros** en cada pod de Kubernetes y en el Service **headless**: `9440`
      (TLS nativo) y `8443` (HTTPS). Se añaden junto con los puertos existentes.
    * **Monta el Secret** en `/etc/clickhouse-server/tls/` y genera el bloque
      `openSSL` de ClickHouse con `verificationMode: relaxed`,
      `disableProtocols: sslv2,sslv3` y `preferServerCiphers: true`. Estos son los
      valores predeterminados; consulta [Personalizar la configuración de TLS](#custom-tls-settings) para cambiarlos.

    Cuando también estableces `required: true`, el operador además:

    * **Elimina los puertos inseguros** `9000` (nativo) y `8123` (HTTP): solo permanecen las variantes
      TLS, por lo que los client en texto plano ya no pueden conectarse.
    * **Cambia la probe de liveness del pod de Kubernetes** al puerto nativo seguro `9440`, para que la comprobación
      de estado siga funcionando sin un listener en texto plano.

    <Note>
      Los puertos TLS `8443` y `9440` están reservados por el webhook **incondicionalmente**,
      incluso cuando TLS está desactivado, por lo que cambiar `tls.enabled` más adelante nunca entra en conflicto con una
      entrada de `spec.additionalPorts`. Consulta
      [Configuración → `additionalPorts`](/docs/es/products/kubernetes-operator/guides/configuration#additional-ports).
    </Note>
  </Step>

  <Step title="Conectar mediante TLS" id="step-4-connect">
    Con `required: true`, los clientes deben usar los puertos seguros y confiar en la CA. Accede
    a un pod de Kubernetes de réplica específico a través del Service headless (o de tu propio Service de tipo `ClusterIP`
    si creaste uno).

    **Protocolo nativo** (`clickhouse-client`, puerto `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** (puerto `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"
    ```

    Extrae `ca.crt` directamente del Secret para pruebas locales:

    ```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">
  ## Cifrado del tráfico de Keeper
</div>

Habilitar TLS en el clúster de ClickHouse **no** cifra la conexión con Keeper.
Habilítelo en el `KeeperCluster` de forma independiente: emita un certificado para el servicio
de Keeper (pasos 1–2 con los `dnsNames` del servicio de Keeper) y haga referencia a él:

```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 expone su puerto de client seguro en `2281`. Una vez que Keeper tiene TLS habilitado, **el
clúster de ClickHouse se conecta a él automáticamente a través de TLS**; no se requiere ninguna configuración adicional en el
lado de ClickHouseCluster. ClickHouse verifica el certificado de Keeper con el almacén de confianza
del sistema, además de cualquier [`caBundle`](#custom-ca) que configure.

<div id="custom-ca">
  ## Bundle de CA personalizado
</div>

De forma predeterminada, ClickHouse verifica los peers a los que se conecta (otras réplicas, Keeper,
dictionary sources de HTTPS, S3, …) con el **almacén de confianza del sistema**. Para **confiar además** en
una CA privada —una CA autofirmada o interna cuya raíz no está en el almacén del sistema—
proporcione un `caBundle`:

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

El operador monta este paquete y lo añade al almacén de confianza del `client` de `openSSL`
(`caConfig`). El almacén de confianza del sistema sigue vigente: se confía en su CA privada **además
de** en las raíces públicas, por lo que las conexiones a endpoints públicos siguen funcionando. Para una
configuración autofirmada, haga que `caBundle` apunte a la clave `ca.crt` del mismo Secret que cert-manager
escribió (como en el ejemplo `cluster_with_ssl`).

<div id="custom-tls-settings">
  ## Personalizar la configuración de TLS
</div>

El bloque `openSSL` que genera el operador es la configuración predeterminada, no un límite. Se escribe
en la configuración principal del servidor; todo lo que esté en `spec.settings.extraConfig` se renderiza en
`config.d/99-extra-config.yaml`, que ClickHouse combina **al final**, por lo que sobrescribe los
valores generados.

Para reforzar la configuración predeterminada —por ejemplo, exigir una verificación estricta del extremo remoto y elevar el
protocolo mínimo a TLS 1.2—, establezca las claves de `openSSL.server` que quiera cambiar:

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

La combinación se realiza por clave: solo se reemplazan los valores que defines, y las claves generadas que
omites (rutas de los certificados, configuración de la CA) se conservan. Consulta las
[opciones de configuración del servidor para `openSSL`](/docs/es/reference/settings/server-settings/settings#openssl)
para ver las opciones disponibles, y
[Configuración → Configuración adicional integrada](/docs/es/products/kubernetes-operator/guides/configuration#embedded-extra-configuration)
para saber cómo se combina `extraConfig`.

<div id="troubleshoot">
  ## Verificar y solucionar problemas
</div>

**Verifique que los puertos seguros estén abiertos en el Service headless:**

```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)
```

**Confirme que el certificado esté montado en el pod de Kubernetes:**

```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)
```

| Síntoma                                                                | Causa probable                                                                                                                                                                                                                                                                                                                                                                                        |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Los pods no se inician / error al montar el volumen tras habilitar TLS | Falta el Secret indicado o no contiene `tls.crt`/`tls.key` (o, cuando se establece `caBundle`, el Secret o la clave a la que hace referencia). El operador no valida el contenido del Secret; si faltan claves, esto se manifiesta como un error al montar el volumen del pod de Kubernetes, no como una condición de estado específica. Inspecciona el pod de Kubernetes con `kubectl describe pod`. |
| El webhook rechaza el clúster                                          | Se estableció `required: true` sin `enabled: true`, o `enabled: true` sin `serverCertSecret`.                                                                                                                                                                                                                                                                                                         |
| `certificate verify failed` del Client                                 | El Client no confía en la CA. Pasa el `ca.crt` del Secret o comprueba que los `dnsNames` del certificado incluyan el host al que te conectas.                                                                                                                                                                                                                                                         |
| Un Client en texto sin cifrar de repente no puede conectarse           | `required: true` quitó los puertos `9000`/`8123`. Cambia el Client a `9440`/`8443`, o establece `required: false` para mantener abiertos los puertos no seguros durante la migración.                                                                                                                                                                                                                 |

<div id="see-also">
  ## Véase también
</div>

* [Configuración → Configuración de TLS/SSL](/docs/es/products/kubernetes-operator/guides/configuration#tls-ssl-configuration) — referencia de campos
* [Configuración → `additionalPorts`](/docs/es/products/kubernetes-operator/guides/configuration#additional-ports) — puertos reservados
* [Referencia de la API → ClusterTLSSpec](/docs/es/products/kubernetes-operator/reference/api-reference#clustertlsspec)
* [Configuración del servidor `openSSL`](/docs/es/reference/settings/server-settings/settings#openssl) — opciones de TLS que se pueden sobrescribir mediante `extraConfig`
