# Kubeblocks Configure Tls

> Access-security capability entry for TLS and mTLS on existing KubeBlocks clusters. Use when the user wants to enable, verify, or rotate encrypted database connections. Do not use this as a create-time primary entry; create-time routing still starts at preflight plus the dedicated engine skill.

- Skill: `apecloud/kubeblocks-configure-tls` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add apecloud/kubeblocks-configure-tls`
- Raw SKILL.md: https://api.skillmd.com/api/skills/apecloud/kubeblocks-configure-tls/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: apecloud (https://skillmd.com/u/apecloud)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/apecloud/kubeblocks-configure-tls

---


# Configure TLS Encryption

This skill belongs to the **access-security capability layer** for already-created clusters.

## Entry Contract

- Prefer this skill only after the cluster exists and a user is explicitly working on connection security or certificate rotation.
- Use [ops-capability-matrix](../../references/coverage/ops-capability-matrix.yaml) to confirm engine support boundaries, and [addon-capability-matrix](../../references/coverage/addon-capability-matrix.yaml) for docs/example evidence.
- Use [kubeblocks-manage-accounts](../kubeblocks-manage-accounts/SKILL.md) for password rotation, not certificate workflows.
- If TLS failures are mixed with broken service exposure or pod failures, diagnose first with [kubeblocks-troubleshoot](../kubeblocks-troubleshoot/SKILL.md).

## Engine-Aware Boundaries

- **Validated first-class path:** `mysql` and `postgresql` are the safest default engines for this skill in the current repo because both the docs and the capability layering already route cold-start agents here.
- **Needs explicit evidence before rollout:** `redis`, `mongodb`, and `kafka` should not automatically inherit the MySQL/PostgreSQL TLS workflow. Confirm addon evidence and engine behavior before promising enablement.
- **Do not oversell encrypted-by-default semantics:** search, vector, object-storage, and streaming engines may still need engine-native validation or external networking work before this skill becomes executable.

## Overview

KubeBlocks supports TLS encryption for database connections. Three modes are available:

- **Built-in TLS**: KubeBlocks generates and manages certificates automatically (requires cert-manager)
- **User-provided TLS**: Use your own CA and certificates
- **mTLS (Mutual TLS)**: Both server and client authenticate with certificates

If the engine is not clearly covered by the current matrix and references, stop at the contract boundary and escalate instead of applying a generic TLS recipe.

Official docs: https://kubeblocks.io/docs/preview/user_docs/connect-databases/tls-connection

## Pre-Check

Before proceeding, verify the cluster is healthy and no other operation is running:

```bash
# Cluster must be Running
kubectl get cluster <cluster-name> -n <namespace> -o jsonpath='{.status.phase}'

# No pending OpsRequests
kubectl get opsrequest -n <namespace> -l app.kubernetes.io/instance=<cluster-name> --field-selector=status.phase!=Succeed
```

If the cluster is not `Running` or has a pending OpsRequest, wait for it to complete before proceeding.

For built-in TLS mode, verify cert-manager is installed:

```bash
kubectl get pods -n cert-manager
```

## Workflow

```
- [ ] Step 1: Choose TLS mode
- [ ] Step 2: Configure TLS in Cluster CR
- [ ] Step 3: Verify TLS connection
```

## Step 1: Choose TLS Mode

| Mode | Certificate Management | Use Case |
|------|----------------------|----------|
| Built-in (KubeBlocks) | Automatic via cert-manager | Quick setup, dev/test |
| User-provided | Manual (bring your own CA) | Production with existing PKI |
| mTLS | Manual + client certs | High-security environments |

### Why Use cert-manager for Built-in TLS?

cert-manager automates the entire certificate lifecycle — issuance, renewal, and rotation — so you never end up with an expired certificate causing a production outage at 3 AM. Manually managed certificates are fine when you already have a PKI team and established rotation processes, but for most users, cert-manager eliminates a whole class of operational risk. KubeBlocks integrates with cert-manager's `Issuer` and `Certificate` CRDs, so enabling TLS is a single field toggle rather than a multi-step manual process.

TLS docs: https://kubeblocks.io/docs/preview/kubeblocks-for-mysql/07-tls/01-tls-overview

### Prerequisites for Built-in TLS

The built-in mode requires **cert-manager**. Install it if not present:

```bash
# Check if cert-manager is installed
kubectl get pods -n cert-manager

# Install cert-manager if needed
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
```

Wait for cert-manager pods to be ready:

```bash
kubectl wait --for=condition=Ready pods --all -n cert-manager --timeout=120s
```

## Step 2: Configure TLS

### Option A: Built-in TLS (KubeBlocks Managed)

Add TLS configuration to the component spec in the Cluster CR:

```yaml
spec:
  componentSpecs:
  - name: <component>
    tls: true
    issuer:
      name: KubeBlocks
```

This tells KubeBlocks to use cert-manager to automatically generate a self-signed CA and server certificates.

### Option B: User-Provided Certificates

**1. Generate certificates (if you don't have them):**

```bash
# Generate CA key and certificate
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=MyDatabaseCA" -days 3650 -out ca.crt

# Generate server key and CSR
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=<cluster>-<component>" -out server.csr

# Sign server certificate with CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out server.crt -days 365 \
  -extfile <(printf "subjectAltName=DNS:*.<cluster>-<component>-headless.<ns>.svc.cluster.local,DNS:*.<cluster>-<component>.<ns>.svc.cluster.local")
```

**2. Create TLS Secret:**

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: <cluster>-tls
  namespace: <ns>
type: kubernetes.io/tls
data:
  ca.crt: <base64-encoded-ca.crt>
  tls.crt: <base64-encoded-server.crt>
  tls.key: <base64-encoded-server.key>
```

Or create it with kubectl:

```bash
kubectl create secret generic <cluster>-tls -n <ns> \
  --from-file=ca.crt=ca.crt \
  --from-file=tls.crt=server.crt \
  --from-file=tls.key=server.key
```

**3. Reference in Cluster CR:**

```yaml
spec:
  componentSpecs:
  - name: <component>
    tls: true
    issuer:
      name: UserProvided
      secretRef:
        name: <cluster>-tls
        ca: ca.crt
        cert: tls.crt
        key: tls.key
```

### Option C: mTLS (Mutual TLS)

mTLS uses the same server-side TLS configuration (Option A or B), plus requires client certificates.

**1. Configure server-side TLS** using Option A or B above.

**2. Generate client certificates:**

```bash
# Generate client key and CSR
openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=dbclient" -out client.csr

# Sign client certificate with the same CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out client.crt -days 365
```

**3. Configure the database to require client certificates:**

```bash
# MySQL: create user requiring X509
kubectl exec -it <pod> -n <ns> -- mysql -u root -p --ssl -e \
  "CREATE USER 'secureuser'@'%' REQUIRE X509; GRANT ALL ON *.* TO 'secureuser'@'%';"

# PostgreSQL: edit pg_hba.conf to require clientcert=verify-full
# This is typically handled via parameter reconfiguration
```

## Step 3: Verify TLS Connection

### Check TLS is Enabled

```bash
# MySQL
kubectl exec -it <pod> -n <ns> -- mysql -u root -p --ssl -e "SHOW VARIABLES LIKE '%ssl%';"

# PostgreSQL
kubectl exec -it <pod> -n <ns> -- psql -U postgres -c "SHOW ssl;"
```

### Connect with TLS from Outside

```bash
# MySQL with TLS
mysql -h <host> -P 3306 -u root -p --ssl-mode=REQUIRED \
  --ssl-ca=ca.crt --ssl-cert=client.crt --ssl-key=client.key

# PostgreSQL with TLS
psql "host=<host> port=5432 user=postgres sslmode=verify-full sslrootcert=ca.crt sslcert=client.crt sslkey=client.key"
```

### Verify Certificate Details

```bash
# Check the mounted certificates in the pod
kubectl exec -it <pod> -n <ns> -- ls -la /var/run/secrets/tls/

# View certificate info
kubectl exec -it <pod> -n <ns> -- openssl x509 -in /var/run/secrets/tls/tls.crt -text -noout
```

## Troubleshooting

**TLS not enabling (pods crashing):**
- Check cert-manager is running (for built-in mode)
- Verify the TLS Secret exists and has correct keys: `kubectl describe secret <cluster>-tls -n <ns>`
- Check pod logs: `kubectl logs <pod> -n <ns>`

**Certificate expired:**
- Built-in mode: cert-manager handles renewal automatically
- User-provided: regenerate certificates and update the Secret

**Client cannot connect with TLS:**
- Verify the CA certificate matches: client's `ca.crt` must match the server's CA
- Check SAN (Subject Alternative Names) in the server certificate

## Additional Resources

For engine-specific TLS configuration details, full certificate generation workflows with SANs, and troubleshooting matrix, see [reference.md](references/reference.md).

For general agent safety conventions (dry-run, status confirmation, production protection), see [safety-patterns.md](../../references/safety-patterns.md).

