diff --git a/crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs b/crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs index 1e233333ed2..670fe44481a 100644 --- a/crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs +++ b/crates/common/tedge_config/src/tedge_config_cli/tedge_config.rs @@ -351,9 +351,9 @@ define_tedge_config! { #[tedge_config(reader(private))] url: ConnectUrl, - /// The path where Cumulocity root certificate(s) are stared - #[tedge_config(note = "The value can be a directory path as well as the path of the direct certificate file.")] - #[tedge_config(example = "/etc/tedge/az-trusted-root-certificates.pem", default(variable = "DEFAULT_ROOT_CERT_PATH"))] + /// The path where Cumulocity root certificate(s) are stored + #[tedge_config(note = "The value can be a directory path as well as the path of the certificate file.")] + #[tedge_config(example = "/etc/tedge/c8y-trusted-root-certificates.pem", default(variable = "DEFAULT_ROOT_CERT_PATH"))] #[doku(as = "PathBuf")] root_cert_path: Utf8PathBuf, @@ -420,12 +420,12 @@ define_tedge_config! { port: u16, }, - /// The file that will be used as a the server certificate for the Cumulocity proxy + /// The file that will be used as the server certificate for the Cumulocity proxy #[tedge_config(example = "/etc/tedge/device-certs/c8y_proxy_certificate.pem")] #[doku(as = "PathBuf")] cert_path: Utf8PathBuf, - /// The file that will be used as a the server private key for the Cumulocity proxy + /// The file that will be used as the server private key for the Cumulocity proxy #[tedge_config(example = "/etc/tedge/device-certs/c8y_proxy_key.pem")] #[doku(as = "PathBuf")] key_path: Utf8PathBuf, @@ -459,8 +459,8 @@ define_tedge_config! { #[tedge_config(example = "myazure.azure-devices.net")] url: ConnectUrl, - /// The path where Azure IoT root certificate(s) are stared - #[tedge_config(note = "The value can be a directory path as well as the path of the direct certificate file.")] + /// The path where Azure IoT root certificate(s) are stored + #[tedge_config(note = "The value can be a directory path as well as the path of the certificate file.")] #[tedge_config(example = "/etc/tedge/az-trusted-root-certificates.pem", default(variable = "DEFAULT_ROOT_CERT_PATH"))] #[doku(as = "PathBuf")] root_cert_path: Utf8PathBuf, @@ -489,8 +489,8 @@ define_tedge_config! { #[tedge_config(example = "your-endpoint.amazonaws.com")] url: ConnectUrl, - /// The path where AWS IoT root certificate(s) are stared - #[tedge_config(note = "The value can be a directory path as well as the path of the direct certificate file.")] + /// The path where AWS IoT root certificate(s) are stored + #[tedge_config(note = "The value can be a directory path as well as the path of the certificate file.")] #[tedge_config(example = "/etc/tedge/aws-trusted-root-certificates.pem", default(variable = "DEFAULT_ROOT_CERT_PATH"))] #[doku(as = "PathBuf")] root_cert_path: Utf8PathBuf, @@ -652,12 +652,12 @@ define_tedge_config! { }, }, - /// The file that will be used as a the server certificate for the File Transfer Service + /// The file that will be used as the server certificate for the File Transfer Service #[tedge_config(example = "/etc/tedge/device-certs/file_transfer_certificate.pem")] #[doku(as = "PathBuf")] cert_path: Utf8PathBuf, - /// The file that will be used as a the server private key for the File Transfer Service + /// The file that will be used as the server private key for the File Transfer Service #[tedge_config(example = "/etc/tedge/device-certs/file_transfer_key.pem")] #[doku(as = "PathBuf")] key_path: Utf8PathBuf, diff --git a/docs/src/operate/security/add_self_signed_trusted.md b/docs/src/operate/security/add_self_signed_trusted.md deleted file mode 100644 index 802d81b6177..00000000000 --- a/docs/src/operate/security/add_self_signed_trusted.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Self-signed Device Certificate -tags: [Operate, Security] -sidebar_position: 1 ---- - -# How to add self-signed certificate to trusted certificates list - -## Overview - -If the server you are trying to connect `thin-edge.io` to is presenting a certificate with a root that is not currently trusted, then you can add the server's root certificate to the list of trusted root certificates. -For the most part the store will be filled with certificates from your TLS/SSL provider, but when you want to use self-signed certificates you may need to update your local certificate store. - -Below are instructions on how to add new CA certificate and update the certificate store. - -:::note -Provided instructions are for supported OSes and may not apply to the flavour you are running, -if you need help with other OS please consult appropriate documentation. -::: - -## Debian/Ubuntu/RaspberryPi OS - -If you do not have the `ca-certificates` package installed on your system, install it with your package manager. - -```sh -sudo apt install ca-certificates -``` - -To add a self-signed certificate to the trusted certificate repository on thin-edge.io system: - -Create a `/usr/local/share/ca-certificates/` directory if it does not exist on your computer: - -```sh -sudo mkdir /usr/local/share/ca-certificates/ -``` - -The directory should be owned by `root:root` and have `755` permissions set for it. The certificates files should be `644`. - -Copy your root certificate (in `PEM` format with `.crt` extension) to the created directory: - -```sh -sudo cp /usr/local/share/ca-certificates/ -``` - -Install the certificates: - -```sh -sudo update-ca-certificates -``` - -```text title="Output" -Updating certificates in /etc/ssl/certs... -1 added, 0 removed; done. -Running hooks in /etc/ca-certificates/update.d... -done. -``` - -Check the certificate was correctly installed: - -```sh -ls /etc/ssl/certs | grep -``` - -Additionally you can check correctness of the installed certificate: - -```sh -cat /etc/ssl/certs/ca-certificates.crt | grep -f -``` diff --git a/docs/src/operate/security/cloud_authentication.md b/docs/src/operate/security/cloud_authentication.md new file mode 100644 index 00000000000..f804f94fdf2 --- /dev/null +++ b/docs/src/operate/security/cloud_authentication.md @@ -0,0 +1,92 @@ +--- +title: Cloud Authentication +tags: [Operate, Security] +sidebar_position: 3 +--- + +When thin-edge connects a cloud, the cloud endpoint is authenticated using X.509 certificates. +For that to work, the signing certificate of the cloud certificate must be trusted by the device. +Usually, these certificates are stored in `/etc/ssl/certs` and nothing specific has to done on the device. + +A specific configuration will be required only for cloud endpoints which CA is not trusted by the device OS default setting. + +## Configuration + +Several `tedge config` settings are used by thin-edge to locate the signing certificate of the cloud endpoint. + +- `c8y.root_cert_path` The path where Cumulocity IoT root certificate(s) are stored (MQTT) +- `c8y.proxy.ca_path` The path where Cumulocity IoT root certificate(s) are stored (HTTP) +- `aws.root_cert_path` The path where AWS IoT root certificate(s) are stored (MQTT). +- `az.root_cert_path` The path where Azure IoT root certificate(s) are stored (MQTT). + +All these paths can point to a directory where the trusted certificates are stored +as well as directly to file containing the certificate of the authority signing the cloud endpoint certificate. +Per default, all these paths are set to the system default: `/etc/ssl/certs`. + +## Adding a Root Certificate + +If the server you are trying to connect `thin-edge.io` to is presenting a certificate with a root that is not currently trusted, +then you can add the server's root certificate to the list of trusted root certificates. +For the most part the store will be filled with certificates from your TLS/SSL provider, +but if this is not the case you may need to update your local certificate store. + +:::note +Updating the local certificate store is notably required to connect Cumulocity IoT Edge, +as this distribution of Cumulocity uses self-signed certificates to authenticate itself. +::: + +Below are instructions on how to add new CA certificate and update the certificate store. + +:::note +Provided instructions are for supported OSes and may not apply to the flavour you are running, +if you need help with other OS please consult appropriate documentation. +::: + +### Debian/Ubuntu/RaspberryPi OS + +If you do not have the `ca-certificates` package installed on your system, install it with your package manager. + +```sh +sudo apt install ca-certificates +``` + +To add a self-signed certificate to the trusted certificate repository on thin-edge.io system: + +Create a `/usr/local/share/ca-certificates/` directory if it does not exist on your computer: + +```sh +sudo mkdir /usr/local/share/ca-certificates/ +``` + +The directory should be owned by `root:root` and have `755` permissions set for it. The certificates files should be `644`. + +Copy your root certificate (in `PEM` format with `.crt` extension) to the created directory: + +```sh +sudo cp /usr/local/share/ca-certificates/ +``` + +Install the certificates: + +```sh +sudo update-ca-certificates +``` + +```text title="Output" +Updating certificates in /etc/ssl/certs... +1 added, 0 removed; done. +Running hooks in /etc/ca-certificates/update.d... +done. +``` + +Check the certificate was correctly installed: + +```sh +ls /etc/ssl/certs | grep +``` + +Additionally, you can check correctness of the installed certificate: + +```sh +cat /etc/ssl/certs/ca-certificates.crt | grep -f +``` diff --git a/docs/src/operate/security/connect_external_device.md b/docs/src/operate/security/connect_external_device.md deleted file mode 100644 index 7ab1b956658..00000000000 --- a/docs/src/operate/security/connect_external_device.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Local Connection -tags: [Operate, Connection, MQTT] -sidebar_position: 1 ---- - -# Connecting an external device - -With `thin-edge.io` you can enable connection for external devices to your `thin-edge.io` enabled device with the use of a few commands. - -## Configuration - -External devices connection can be setup by using the `tedge` cli tool making some changes to the configuration. - -The following configurations option are available for you if you want to add an external listener to thin-edge.io: - -|Property|Description| -|--------|-----------| -|`mqtt.external.bind.port`|Mqtt broker port, which is used by the external mqtt clients to publish or subscribe. Example: 8883| -|`mqtt.external.bind.address`|IP address / hostname, which the mqtt broker limits incoming connections on. Example: 0.0.0.0| -|`mqtt.external.bind.interface`|Name of network interface, which the mqtt broker limits incoming connections on. Example: wlan0| -|`mqtt.external.ca_path`|Path to a file containing the PEM encoded CA certificates that are trusted when checking incoming client certificates. Example: /etc/ssl/certs| -|`mqtt.external.cert_file`|Path to the certificate file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-certificate.pem| -|`mqtt.external.key_file`|Path to the private key file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-private-key.pem| - -:::note -If none of these options is set, then no external listener is set. -If one of these options is set, then default values are inferred by the MQTT server (Mosquitto). -For instance, the port defaults to 1883 for a non-TLS listener, and to 8883 for a TLS listener. -::: - -These settings can be considered in 2 groups, listener configuration and TLS configuration. - -### Configure basic listener - -To configure basic listener you should provide port and/or bind address which will use default interface. -To change the default interface you can use mqtt.external.bind.interface configuration option. - -To set them you can use `tedge config` as follows: - -```sh -sudo tedge config set mqtt.external.bind.port 8883 -``` - -To allow connections from all IP addresses on the interface: - -```sh -sudo tedge config set mqtt.external.bind.address "0.0.0.0" -``` - -### Configure TLS on the listener - -To configure the external listener with TLS additional settings are available: - -* `mqtt.external.ca_path` -* `mqtt.external.cert_file` -* `mqtt.external.key_file` - -To enable MQTT over TLS, a server side certificate must be configured using the 2 following settings: - -```sh -sudo tedge config set mqtt.external.cert_file /etc/tedge/server-certs/tedge-certificate.pem -sudo tedge config set mqtt.external.key_file /etc/tedge/server-certs/tedge-private-key.pem -``` - -To fully enable TLS authentication clients, client side certificate validation can be enabled: - -```sh -sudo tedge config set mqtt.external.ca_path /etc/ssl/certs -``` - -:::note -When these 3 mqtt settings are configured then client certificates will be required to connect thin-edge. -::: - -## Additional information - -* Currently, only one additional listener can be defined diff --git a/docs/src/operate/security/device-certificate.md b/docs/src/operate/security/device-certificate.md new file mode 100644 index 00000000000..5f8ff63d913 --- /dev/null +++ b/docs/src/operate/security/device-certificate.md @@ -0,0 +1,80 @@ +--- +title: Device Certificate Setting +tags: [Operate, Security, Cloud] +sidebar_position: 2 +--- + +## Obtaining a Device Certificate + +Obtaining a Device Certificate is a quite involved process: +- A private key and a certificate signing request has to be created on the device +- The certificate signing request is sent to the Certificate Authority (CA) chosen by the tenant for its fleet of devices +- The CA checks that the device issuing the signing request is actually allowed to connect the tenant +- The CA signs the signing request sending back the resulting certificate to the device +- The tenant adds the signing certificate of the CA to its trusted list of certificate + +There are numerous variations notably on the contract between the tenant and the CA, +the chain of signing certificates and the checks to be performed before approving a signing request. +However, the outcome of the certificate signing process is always the same. +It consists in three files: +- The device private key - generated by the device and which must be kept secret as this the proof of ownership +- The device certificate - signed by the CA and shared by the device on-demand +- The signing certificate - the certificate used by the CA to sign the certificate and by the tenant to check device certificates + +## Installing a Device Certificate + +The device certificate must be installed on the gateway device, +i.e. on the same box as the MQTT broker establishing the MQTT connection to the cloud over a bridge. + +```text title="ls -lh /etc/mosquitto/certs" +-r-------- 1 mosquitto root 1679 oct. 21 2022 demo-device-007.key +-r--r--r-- 1 mosquitto root 2095 oct. 21 2022 demo-device-007.pem +``` + +Note that *only* the MQTT broker should be able to read or write the private key, while the certificate itself is public. + +Then thin-edge must be told where the certificate is stored. +Note that the device certificate file must contain not only the device certificate itself +but also the signing certificate +(so the cloud endpoint can check the chain, starting from a trusted root upto the device certificate). + +```sh +# Create a new cert chain, which contains both the signing and device public cert +cat signing-cert.pem > demo-device-007.chain.pem +cat demo-device-007.pem >> demo-device-007.chain.pem + +# Configure the cert chain file as the main cert to be used by thin-edge.io +tedge config set device.cert_path /etc/mosquitto/certs/demo-device-007.chain.pem +tedge config set device.key_path /etc/mosquitto/certs/demo-device-007.key +``` + +The `tedge cert show` command can be used to look at the content of the certificate. + +```text title="tedge cert show"" +Device certificate: /etc/mosquitto/certs/demo-device-007.chain.pem +Subject: O=Thin-Edge, OU=t398942, CN=demo-device-007 +Issuer: C=DE, O=Software AG, CN=QA Thin-Edge CA G1 +Valid from: Tue, 09 Nov 2021 14:38:41 +0000 +Valid up to: Sat, 09 Nov 2024 14:38:41 +0000 +Thumbprint: 1E0F9A074E6FE67A43EE948335E42EB729CB3974 +``` + +## Cloud tenant setting + +The last point is to make the cloud tenant trust the device certificate. +For that the certificate of the issuer - .i.e. "QA Thin-Edge CA G1" in the example case, +must be added to the list of trusted signing certificate. + +This process is cloud dependent. +See the respective documentation of the cloud you're trying to connect to for details on how to add a new signing certificate: +- [Cumulocity IoT: Managing trusted certificates](https://cumulocity.com/guides/users-guide/device-management/#managing-trusted-certificates) +- [Understand how Azure IoT Edge uses certificates](https://learn.microsoft.com/en-us/azure/iot-edge/iot-edge-certs) +- [AWS IoT: X.509 client certificates](https://docs.aws.amazon.com/iot/latest/developerguide/x509-client-certs.html) + +:::note +The command `tedge cert upload` is of no help here. + +Indeed, the device does not have a copy of the signing certificate of the CA. +This certificate is given by the CA to the tenant owner or the device operator +in the context of the signing process. +::: diff --git a/docs/src/operate/security/https_configuration.md b/docs/src/operate/security/https_configuration.md new file mode 100644 index 00000000000..6a7a610b7f4 --- /dev/null +++ b/docs/src/operate/security/https_configuration.md @@ -0,0 +1,411 @@ +--- +title: HTTPS Configuration +tags: [Operate, Security, HTTP] +sidebar_position: 6 +--- + +Thin-edge provides two services over HTTP: +- The [File Transfer Service](../../references/tedge-file-transfer-service.md) is used by the mappers and the child devices to transfer files locally. +- The [Cumulocity Proxy](../../references/tedge-cumulocity-proxy.md) acts as a local proxy to the Cumulocity IoT REST API. + +Three levels of security are supported: + +1. HTTP without any client authentication (default) +2. HTTPS with server authentication +3. HTTPS with server and client authentication + + +## Default HTTP Setting + +### File Transfer Service + +The **tedge-agent** running on the main device acts as a local HTTP server +which is the mappers and the child devices to transfer files locally. +Any local process can PUT and GET files there: + +```sh +echo "Hello thin-edge.io" >/tmp/foo.txt +curl -X PUT -F 'file=@/tmp/foo.txt' http://localhost:8000/tedge/file-transfer/foo.txt +curl http://localhost:8000/tedge/file-transfer/foo.txt +``` + +### Cumulocity Proxy + +When a device is successfully connected to Cumulocity IoT, +**tedge-mapper** acts as a proxy to the Cumulocity IoT REST API. +For instance, the following lists the managed objects related to the device: + +```sh +curl http://localhost:8001/c8y/inventory/managedObjects +``` + +:::note +The connection from the Cumulocity Proxy to Cumulocity IoT is always established over HTTPS, +whatever the settings for local connections. + +The identity of the Cumulocity end-point is authenticated using the +root certificates configured with `tedge config get c8y.proxy.ca_path` and the device itself +is authenticated using JWT tokens retrieved from Cumulocity IoT via MQTT. +::: + +## Open HTTP services on the local network + +Per default, the File Transfer Service and Cumulocity Proxy are only available on `localhost`, +the loopback network interface of the main device. +To open these services to child devices, their *bind* addresses must be set explicitly. + +### File Transfer Service + +On the __main device__, two `tedge config` settings define the binding address and port of the File Transfer Service: + +- `http.bind.address` The bind address of the File Transfer Service HTTP server +- `http.bind.port` The port number of the File Transfer Service HTTP server + +On a __child device__, two `tedge config` settings define how to connect the File Transfer Service: + +- `http.client.host` The address or hostname of the main device where the File Transfer Service HTTP server is running +- `http.client.port` The port number on main device on which the File Transfer Service HTTP server is running + +For instance, assuming a main device named `rpi4-dca632efb150` with `192.168.1.6` as IP address, +one has first to configure and restart *tedge-agent* of the main device: + +```sh title="main device" +sudo tedge config set http.bind.address 192.168.1.6 +sudo systemctl restart tedge-agent +``` + +and then, on the child device, *tedge-agent* needs to be configured to use the File Transfer Service of the main device: + +```sh title="child device" +sudo tedge config set http.client.host rpi4-dca632efb150 +sudo systemctl restart tedge-agent +``` + +Any process running on a child device can also use the File Transfer Service: + +```sh title="child device" +echo "Hello thin-edge.io" >/tmp/foo.txt +curl -X PUT -F 'file=@/tmp/foo.txt' http://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +curl http://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +``` + +:::note +The firewall of the main device has also to be configured +to accept incoming requests on the port used by the File Transfer Service (`8000` per default) +::: + +### Cumulocity Proxy + +As for the File Transfer Service, the Cumulocity Proxy is configured using four settings, +two to be used by the Cumulocity **tedge-mapper**, and two used by its clients +(mainly the **tedge-agent**, running on the main device or a child devices). + +- `c8y.proxy.bind.address` The IP address local Cumulocity HTTP proxy binds to +- `c8y.proxy.bind.port` The port local Cumulocity HTTP proxy binds to +- `c8y.proxy.client.host` The address of the host on which the local Cumulocity HTTP Proxy is running +- `c8y.proxy.client.port` The port number on the remote host on which the local Cumulocity HTTP Proxy is running + +For instance, assuming a main device named `rpi4-dca632efb150` with `192.168.1.6` as IP address, +one has first to configure and restart *tedge-mapper-c8y*: + +```sh title="device running tedge-mapper-c8y" +sudo tedge config set c8y.proxy.bind.address 192.168.1.6 +sudo systemctl restart tedge-mapper-c8y +``` + +and then, on all the devices, *tedge-agent* needs to be configured to connect the Cumulocity HTTP Proxy: + +```sh title="main and child device" +sudo tedge config set c8y.proxy.client.host rpi4-dca632efb150 +sudo systemctl restart tedge-agent +``` + +Any process running on a child device can also use the Cumulocity HTTP Proxy: + +```sh title="main and child device" +curl http://rpi4-dca632efb150:8001/c8y/inventory/managedObjects +``` + +:::note +The firewall of the box running the Cumumocity mapper has also to be configured +to accept incoming requests on the port used by the Cumulocity HTTP Proxy (`8001` per default) +::: + +## Enable HTTPS + +The next step is to enable HTTPS, the clients authenticating the servers. + +For that, one needs two certificates: +- one for the main **tedge-agent** running the File Transfer Service +- another for the Cumulocity **tedge-mapper** running the Cumulocity HTTP Proxy. + +These two certificates have also to be trusted by the clients, i.e. the child devices. +Hence, the signing certificate will have to be added to the list of trusted root certificates on each child device. + +### Generating Certificates + +Thin-edge currently provides no specific tool to generate and deploy certificates over child devices. + +You can use the following script to generate all the required certificates. + +First, one needs a signing key that will be used to sign the certificates of the **tedge-agent** and **tedge-mapper**: + +```sh +DEVICE=$(tedge config get device.id) + +## Signing certificate +openssl req \ + -new \ + -x509 \ + -days 100 \ + -extensions v3_ca \ + -nodes \ + -subj "/O=thin-edge/OU=$DEVICE/CN=tedge-ca" \ + -keyout tedge-local-ca.key \ + -out tedge-local-ca.crt +``` + +This signing certificate has to be trusted by the main device as well as all the child devices: + +```sh title="on the main as well as the child devices" +cp tedge-local-ca.crt /usr/local/share/ca-certificates +sudo update-ca-certificates +``` + +One can then proceed with a certificate for the **tedge-agent** of the main device: + +```sh +## main agent private key +openssl genrsa -out main-agent.key 2048 + +## main agent certificate signing request +openssl req -out main-agent.csr \ + -key main-agent.key \ + -subj "/O=thin-edge/OU=$DEVICE/SN=main-agent/CN=localhost" \ + -new + +## signing the main agent certificate +cat > v3.ext << EOF +authorityKeyIdentifier=keyid +basicConstraints=CA:FALSE +keyUsage = digitalSignature, keyAgreement +extendedKeyUsage = serverAuth, clientAuth +subjectAltName=DNS:$(hostname),DNS:localhost +EOF + +openssl x509 -req \ + -in main-agent.csr \ + -CA tedge-local-ca.crt \ + -CAkey tedge-local-ca.key \ + -extfile v3.ext \ + -CAcreateserial \ + -out main-agent.crt \ + -days 100 +``` + +:::note +Note that the hostname used as `subjectAltName` must be the hostname used by the clients to client to connect **tedge-agent**. +If you want to connect **tedge-agent** using its IP address, say `192.168.1.6`, +then the `subjectAltName` must be set to `subjectAltName=IP:192.168.1.6`. +::: + +And another one for the **tedge-mapper**: + +```sh +## mapper private key +openssl genrsa -out c8y-mapper.key 2048 + +## mapper certificate signing request +openssl req -out c8y-mapper.csr -key c8y-mapper.key \ + -subj "/O=thin-edge/OU=$DEVICE/SN=c8y-mapper/CN=localhost" \ + -new + +## signing the mapper certificate +cat > v3.ext << EOF +authorityKeyIdentifier=keyid +basicConstraints=CA:FALSE +keyUsage = digitalSignature, keyAgreement +extendedKeyUsage = serverAuth, clientAuth +subjectAltName=DNS:$(hostname),DNS:localhost +EOF + +openssl x509 -req \ + -in c8y-mapper.csr \ + -CA tedge-local-ca.crt \ + -CAkey tedge-local-ca.key \ + -extfile v3.ext \ + -CAcreateserial \ + -out c8y-mapper.crt \ + -days 100 +``` + +### File Transfer Service + +Two `tedge config` settings enable HTTPS for the File Transfer Service of the main device. + +- `http.cert_path` The file that will be used as the server certificate for the File Transfer Service. +- `http.key_path` The file that will be used as the server private key for the File Transfer Service. + +Assuming the main device certificate is stored in `/etc/tedge/device-local-certs`, +one simply has to set these settings and to restart the **tedge-agent** to enable HTTPS: + +```sh title="main device" +sudo tedge config set http.cert_path /etc/tedge/device-local-certs/main-agent.crt +sudo tedge config set http.key_path /etc/tedge/device-local-certs/main-agent.key +sudo systemctl restart tedge-agent +``` + +Nothing has to be done on the child devices (except trusting the signing certificate). +And file transfer is now available over HTTPS: + +```sh title="child device" +echo "Hello thin-edge.io" >/tmp/foo.txt +curl -X PUT -F 'file=@/tmp/foo.txt' https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +curl https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +``` + +### Cumulocity Proxy + +Two `tedge config` settings enable HTTPS for the Cumulocity Proxy. + +- `c8y.proxy.cert_path` The file that will be used as the server certificate for the Cumulocity proxy. +- `c8y.proxy.key_path` The file that will be used as the server private key for the Cumulocity proxy. + +Assuming the main device certificate is stored in `/etc/tedge/device-local-certs`, +one simply has to set these settings and to restart the **tedge-mapper** to enable HTTPS: + +```sh title="on the box running c8y mapper" +tedge config set c8y.proxy.cert_path /etc/tedge/device-local-certs/c8y-mapper.crt +tedge config set c8y.proxy.key_path /etc/tedge/device-local-certs/c8y-mapper.key +sudo systemctl restart tedge-mapper-c8y +``` + +Nothing has to be done on the child devices (except trusting the signing certificate). +And the Cumulocity proxy is now available over HTTPS: + +```sh title="child device" +echo "Hello thin-edge.io" >/tmp/foo.txt +curl -X PUT -F 'file=@/tmp/foo.txt' https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +curl https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +``` + +```sh title="main and child device" +curl https://rpi4-dca632efb150:8001/c8y/inventory/managedObjects +``` + +## Enable HTTPS client authentication + +The final step is to enforce certificate-based authentication to the clients connecting +the File Transfer Service and the Cumulocity Proxy. + +### Generating Certificates + +Each child device must be given a certificate. +The simpler is to use the same signing key as for the servers. This is not mandatory though. + +```sh title="on each child device" +## child device private key +openssl genrsa -out tedge-client.key 2048 + +## child device certificate signing request +openssl req -out tedge-client.csr \ + -key tedge-client.key \ + -subj "/O=thin-edge/OU=$DEVICE/SN=child/CN=tedge-client" \ + -new +``` + +The certificate signing request (CSR) has to be signed on the box where the signing key is stored. + +```sh title="on the laptop owning the signing key" +## signing the child device certificate +cat > client-v3.ext << EOF +basicConstraints=CA:FALSE +extendedKeyUsage = clientAuth +EOF + +openssl x509 -req \ + -in tedge-client.csr \ + -CA tedge-local-ca.crt \ + -CAkey tedge-local-ca.key \ + -extfile client-v3.ext \ + -CAcreateserial \ + -out tedge-client.crt \ + -days 100 +``` + +The resulting certificate can then be copied and used on the child device. + +### File Transfer Service + +A single `tedge config` setting enables client authentication (once HTTPS is already enabled). + +- `http.ca_path` Path to a directory containing the PEM encoded CA certificates that are trusted + when checking incoming client certificates for the File Transfer Service. + +Assuming the signing certificate used for the child device has been properly added to `/etc/ssl/certs`, +one simply has to set `http.ca_path` and to restart the **tedge-agent** to enforce client authentication: + +```sh title="main device" +sudo tedge config set http.ca_path /etc/ssl/certs +sudo systemctl restart tedge-agent +``` + +Clients have then to authenticate themselves using a certificate trusted by the main **tedge-agent**: + +```sh title="child device" +echo "Hello thin-edge.io" >/tmp/foo.txt +curl --cert /etc/tedge/device-local-certs/tedge-client.crt \ + --key /etc/tedge/device-local-certs/tedge-client.key \ + -X PUT -F 'file=@/tmp/foo.txt' \ + https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +curl --cert /etc/tedge/device-local-certs/tedge-client.crt \ + --key /etc/tedge/device-local-certs/tedge-client.key \ + https://rpi4-dca632efb150:8000/tedge/file-transfer/foo.txt +``` + +Notably, **tedge-agent** must be updated on each child device, +using the following `tedge config` settings: + +- `http.client.auth.cert_file` Path to the certificate which is used by the agent when connecting to external services +- `http.client.auth.key_file` Path to the private key which is used by the agent when connecting to external services + +```sh title="child device" +sudo tedge config set http.client.auth.cert_file /etc/tedge/device-local-certs/tedge-client.crt +sudo tedge config set http.client.auth.key_file /etc/tedge/device-local-certs/tedge-client.key +sudo systemctl restart tedge-agent +``` + +### Cumulocity Proxy + +A single `tedge config` setting enables client authentication (once HTTPS is already enabled). + +- `c8y.proxy.ca_path` Path to a file containing the PEM encoded CA certificates that are trusted + when checking incoming client certificates for the Cumulocity Proxy. + +Assuming the signing certificate used for the child device has been properly added to `/etc/ssl/certs`, +one simply has to set `c8y.proxy.ca_pathh` and to restart the **tedge-mapper** to enforce client authentication: + +```sh title="on the box running tedge-mapper" +sudo tedge config set c8y.proxy.ca_path /etc/ssl/certs +sudo systemctl restart tedge-mapper-c8y +``` + +Clients have then to authenticate themselves using a certificate trusted by the main **tedge-mapper**: + +```sh title="child device" +curl --cert /etc/tedge/device-local-certs/tedge-client.crt \ + --key /etc/tedge/device-local-certs/tedge-client.key \ + https://rpi4-dca632efb150:8001/c8y/inventory/managedObjects +``` + +Notably, **tedge-agent** must be updated on the main device and all the child devices, +using the following `tedge config` settings: + +- `http.client.auth.cert_file` Path to the certificate which is used by the agent when connecting to external services +- `http.client.auth.key_file` Path to the private key which is used by the agent when connecting to external services + +```sh title="main device as well as child devices" +sudo tedge config set http.client.auth.cert_file /etc/tedge/device-local-certs/tedge-client.crt +sudo tedge config set http.client.auth.key_file /etc/tedge/device-local-certs/tedge-client.key +sudo systemctl restart tedge-agent +``` diff --git a/docs/src/operate/security/index.md b/docs/src/operate/security/index.md index 6bea1511b2c..57866b950af 100644 --- a/docs/src/operate/security/index.md +++ b/docs/src/operate/security/index.md @@ -6,6 +6,22 @@ sidebar_position: 1 import DocCardList from '@theme/DocCardList'; -How to configure thin-edge and its dependencies to control access on thin-edge devices. +Thin-edge uses X.509 certificates as the key mechanism to authenticate peers. +- The MQTT connection between the gateway device and the cloud is established over TLS + and uses certificates to authenticate the device on the cloud, as well as to authenticate the cloud on the device. +- The local MQTT connections, from the miscellaneous services and child devices to the local MQTT broker, + can also be configured to be established over TLS. In the stronger setting, the clients have to authenticate themselves using certificates. +- The local HTTP services (namely the [File Transfer Service](../../references/tedge-file-transfer-service.md) and the [Cumulocity Proxy](../../references/tedge-cumulocity-proxy.md)) + can be configured to use HTTPS. As for MQTT, certificate-based authentication of the clients can also be enforced. + +A complete setting requires numerous private keys, certificates and trust chains. +Nothing really complex, but this requires rigorous settings. +It is therefore recommended to set things up step by step. +- The only mandatory step is to configure the authentication between the gateway device and the cloud. + - This can be done using a [self-signed device certificate](self_signed_device_certificate.md) or a proper [CA-signed certificate](device-certificate.md). + - Most of the time the cloud certificate will be trusted out-of-the-box, + but a [self-signed cloud certificate](cloud_authentication.md) will need specific care. +- The second step is to enable TLS on the local MQTT and HTTP connections. +- The final step is to enforce certificate-based client authentication on the local MQTT and HTTP connections. diff --git a/docs/src/operate/security/mqtt_local_broker_authentication.md b/docs/src/operate/security/mqtt_tls_configuration.md similarity index 66% rename from docs/src/operate/security/mqtt_local_broker_authentication.md rename to docs/src/operate/security/mqtt_tls_configuration.md index 786eaefc6c7..c09799e5acf 100644 --- a/docs/src/operate/security/mqtt_local_broker_authentication.md +++ b/docs/src/operate/security/mqtt_tls_configuration.md @@ -1,11 +1,9 @@ --- -title: MQTT Authentication +title: MQTT TLS Configuration tags: [Operate, Security, MQTT] -sidebar_position: 1 +sidebar_position: 5 --- -# Use MQTT authentication for local broker - thin-edge.io supports certificate-based authentication when communicating with an MQTT broker. Three levels of security are supported: @@ -13,6 +11,66 @@ an MQTT broker. Three levels of security are supported: 2. Server authentication 3. Server + client authentication +## MQTT Configuration + +The `tedge config` command provides MQTT specific settings +to open to the child devices the MQTT broker running on the gateway device. + +|Property|Description| +|--------|-----------| +|`mqtt.external.bind.port`|Mqtt broker port, which is used by the external mqtt clients to publish or subscribe. Example: 8883| +|`mqtt.external.bind.address`|IP address / hostname, which the mqtt broker limits incoming connections on. Example: 0.0.0.0| +|`mqtt.external.bind.interface`|Name of network interface, which the mqtt broker limits incoming connections on. Example: wlan0| +|`mqtt.external.ca_path`|Path to a file containing the PEM encoded CA certificates that are trusted when checking incoming client certificates. Example: /etc/ssl/certs| +|`mqtt.external.cert_file`|Path to the certificate file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-certificate.pem| +|`mqtt.external.key_file`|Path to the private key file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-private-key.pem| + +:::note +If none of these options is set, then no external listener is set. +If one of these options is set, then default values are inferred by the MQTT server (Mosquitto). +For instance, the port defaults to 1883 for a non-TLS listener, and to 8883 for a TLS listener. +::: + +These settings can be considered in 2 groups, listener configuration and TLS configuration. + +### Configure basic listener + +To configure basic listener you should provide port and/or bind address which will use default interface. +To change the default interface you can use mqtt.external.bind.interface configuration option. + +To set them you can use `tedge config` as follows: + +```sh +sudo tedge config set mqtt.external.bind.port 8883 +``` + +To allow connections from all IP addresses on the interface: + +```sh +sudo tedge config set mqtt.external.bind.address "0.0.0.0" +``` + +### Configure TLS on the listener + +To configure the external listener with TLS additional settings are available: + +* `mqtt.external.ca_path` +* `mqtt.external.cert_file` +* `mqtt.external.key_file` + +To enable MQTT over TLS, a server side certificate must be configured using the 2 following settings: + +```sh +sudo tedge config set mqtt.external.cert_file /etc/tedge/server-certs/tedge-certificate.pem +sudo tedge config set mqtt.external.key_file /etc/tedge/server-certs/tedge-private-key.pem +``` + +To fully enable TLS authentication clients, client side certificate validation can be enabled: + +```sh +sudo tedge config set mqtt.external.ca_path /etc/ssl/certs +``` + ## Server authentication Enabling server authentication causes thin-edge.io MQTT clients to require a diff --git a/docs/src/operate/security/registration.md b/docs/src/operate/security/self_signed_device_certificate.md similarity index 65% rename from docs/src/operate/security/registration.md rename to docs/src/operate/security/self_signed_device_certificate.md index cde49186614..9377bdbeb77 100644 --- a/docs/src/operate/security/registration.md +++ b/docs/src/operate/security/self_signed_device_certificate.md @@ -1,14 +1,17 @@ --- -title: Cloud Authentication +title: Self-signed Device Certificate tags: [Operate, Security, Cloud] sidebar_position: 1 --- -# How to register? +Using a self-signed device certificate is the simplest way to connect a thin-edge device to the cloud. +This is a secure method even if more adapted for testing purposes. +Indeed, the self-signed certificates must be trusted individually by the cloud tenant, +raising managing issues when there are more than a few devices. ## Create self-signed certificate -To create new certificate you can use [`tedge cert create`](../../references/cli/tedge-cert.md) thin-edge.io command: +To create a new certificate you can use [`tedge cert create`](../../references/cli/tedge-cert.md) thin-edge.io command: ```sh sudo tedge cert create --device-id alpha @@ -22,7 +25,7 @@ Certificate was successfully created `tedge cert` requires `sudo` privilege. This command provides no output on success. ::: -[`sudo tedge cert create`](../../references/cli/tedge-cert.md) will create certificate in a default location (`/etc/tedge/device-certs/`). +[`sudo tedge cert create`](../../references/cli/tedge-cert.md) creates the certificate in a default location (`/etc/tedge/device-certs/`). To use a custom location, refer to [`tedge config`](../../references/cli/tedge-config.md). Now you should have a certificate in the `/etc/tedge/device-certs/` directory. @@ -37,6 +40,27 @@ total 8 -r-------- 1 mosquitto mosquitto 246 May 31 09:26 tedge-private-key.pem ``` +## Make the cloud trust the device self-signed certificate + +For the cloud to trust the device certificate, +the signing certificate must be added to the trusted list of signing certificate of the cloud tenant. + +The certificate created with `tedge cert create` being self-signed, one needs to add the device certificate itself to the trusted list. + +How this is done depends on the cloud. In the specific case of Cumulocity, this can be done using the `tedge` cli. + +One has first to set the Cumulocity end-point: + +```sh +tedge config set c8y.url +``` + +And then upload the signing certificate: + +```sh +tedge cert upload c8y --user +``` + ## Renew self-signed certificate To renew the expired certificate you can use [`tedge cert renew`](../../references/cli/tedge-cert.md) thin-edge.io command: