Hono: Auto-Provisioning of Gateways

Created on 27 Oct 2020  路  17Comments  路  Source: eclipse/hono

There're two patterns in Hono how devices can be registered on-the-fly.

1) For devices directly connected to Hono adapters auto-provisoning is done based on X.509 certificates.
2) For devices connected via gateways to Hono adapters, so called implicit device registration (see #2053 ) will be provided.

I want to ask you, if the combination of these two patterns is possible for complete on-the-fly registration of the gateways and devices communicating via these gateways. I.e. there's an edge gateway configured with X.509 certificate for authentication and it's necessary to provision this gateway as well as the edge devices communicating via this gateway on-the-fly.
Meaning the gateway sends on behalf of the edge device one telemetry or event message, firstly the gateway and its credentials will be registered in Device Registry (x.509 cert and device-id provided by the gateway), after that the request will be sent to Ditto to create digital twin for this gateway. Secondly, the edge device for which the gateway trying to send a message is implicitly registered as it is implemented in #2053.

@b-abel @fkaltner @sophokles73 could you please provide your opinion, thoughts to this topic?

Most helpful comment

After discussing with @b-abel it turned out there's also a security aspect to consider:

If we would not separate between devices and gateways by the suggested _create-devices-as-gateways_ flag (meaning we would just use a tenant-wide flag) an attacker gaining access to the credentials of any _normal_ device could use those credentials not only to "impersonate" a _normal_ device but also to "impersonate" a gateway and create new devices (ab)using the auto-provisioning feature of gateways.

In case we will have the _create-devices-as-gateways_ flag the attacker could not turn any device into a gateway using its credentials only, since the "auto-provisioning-enabled" is not present on the hijacked device. So the scope of the attack would be more limited which is also in favour of that proposal from my point of view.

All 17 comments

I already had a similar idea a couple of months ago, see: https://github.com/eclipse/hono/issues/2053#issuecomment-668609655

After a short chat with @b-abel we came to the following suggestion:
In general it should be possible to combine both approaches, the main challenge is the authorisation:

  1. Auto-provisioning of gateways via client certificates is only allowed if the tenant has the corresponding flag set.
  2. Currently auto-provisioning of edge devices will only be allowed if the gateway has the "auto-provisioning-enabled" authority set in its device registration.

We could solve this by taking the tenant flag also into consideration when auto-provisioning edge devices (2), meaning it will "override" the gateway's authority / be a replacement for it.

@alinaserg & @sophokles73 WDYT?

Thanks @fkaltner for the proposal, additional question regarding replacement of gateways' authority. See below 3 use cases how auto-provisioning can be activated:

Activating auto-provisioning:

  1. Devices connected directly to Hono protocol adapters -> enabling auto-provisioning on tenant level for CA cert.
  2. Devices connected via gateways to Hono protocol adapters, gateways don't use client certificates -> enabling auto-provisioning on gateway level by setting "auto-provisioning-enabled" authority during device registration.
  3. Devices connected via gateways to Hono protocol adapters, gateways use client certificates -> enabling auto-provisioning on tenant level for CA cert -> replace the gateway's authority

The replacement of the gateway's authority will be done only in case, if gateways use client certificates.

@e-grigorov In the current Hono implementation of device auto-provisioning the device-id is generated in Hono Device Registry.
As far as I understood in case of gateways auto-provisioning the device-id of the gateway will be provided from the gateway.
Is it correct?

I see one more open point in the gateway auto-provisioning topic for Ditto, namely using of gateway's policies as a template for creation of digital twins. As gateways will be registered on-the-fly, there won't be policies templates pre-configured for these gateways.
I would like to address this point to @thjaeckle @jokraehe

@e-grigorov In the current Hono implementation of device auto-provisioning the device-id is generated in Hono Device Registry.
As far as I understood in case of gateways auto-provisioning the device-id of the gateway will be provided from the gateway.
Is it correct?

Actually, the device identifier is so called namespaced i.e. it's built by \:\. I guess that \ part can be read from the device certificate. The question is how to reach the namespace. There are a few options:

  • manual - the user can be requested to do it
  • automated - the gateway and the hub can exchange it

Is it possible to implement the automated option?

To share some more background here. Currently, the gateway is using this provisioning info:

  • MQTT Adapter URL
  • deviceId - used in the Ditto payloads (namespaced id)
  • tenantId - used in Hono MQTT topics
  • policyId
  • credentials

Is it possible to exchange (between Hub and the gateway) these provisioning properties? In the best case, the user can just configure the MQTT Adapter URL and the device certificate. Everything else can be automatically exchanged.

We could solve this by taking the tenant flag also into consideration when auto-provisioning edge devices (2), meaning it will "override" the gateway's authority / be a replacement for it.

Not sure if this is sufficient. Currently, we only allow gateway devices to implicitly register devices connected via the gateway. If we now want to automatically register the gateway device itself, how do we know that it is a gateway device and should thus be entitled to register other devices implicitly? So far, we make this distinction by means of having a device manager explicitly enabling the property on a device, thus turning it into a gateway. Without such explicit configuration being required, we would effectively allow all devices to act as a gateway. But maybe that is not a problem and is in fact the way we should go?
WDYT? @fkaltner @calohmn

Without such explicit configuration being required, we would effectively allow all devices to act as a gateway. But maybe that is not a problem and is in fact the way we should go?

FMPOV the tenant-wide option to enable/disable auto-provisioning is sufficient, having an additional option per gateway adds not much practical value but increases the complexity significantly.

@e-grigorov regarding automatic exchange of provisioning properties.
My understanding was that even by initial communication between gateway and protocol adapter, the gateway acts on behalf of edge devices and doesn't send messages on its own. Is it correct?
If yes, then the gateway should provide device-id of the edge device, on behalf of which the gateway is acting. Meaning the gateway knows already before initial communication with protocol adapter device-id and its namespace and includes it in mqtt-message and in the ditto-payload as you mentioned. In this case the provisioning properties can't be provided from Hono or Ditto.

If by initial communication between gateway and protocol adapter the gateway acts on its own, meaning gateway sends an initial message as a device directly connected to Hono protocol adapter, in this case we could talk about possibility to provide provisioning properties after the gateway is registered in Hono and Ditto.

How initial communication will look like?

@b-abel @calohmn @sophokles73 any concerns, suggestions about it?

IMHO we could add a boolean property, e.g. create-devices-as-gateways, to trust anchors. Setting this property to true would then cause any devices that are being auto-provisioned for that trust anchor to also have their auto-provisioning-enabled property (as introduced in #2094) set to true. That way we would not need to turn all devices of a tenant into gateways but only those that are being auto-provisioned using a specific trust anchor. You could then also use multiple trust anchors to partition the devices of a tenant into gateways and normal devices. WDYT? @fkaltner @b-abel @calohmn

IMHO we could add a boolean property, e.g. _create-devices-as-gateways_, to trust anchors. Setting this property to true would then cause any devices that are being auto-provisioned for that trust anchor to also have their _auto-provisioning-enabled_ property (as introduced in #2094) set to true. That way we would not need to turn _all_ devices of a tenant into gateways but only those that are being auto-provisioned using a specific trust anchor. You could then also use multiple trust anchors to partition the devices of a tenant into gateways and _normal_ devices. WDYT? @fkaltner @b-abel @calohmn

This makes sense to me. I missed that the certificate-based auto-provisioning is also used for _normal_ devices (by the way is there a wording for it? I tend to call it "edge device" contrasting it to "gateway"). Consequently, in order not to have to use separate tenants for separating between gateways and normal devices, this is a sound proposal in my eyes.

After discussing with @b-abel it turned out there's also a security aspect to consider:

If we would not separate between devices and gateways by the suggested _create-devices-as-gateways_ flag (meaning we would just use a tenant-wide flag) an attacker gaining access to the credentials of any _normal_ device could use those credentials not only to "impersonate" a _normal_ device but also to "impersonate" a gateway and create new devices (ab)using the auto-provisioning feature of gateways.

In case we will have the _create-devices-as-gateways_ flag the attacker could not turn any device into a gateway using its credentials only, since the "auto-provisioning-enabled" is not present on the hijacked device. So the scope of the attack would be more limited which is also in favour of that proposal from my point of view.

IMHO we could add a boolean property, e.g. _create-devices-as-gateways_, to trust anchors. Setting this property to true would then cause any devices that are being auto-provisioned for that trust anchor to also have their _auto-provisioning-enabled_ property (as introduced in #2094) set to true. That way we would not need to turn _all_ devices of a tenant into gateways but only those that are being auto-provisioned using a specific trust anchor. You could then also use multiple trust anchors to partition the devices of a tenant into gateways and _normal_ devices.

Note to avoid confusion: there is already a boolean property _auto-provisioning-enabled_ on the trust anchor, #2094 adds a property with the same name to the device registration data.

So, a tenant configuration could look like this (only relevant properties) when fully partitioned:

{
  "tenant-id" : "TEST_TENANT",
  "trusted-ca": [{
    "subject-dn": "CN=ca,OU=device-provisioning,O=Eclipse",
    "auto-provisioning-enabled": true,
    "create-devices-as-gateways": false,
  }, {
    "subject-dn": "CN=ca,OU=gateway-provisioning,O=Eclipse",
    "auto-provisioning-enabled": true,
    "create-devices-as-gateways": true,
  }, {
    "subject-dn": "CN=ca,OU=normal-devices,O=Eclipse",
    "auto-provisioning-enabled": false,
    "create-devices-as-gateways": false,
  }, {
    "subject-dn": "CN=ca,OU=works-like-normal-devices,O=Eclipse",
    "auto-provisioning-enabled": false,
    "create-devices-as-gateways": true,
  }]
}

_Device registration data_ for devices that are auto-provisioned with trust anchor "CN=ca,OU=gateway-provisioning,O=Eclipse" would then have the property auto-provisioning-enabled set to true, devices that are auto-provisioned with trust anchor "CN=ca,OU=device-provisioning,O=Eclipse" would have property auto-provisioning-enabled set to false.

In the case of all three flags: a missing flag is considered as false.

This makes total sense to me.

Sorry, @sophokles73, I just reiterated what you said, but it helped me to get the full picture and might help others too.

Actually, the device identifier is so called namespaced i.e. it's built by :. I guess that part can be read from the device certificate.

Coming back to this requirement. As it is described device identifier (device-id) may consist of 2 configurable parts:

  1. Configurable <device-id-prefix> (in this case device-id prefix is Ditto-Namespace)
  2. Configurable <ID> can be taken from client certificate ("subject-dn" or "serial-number").

Can the configuration of device-identifier be provided by additional property of trust anchor to provide such flexibility?

Example:

  1. Configuration for device identifier to use device-id-prefix plus subject-dn from client certificate as ID
    {
    "tenant-id": "TEST_TENANT",
    "trusted-ca": [{
    "subject-dn": "CN=ca,OU=device-provisioning,O=Eclipse",
    "auto-provisioning-enabled": true,
    "create-devices-as-gateways": true,
    "device-id-pattern": "device-id-prefix:{{ certificate:subject-dn }}"
}]

}

  1. Configuration for device identifier to use device-id-prefix plus serial-number from client certificate as ID
    {
    "tenant-id": "TEST_TENANT",
    "trusted-ca": [{
    "subject-dn": "CN=ca,OU=device-provisioning,O=Eclipse",
    "auto-provisioning-enabled": true,
    "create-devices-as-gateways": true,
    "device-id-pattern": "device-id-prefix:{{ certificate:serial-number }}"

    }]
    }

And if this property not configured for trust-anchor then a unique device-id can be generated in Device Registry.

WDYT? @sophokles73 @b-abel @fkaltner

Is it possible to exchange (between Hub and the gateway) these provisioning properties?

Before the gateway is provisioned in Hono only protocol adapter endpoints and client certificate are preconfigured on the gateway. As tenant-id will be identified in Hono based on the CA-certificate and device-id will be created during device registration there's necessity to provide this information to the gateway.

How can we provide created device-id and tenant-id after registration of the device in Device Registry to the gateway?

Additionally to the above mentioned points Device Registration service must send a request to Ditto for thing creation.

As it's described in https://github.com/eclipse/hono/issues/2053#issuecomment-669886189

Device Registration service creates device without credentials and publishes an empty notification event containing the tenant_id, device_id, gateway_id and hono_registration_status=NEW properties.

Could Device Registration service after registration of gateway and saving credentials (provided from the gateway X.509 certificate) publish an empty notification event with tenant_id and device_id and hono_registration_status=NEW properties ???

Could Device Registration service after registration of gateway and saving credentials (provided from the gateway X.509 certificate) publish an empty notification event with tenant_id and device_id and hono_registration_status=NEW properties ???

FMPOV this makes sense, especially since it is making the process for certificate-based and gateway-based auto-provisioning more consistent.

@alinaserg Auto-provisioning of devices (except edge devices connected via gateways) always involves generation of a random unique identifier as the device identifier. In case of auto-provisioning of edge devices connected via gateways at-least there is a possibility that the device id are provided by the gateways, if not given then a random id is used. Unlike in the case of the edge devices connected via gateways, here no event notifications are sent to north-bound side informing that a device has been auto-provisioned. Hence both the device and the north-bound side are unaware of the generated device id.

In this case, I see that your new requirement opens a way to tell Hono, how the device id should be generated instead of a random unique identifier. As you suggested, I can imagine well a configuration property such as "device-id-pattern" as below.

  1. "device-id-pattern": "xyz-{{ subject-DN }}" ---> use Subject DN
  2. "device-id-pattern": "abc-{{ random-ID }}" ---> use random UUID
  3. "device-id-pattern": "xyz-{{ serial-number }}" ---> use Serial Number from the client certificate.

As per X.509 RFC:

The serial number MUST be a positive integer assigned by the CA to each certificate. It MUST be unique for each certificate issued by a given CA (i.e., the issuer name and serial number identify a unique certificate). CAs MUST force the serialNumber to be a non-negative integer.

@b-abel @calohmn @fkaltner @sophokles73 WDYT?

Was this page helpful?
0 / 5 - 0 ratings