# Authentication Using Signed Certificates Using client-specific certificates, signed by a common authority (even if self-signed) provides a highly secure way of authenticating mqtt clients. Often used with IoT devices where a unique certificate can be initialized on initial provisioning. With so many options, X509 certificates can be daunting to create with `openssl`. Included are command line utilities to generate a root self-signed certificate and then the proper broker and device certificates with the correct X509 attributes to enable authenticity. ### Quick start Generate a self-signed root credentials and server credentials: ```shell $ ca_creds --country US --state NY --locality NY --org-name "My Org's Name" --cn "my.domain.name" $ server_creds --country US --org-name "My Org's Name" --cn "my.domain.name" ``` !!! warning "Security of private keys" Your root credential private key and your server key should *never* be shared with anyone. The certificates -- specifically the root CA certificate -- is completely safe to share and will need to be shared along with device credentials when using a self-signed CA. Include in your server config: ```yaml listeners: ssl-mqtt: bind: "127.0.0.1:8883" ssl: true certfile: server.crt keyfile: server.key cafile: ca.crt plugins: amqtt.contrib.cert.CertificateAuthPlugin: uri_domain: my.domain.name ``` Generate a device's credentials: ```shell $ device_creds --country US --org-name "My Org's Name" --device-id myUniqueDeviceId --uri my.domain.name ``` And use these to initialize the `MQTTClient`: ```python import asyncio from amqtt.client import MQTTClient client_config = { 'keyfile': 'myUniqueDeviceId.key', 'certfile': 'myUniqueDeviceId.crt', 'broker': { 'cafile': 'ca.crt' } } async def main(): client = MQTTClient(config=client_config) await client.connect("mqtts://my.domain.name:8883") # publish messages or subscribe to receive asyncio.run(main()) ``` ## Background Often used for IoT devices, this method provides the most secure form of identification. A root certificate, often referenced as a CA certificate -- either issued by a known authority (such as LetsEncrypt) or a self-signed certificate) is used to sign a private key and certificate for the server. Each device/client also gets a unique private key and certificate signed by the same CA certificate; also included in the device certificate is a 'SAN' or SubjectAlternativeName which is the device's unique identifier. Since both server and device certificates are signed by the same CA certificate, the client can verify the server's authenticity; and the server can verify the client's authenticity. And since the device's certificate contains a x509 SAN, the server (with this plugin) can identify the device securely. !!! note "URI and Client ID configuration" `uri_domain` configuration must be set to the same uri used to generate the device credentials when a device is connecting with private key and certificate, the `client_id` must match the device id used to generate the device credentials. Available ore three scripts to help with the key generation and certificate signing: `ca_creds`, `server_creds` and `device_creds`. !!! note "Configuring broker & client for using Self-signed root CA" If using self-signed root credentials, the `cafile` configuration for both broker and client need to be configured with `cafile` set to the `ca.crt`. ## Root & Certificate Credentials The process for generating a server's private key and certificate is only done once. If you have a private key & certificate -- such as one from verifying your webserver's domain with LetsEncrypt -- that you want to use, pass them to the `server_creds` cli. If you'd like to use a self-signed certificate, generate your own CA by running the `ca_creds` cli (make sure your client is configured with `check_hostname` as `False`). ```mermaid --- config: theme: redux --- flowchart LR subgraph ca_cred["ca_cred #40;cli#41; or other CA"] ca["ca key & cert"] end subgraph server_cred["server_cred fl°°40¶ßclifl°°41¶ß"] scsr("certificate signing
request fl°°40¶ßCSRfl°°41¶ß with
SAN of DNS & IP Address") spk["private key"] ssi["sign csr"] end spk -.-> skc["server key & cert"] ca_cred --> ssi spk --> scsr con["country, org
& common name"] --> scsr scsr --> ssi ssi --> skc ``` ## Device credentials For each device, create a device id to generate a device-specific private key and certificate using the `device_creds` cli. Use the same CA as was used for the server (above) so the client & server recognize each other. ```mermaid --- config: theme: redux --- flowchart LR subgraph ca_cred["ca_cred #40;cli#41; or other CA"] ca["ca key & cert"] end subgraph device_cred["device_cred fl°°40¶ßclifl°°41¶ß"] ccsr("certificate signing
request fl°°40¶ßCSRfl°°41¶ß with
SAN of URI & DNS") cpk["private key"] csi["sign csr"] end cpk --> ccsr csi --> ckc[device key & cert] cpk -.-> ckc ccsr --> csi ca_cred --> csi con["country, org
common name
& device id"] --> ccsr ``` ## Configuration ::: amqtt.contrib.cert.UserAuthCertPlugin.Config options: show_source: false heading_level: 4 extra: class_style: "simple" ## Key and Certificate Generation ::: mkdocs-typer2 :module: amqtt.scripts.ca_creds :name: ca_creds ::: mkdocs-typer2 :module: amqtt.scripts.server_creds :name: server_creds ::: mkdocs-typer2 :module: amqtt.scripts.device_creds :name: device_creds