# Mutual TLS (mTLS)

## What is Mutual TLS?

### Standard TLS vs Mutual TLS

**Standard TLS (One-Way Authentication):**

* Client verifies server's certificate
* Server does not verify client's identity
* Client can be anonymous
* Common for public web services

**Mutual TLS (Two-Way Authentication):**

* Client verifies server's certificate
* Server verifies client's certificate
* Both parties prove their identity
* Used in high-security environments

### Benefits of Mutual TLS

* **Strong Authentication**: Cryptographic proof of client identity
* **Access Control**: Only clients with valid certificates can connect
* **Zero Trust**: Doesn't rely on network-level security (IP allowlists, VPNs)
* **Non-Repudiation**: Client identity is cryptographically verified

## When to Use Mutual TLS

Consider using mTLS when:

* You need to restrict which clients can send data to the collector
* Compliance requires two-way authentication
* You're in a zero-trust security environment
* You want to authenticate clients by certificate rather than IP address
* You need cryptographic proof of client identity for audit purposes

{% hint style="info" %}
**mTLS vs IP Allowlisting**

While IP allowlisting can restrict access by network location, mTLS provides stronger authentication that travels with the client, regardless of network location. This is especially valuable in cloud and containerized environments where IP addresses are dynamic.
{% endhint %}

## mTLS Configuration Options

Bindplane collectors provide two parameters for client certificate verification with different behaviors:

### Option 1: `ca_file` (Opportunistic Client Verification)

```yaml
receivers:
  tcplog:
    listen_address: "0.0.0.0:10514"
    tls:
      cert_file: /path/to/server-fullchain.crt
      key_file: /path/to/server.key
      ca_file: /path/to/client-ca.crt  # Verifies clients IF they present a cert
      min_version: "1.2"
```

**Behavior:**

* Client certificates are **optional**
* If a client presents a certificate, it will be verified against the CA
* Clients without certificates can still connect
* Useful for mixed environments (some authenticated, some not)

{% hint style="info" %}
**Technical Details**

This sets the `RootCAs` trust pool but does not enforce client certificate requirements. See the [OTel configtls documentation](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configtls/README.md) for details on the underlying `tls.Config` mapping.
{% endhint %}

### Option 2: `client_ca_file` (Required Client Verification)

```yaml
receivers:
  tcplog:
    listen_address: "0.0.0.0:10514"
    tls:
      cert_file: /path/to/server-fullchain.crt
      key_file: /path/to/server.key
      client_ca_file: /path/to/client-ca.crt  # Requires and verifies client certs
      client_ca_file_reload: true
      min_version: "1.2"
```

**Behavior:**

* Client certificates are **required**
* Connections without valid client certificates are rejected
* Sets Go's `ClientAuth` to `RequireAndVerifyClientCert`
* Supports automatic reloading with `client_ca_file_reload`
* **This is the recommended approach for enforcing mTLS**

{% hint style="success" %}
**Recommended for mTLS**

Use `client_ca_file` when you want to enforce mutual TLS. This ensures that all clients must present valid certificates.
{% endhint %}

### Comparison Table

| Feature               | `ca_file`                 | `client_ca_file`                   |
| --------------------- | ------------------------- | ---------------------------------- |
| Client cert required  | No (optional)             | Yes (enforced)                     |
| Clients without certs | Allowed                   | Rejected                           |
| Auto-reload support   | No                        | Yes (with `client_ca_file_reload`) |
| Use case              | Mixed environments        | Strict mTLS                        |
| ClientAuth mode       | `VerifyClientCertIfGiven` | `RequireAndVerifyClientCert`       |

## Setting Up mTLS Certificates

### Server Side (Collector)

You'll need:

1. **Server certificate and key** (same as basic TLS)
   * `cert_file`: Server certificate (can include full chain)
   * `key_file`: Server private key (must be unencrypted)
2. **Client CA certificate(s)** to verify client certificates
   * `client_ca_file`: CA certificate(s) that signed the client certificates
   * Can contain multiple CA certificates (concatenated PEM)

### Client Side

Each client needs:

1. **Client certificate** signed by the CA trusted by the server
2. **Client private key** (must be unencrypted if using OpenTelemetry clients)
3. **Server CA certificate(s)** to verify the collector's certificate

{% hint style="warning" %}
**Certificate Authority Trust**

The CA used to sign client certificates does NOT need to be the same CA that signed the server certificate. You can use different CAs for server and client certificates, as long as each side trusts the appropriate CA.
{% endhint %}

### PKI Infrastructure Considerations

For production mTLS deployments:

* Use your organization's PKI infrastructure to issue certificates
* Implement certificate lifecycle management (issuance, renewal, revocation)
* Consider using different intermediate CAs for server and client certificates
* Plan for certificate rotation and revocation

For testing, see [Generating Test Certificates](https://docs.bindplane.com/how-to-guides/security-and-tls/reference/certificate-conversion#generating-test-certificates).

## Complete mTLS Configuration Examples

### TCP Receiver with mTLS

```yaml
receivers:
  tcplog:
    listen_address: "0.0.0.0:10514"
    tls:
      # Server certificate (what collector presents to clients)
      cert_file: /etc/collector/certs/server-fullchain.crt
      key_file: /etc/collector/certs/server.key

      # Client verification (enforces mTLS)
      client_ca_file: /etc/collector/certs/client-ca.crt
      client_ca_file_reload: true  # Auto-reload when CA file changes

      # Security settings
      min_version: "1.2"
```

### Syslog Receiver with mTLS

```yaml
receivers:
  syslog:
    protocol: rfc5424
    tcp:
      listen_address: "0.0.0.0:6514"
      tls:
        # Server certificate
        cert_file: /etc/collector/certs/server-fullchain.crt
        key_file: /etc/collector/certs/server.key

        # Client verification
        client_ca_file: /etc/collector/certs/client-ca.crt
        client_ca_file_reload: true

        # Security settings
        min_version: "1.2"
```

### Production mTLS with Security Hardening

```yaml
receivers:
  tcplog:
    listen_address: "0.0.0.0:10514"
    tls:
      # Server certificate
      cert_file: /etc/collector/certs/server-fullchain.crt
      key_file: /etc/collector/certs/server.key

      # Client verification
      client_ca_file: /etc/collector/certs/client-ca.crt
      client_ca_file_reload: true

      # Security hardening
      min_version: "1.2"
      cipher_suites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

      # Certificate rotation
      reload_interval: 24h
```

## Configuring mTLS in the Bindplane UI

{% hint style="info" %}
**Important:** There is **no separate "Enable mTLS" checkbox** in the UI for most receivers. mTLS is enabled by providing a CA certificate file.
{% endhint %}

### Step-by-Step UI Configuration

1. Navigate to your source configuration (e.g., TCP or Syslog source)
2. Expand the **Advanced** section
3. Check **"Enable TLS"**
4. Configure server certificate:
   * **TLS Certificate Path**: `/path/to/server-fullchain.crt`
   * **TLS Private Key Path**: `/path/to/server.key`
5. Configure client verification (this enables mTLS):
   * **Client CA File**: `/path/to/client-ca.crt`
6. Optional: Set **TLS Min Version** to "1.2" or higher

### UI Field Mapping

| Bindplane UI Field   | YAML Parameter   | Purpose                      |
| -------------------- | ---------------- | ---------------------------- |
| Enable TLS           | `tls:` block     | Enables TLS configuration    |
| TLS Certificate Path | `cert_file`      | Server certificate           |
| TLS Private Key Path | `key_file`       | Server private key           |
| CA File              | `ca_file`        | Optional client verification |
| **Client CA File**   | `client_ca_file` | **Enforced mTLS**            |
| TLS Min Version      | `min_version`    | Minimum TLS version          |

## Testing mTLS Connections

### Test with Valid Client Certificate

{% tabs %}
{% tab title="Linux/macOS" %}

```bash
openssl s_client -connect collector.example.com:10514 \
  -cert client.crt \
  -key client.key \
  -CAfile server-ca.crt
```

{% endtab %}

{% tab title="Windows PowerShell" %}

```powershell
openssl s_client -connect collector.example.com:10514 `
  -cert client.crt `
  -key client.key `
  -CAfile server-ca.crt
```

{% endtab %}
{% endtabs %}

**Expected result:**

* Connection succeeds
* Handshake completes
* `Verify return code: 0 (ok)` or appropriate verification result

### Test Rejection of Unauthorized Clients

When using `client_ca_file`, test that connections without client certificates are rejected:

{% tabs %}
{% tab title="Linux/macOS" %}

```bash
# This should fail with "certificate required" error
openssl s_client -connect collector.example.com:10514
```

{% endtab %}

{% tab title="Windows PowerShell" %}

```powershell
# This should fail with "certificate required" error
openssl s_client -connect collector.example.com:10514
```

{% endtab %}
{% endtabs %}

**Expected result:**

* Connection rejected
* Error message: "certificate required" or "handshake failure"

### Verify Client Certificate Details

{% tabs %}
{% tab title="Linux/macOS" %}

```bash
# View client certificate information
openssl x509 -in client.crt -text -noout

# Verify client certificate is signed by the CA
openssl verify -CAfile client-ca.crt client.crt
# Should output: client.crt: OK
```

{% endtab %}

{% tab title="Windows PowerShell" %}

```powershell
# View client certificate information
openssl x509 -in client.crt -text -noout

# Verify client certificate is signed by the CA
openssl verify -CAfile client-ca.crt client.crt
# Should output: client.crt: OK
```

{% endtab %}
{% endtabs %}

For more testing commands, see [Testing and Verification](https://docs.bindplane.com/how-to-guides/security-and-tls/using-tls/reference/testing-verification).

## mTLS Troubleshooting

### Issue: Client Certificate Required Errors

**Symptoms:**

* Clients receive "certificate required" or "handshake failure" errors
* Connections are rejected during TLS handshake

**Cause:** Client is not presenting a valid certificate when `client_ca_file` is configured.

**Solution:**

1. Verify the client is presenting a certificate:
2. Ensure the client certificate is signed by the CA specified in `client_ca_file`:
3. Check that the client certificate hasn't expired:

### Issue: Client Certificate Verification Fails

**Symptoms:**

* Client presents a certificate but connection is still rejected
* Error: "bad certificate" or "unknown ca"

**Cause:** Client CA file doesn't match the CA that signed the client certificate.

**Solution:**

1. Check that `client_ca_file` contains the CA that signed the client certificate
2. If using intermediate CAs, ensure the full chain is included
3. Verify the certificate chain:

### Issue: Connections Accepted Without Client Certificates

**Symptoms:**

* Clients without certificates can still connect
* mTLS is not being enforced

**Cause:** Using `ca_file` instead of `client_ca_file`.

**Solution:**

1. Verify you're using `client_ca_file` (not just `ca_file`)
2. `ca_file` alone does not enforce mTLS - it only provides optional verification
3. `client_ca_file` sets `ClientAuth` to `RequireAndVerifyClientCert`

**Correct configuration:**

```yaml
tls:
  cert_file: /path/to/server.crt
  key_file: /path/to/server.key
  client_ca_file: /path/to/client-ca.crt  # Use this, not ca_file
```

### Issue: Client CA Changes Not Taking Effect

**Cause:** Not using `client_ca_file_reload` or collector needs restart.

**Solution:**

Enable automatic CA file reloading:

```yaml
tls:
  client_ca_file: /path/to/client-ca.crt
  client_ca_file_reload: true  # Auto-reload on file change
```

Or restart the collector after updating the CA file.
