# Client Certificates

Mutual Transport Layer Security (mTLS) with client certificates provides enhanced security for MQTT connections to Connectware by eliminating the need for traditional username/password authentication. This approach uses X.509 client certificates for public-key authentication, reducing security risks during the authentication process.

Connectware uses a truststore file (`cybus_ca.crt`) to determine which Certificate Authorities (CAs) it trusts for mTLS authentication.

{% hint style="info" %}
Connectware supports TLS up to version 1.2.
{% endhint %}

## Setting Up Client Certificates

To access MQTT using mTLS with Connectware, the following steps are required:

1. Choose the authentication method for MQTT, either username and password or certificate based authentication.
2. Generate a Certificate Signing Request and private key for the client device.
3. Sign the CSR with your custom Certificate Authority to create the final client certificate.
4. Add the custom CA or certificate chain to the Connectware truststore file `cybus_ca.crt`.
5. Configure certificate based authentication in Connectware by creating a user whose Common Name matches the client certificate.

{% hint style="info" %}
All certificate and key files must be in PEM format.
{% endhint %}

**Learn More About**

* [Server Certificates](https://docs.cybus.io/2-0-6/documentation/security/tls-certificates/server-certificates)
* [Using Mutual Transport Layer Security (mTLS) for agents with the connectware-agent Helm chart](https://docs.cybus.io/2-0-6/documentation/agents/agents-in-kubernetes/configuring-agents-with-the-connectware-agent-helm-chart/using-mutual-transport-layer-security-mtls-for-agents-with-the-connectware-agent-helm-chart)
* [X.509](https://en.wikipedia.org/wiki/X.509)
* [OpenSSL PKI](https://pki-tutorial.readthedocs.io/en/latest/)
* [OpenSSL](https://www.openssl.org/)

### 1. Choosing Your Authentication Method

Connectware provides the following authentication methods for the message broker:

* **Default authentication**: Utilizes username and password credentials. This method is compatible with:
  * Unencrypted connections over port 1883
  * Encrypted connections over port 8883 (TLS)
* **Alternative authentication**: Certificate-based mutual TLS authentication (mTLS)

When using mTLS, the following changes take effect:

* Clients that want to authenticate using mTLS must present valid client certificates when connecting to MQTTS on port 8883.
* Connectware will extract the certificate's Common Name (CN) for user identification.
* The extracted CN must match an existing Connectware user configured for certificate-based authentication (grant type).
* A connection will only be established if both the certificate is validated and the associated user is successfully authenticated.

{% hint style="warning" %}
You must choose either username/password or certificate-based authentication - they cannot operate simultaneously.
{% endhint %}

### 2. Generating a Certificate Signing Request (CSR)

We recommend implementing your own Public Key Infrastructure (PKI) to issue and manage client certificates for Connectware authentication.

**Prerequisites**

* Access to your organization's Certificate Authority (CA) infrastructure
* The ability to sign certificate requests with your CA or Intermediate CA
* Basic understanding of OpenSSL commands

**Procedure**

To generate the CSR, proceed as follows:

1. Generate a private key for your device:

{% code lineNumbers="true" %}

```bash
openssl genrsa -out anymachine-key.pem 2048
```

{% endcode %}

2. Download the `openssl-client-cert.conf` sample file from [GitHub](https://github.com/cybusio/tutorial-how-to-use-client-certificates-for-mqtt-over-tls-with-connectware/blob/main/resources/openssl-client-cert.conf).
3. Open the `openssl-client-cert.conf` file and modify the following settings:

{% code lineNumbers="true" %}

```bash
COMMON_NAME = device001
ORGNAME = Smart Factory Inc.
```

{% endcode %}

3. Create the CSR using your configuration and key:

{% code lineNumbers="true" %}

```bash
openssl req -new \
-config openssl-client-cert.conf \
-key anymachine-key.pem \
-out anymachine.csr
```

{% endcode %}

You can also create both the private key and the CSR at the same time via `-keyout`:

{% code lineNumbers="true" %}

```bash
openssl req -new \
-config openssl-client-cert.conf \
-keyout anymachine-key.pem \
-out anymachine.csr
```

{% endcode %}

4. Verify your CSR:

{% code lineNumbers="true" %}

```bash
openssl req -in anymachine.csr -noout -text -nameopt sep_multiline
```

{% endcode %}

The important fields to verify include:

{% code lineNumbers="true" %}

```bash
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=DE
            O=Smart Factory Inc.
            CN=device001
```

{% endcode %}

### 3. Signing the CSR with Your Custom CA

A manual or automated process for signing certificates with a company Root CA or Intermediate CA is up to the customer.

In this tutorial, we assume the availability of a custom CA key-pair or a corresponding Intermediate CA key-pair eligible to sign certificate requests.

**Example:** For testing purposes, you can use an example root CA configuration to generate a new self-signed root CA. Download the `openssl-root-ca-example.conf` sample file from [GitHub](https://github.com/cybusio/tutorial-how-to-use-client-certificates-for-mqtt-over-tls-with-connectware/blob/main/resources/openssl-root-ca-example.conf).

1. Create a CSR for the device that you want to connect to Connectware.
2. Sign the CSR with your custom CA:

{% code lineNumbers="true" %}

```bash
openssl x509 -req -in anymachine.csr -days 100 \
-CA custom_ca.crt \
-CAkey custom_ca.key \
-set_serial 01 > anymachine.crt
```

{% endcode %}

This produces the signed certificate valid 100 days with the following output:

{% code lineNumbers="true" %}

```bash
Signature ok
subject=/C=DE/O=Smart Factory Inc./CN=device001
Getting CA Private Key
```

{% endcode %}

3. Inspect the signed certificate to verify its details. The output should confirm that the issuer matches your custom CA and that the subject corresponds to the device or machine identity you provided.

{% code lineNumbers="true" %}

```bash
openssl x509 -in anymachine.crt -text -noout
```

{% endcode %}

**Result**: Once properly configured, your custom-signed client certificates will function with Connectware without requiring container restarts.

### 4. Add a Custom CA to the cybus\_ca.crt Truststore

To allow Connectware to authenticate clients using this certificate, the custom CA certificate (or full certificate chain) must be trusted by Connectware.

1. Add your CA chain to the Connectware truststore (cybus\_ca.crt). You can retrieve this file from your Connectware instance and then add your custom CA:

{% code lineNumbers="true" %}

```bash
cat custom_ca.crt >> cybus_ca.crt
```

{% endcode %}

2. To verify the trust chain locally before deploying:

{% code lineNumbers="true" %}

```bash
openssl verify -CAfile cybus_ca.crt cybus_client.crt custom_client.crt
```

{% endcode %}

Expected output:

{% code lineNumbers="true" %}

```bash
cybus_client.crt: OK
custom_client.crt: OK
```

{% endcode %}

### 5. Configuring Certificate-Based Authentication

After generating client certificates, you must configure Connectware to recognize and authorize connections using these certificates:

1. For certificate authentication to work, the Common Name (CN) in your client certificate must exactly match a username in Connectware that has been configured with the certificate grant type.
2. Create a user in Connectware with the same name as the CN in your client certificate:

{% code lineNumbers="true" %}

```bash
curl -k --location --request POST 'https://localhost/api/users' \
--header 'Authorization: Bearer eyJzdWI...
--data-raw '{
    "username": "device001",
    "identityProvider": "local",
    "grantTypes": [ { "method": "certificate", "isRequired": false } ],
    "roles": [ "cfb72c04-e4a8-11eb-92a8-0242ac1e0006" ]
}'
```

{% endcode %}

3. Assign appropriate access roles to this certificate-authenticated user. For testing, you can use the `connectware-admin` role. For production environments, follow the principle of least privilege with more restricted roles.
4. To find the correct `connectware-admin` role ID for your environment, use the following GET request:

{% code lineNumbers="true" %}

```bash
https://localhost/api/roles?name[eq]=connectware-admin
```

{% endcode %}

**Result**: Once properly configured, clients connecting via mTLS with a certificate containing `CN=device001` will authenticate successfully, provided the certificate was signed by a CA in the trusted `cybus_ca.crt` chain.

**Learn More About**

* [Adding Individual Permissions to Users](https://docs.cybus.io/2-0-6/user-management/users#adding-individual-permissions-to-users)

## Verifying the mTLS Configuration

{% tabs %}
{% tab title="Kubernetes" %}

### Verifying the mTLS Configuration (Kubernetes)

To confirm that mTLS is configured correctly for Connectware, do the following:

1. In the [Admin UI](https://docs.cybus.io/2-0-6/getting-started/admin-ui), select **User** > **User Management**, and select the **admin** user.
2. In the **Edit User** dialog, enable **Advanced Mode**.
3. Enable **Certificate** and click **Update**.
4. Download the certificate files from the Connectware pod using kubectl. The following commands will extract the `cybus_ca.crt`, `cybus_client.crt`, and `cybus_client.key` files from the `/connectware_certs` directory in the system-control-server pod to your current local directory.

{% code lineNumbers="true" %}

```bash
kubectl cp $(kubectl get pod -lapp=system-control-server -o name | sed -e 's/pod\///g'):/connectware_certs/cybus_ca.crt cybus_ca.crt
kubectl cp $(kubectl get pod -lapp=system-control-server -o name | sed -e 's/pod\///g'):/connectware_certs/cybus_client.crt cybus_client.crt
kubectl cp $(kubectl get pod -lapp=system-control-server -o name | sed -e 's/pod\///g'):/connectware_certs/cybus_client.key cybus_client.key
```

{% endcode %}

6. Use the `cybus_client` key pair with `CN=admin`.
7. Connect to an MQTT client on port 8883 using the CA file (`cybus_ca.crt`) and the `cybus_client` key pair.
8. Use an MQTT client like `mosquitto_sub` to check for successful connection.

{% code lineNumbers="true" %}

```bash
mosquitto_sub \
--cert cybus_client.crt \
--key cybus_client.key \
--cafile cybus_ca.crt \
-h localhost -p 8883 -t '#' -d
```

{% endcode %}
{% endtab %}

{% tab title="Docker" %}

### Verifying the mTLS Configuration (Docker)

To confirm that mTLS is configured correctly for Connectware, do the following:

1. In the [Admin UI](https://docs.cybus.io/2-0-6/getting-started/admin-ui), select **User** > **User Management**, and select the **admin** user.
2. In the **Edit User** dialog, enable **Advanced Mode**.
3. Enable **Certificate** and click **Update**.
4. Download the `cybus_client.key` and `cybus_client.crt` files, located in the `/connectware_certs` Docker volume.
5. To extract the `cybus_client.*` files, use the [extract script](https://github.com/cybusio/tutorial-how-to-use-client-certificates-for-mqtt-over-tls-with-connectware/blob/main/tools/extract_certs-from_connectware.sh), which uses `docker cp` to copy files from a running container.
6. Use the `cybus_client` key pair with `CN=admin`.
7. Connect to an MQTT client on port 8883 using the CA file (`cybus_ca.crt`) and the `cybus_client` key pair.
8. Use an MQTT client like `mosquitto_sub` to check for successful connection.

{% code lineNumbers="true" %}

```bash
mosquitto_sub \
--cert cybus_client.crt \
--key cybus_client.key \
--cafile cybus_ca.crt \
-h localhost -p 8883 -t '#' -d
```

{% endcode %}
{% endtab %}
{% endtabs %}

### mTLS Example Output

**Successful connection**

{% code lineNumbers="true" %}

```bash
Client mosq-wcdbhQtb5lkGOBMIbi sending CONNECT
Client mosq-wcdbhQtb5lkGOBMIbi received CONNACK (0)
Client mosq-wcdbhQtb5lkGOBMIbi sending SUBSCRIBE (Mid: 1, Topic: #, QoS: 0, Options: 0x00)
Client mosq-wcdbhQtb5lkGOBMIbi received SUBACK
Subscribed (mid: 1): 0
```

{% endcode %}

**TLS handshake failure**

{% code lineNumbers="true" %}

```bash
Client mosq-wcdbhQtb5lkGOBMIbi sending CONNECT
OpenSSL Error[0]: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
Error: A TLS error occurred.
```

{% endcode %}

**Backend authorization failure**

{% code lineNumbers="true" %}

```bash
Client mosq-wcdbhQtb5lkGOBMIbi sending CONNECT
Client mosq-wcdbhQtb5lkGOBMIbi  received CONNACK (5)
Connection error: Connection Refused: not authorised.
Client mosq-wcdbhQtb5lkGOBMIbi  sending DISCONNECT
```

{% endcode %}

## Revoking Access for Clients with Custom CA Certificates

* To revoke all client certificates issued by a particular custom CA, remove the custom CA entries from the `cybus_ca.crt` file.

This will block further access from any certificate issued by that CA without needing to restart Connectware.
