TheThingsNetwork / lorawan-stack

The Things Stack, an Open Source LoRaWAN Network Server
https://www.thethingsindustries.com/stack/
Apache License 2.0
975 stars 306 forks source link

Device Claiming Server #4841

Closed johanstokking closed 2 years ago

johanstokking commented 2 years ago

Summary

Implement a Device Claiming Server.

Why do we need this?

To facilitate claiming of end devices.

What is already there? What do you see now?

We currently have a proprietary implementation of the Device Claiming Server. This issue replaces at least the end device claiming part and makes the DCS component groundwork open source.

What is missing? What do you want to see?

How do you propose to implement this?

  1. Rework EndDeviceClaimingServer service:
    1. Remove application authorization; AuthorizeApplication() and UnauthorizeApplication() or simply return Unimplemented
    2. Report whether claiming is available for a given JoinEUI with new rpc GetInfoByJoinEUI()
    3. Claim an end device; existing rpc Claim() suffices, but most fields aren't relevant anymore as DCS won't deal with NS and AS registration. DCS will call out to the Join Server on behalf of the user and is the "application owner"
    4. Get claim status of an end device with new rpc GetClaimStatus(). This takes EndDeviceIdentifiers
    5. Unclaim with new rpc Unclaim()
  2. Implement The Things Join Server and LoRa Cloud Join Server as client protocols

Can you do this yourself and submit a Pull Request?

We need to decide between:

  1. Registering each TTS application with its own credentials at the Join Server. This means that TTS needs a way to manage device groups (applications) at the Join Server. Each device group would have its own auth. With LoRa Cloud Join Server, we can't programmatically create a new "application owner", so users would have to copy-paste their application owner TLS client cert and key so DCS can act on behalf of the user. This benefit of mapping TTS applications to JS device groups is that the JS can enforce authentication. The downside is that DCS needs to keep per-application credentials for each JS. Another downside is that customers are not able to manage their devices themselves in LoRa Cloud Join Server, unless of course they run The Things Stack themselves

  2. Considering a TTS cluster with AS and DCS one "Application Server" at the Join Server. In LoRaWAN Backend Interfaces terms, this would be one ASID. In LoRa Cloud Join Server terms, a TTS cluster is an "application owner". The benefit is that this is easiest to configure. The downside is that TTS has to make sure that you can't unclaim devices that are not registered in the application (DCS would basically need to get the device from IS).

My preference is with (2).

@htdvisser @KrishnaIyer thoughts?

KrishnaIyer commented 2 years ago

Considering a TTS cluster with AS and DCS one "Application Server" at the Join Server. In LoRaWAN Backend Interfaces terms, this would be one ASID. In LoRa Cloud Join Server terms, a TTS cluster is an "application owner". The benefit is that this is easiest to configure. The downside is that TTS has to make sure that you can't unclaim devices that are not registered in the application (DCS would basically need to get the device from IS).

This sounds good to me.

Report whether claiming is available for a given JoinEUI with new rpc GetInfoByJoinEUI() Get claim status of an end device with new rpc GetClaimStatus(). This takes EndDeviceIdentifiers

In both these cases, what auth would the user provide and how to assign rights? If we allow anyone to query if a particular EUI is claimed or not, wouldn't we be allowing users to scan the claim status of every EUI possible? In Gateway claiming, we return "error already claimed" only after we validate the CAC for the EUI (but then we have the IS there).

I think users should at least provide the correct CAC for the EUI pairs that they are checking the claim status of.

johanstokking commented 2 years ago

Report whether claiming is available for a given JoinEUI with new rpc GetInfoByJoinEUI() Get claim status of an end device with new rpc GetClaimStatus(). This takes EndDeviceIdentifiers

In both these cases, what auth would the user provide and how to assign rights? If we allow anyone to query if a particular EUI is claimed or not, wouldn't we be allowing users to scan the claim status of every EUI possible?

The rpc GetInfoByJoinEUI() is only taking a JoinEUI. Whether claiming is supported by a JoinEUI is pretty much public, it will be in DNS in the future anyway.

The rpc GetClaimStatus() requires application rights. DCS takes EndDeviceIdentifiers and checks rights to the application. DCS then dials out to the Join Server to get the claim status by DevEUI.

htdvisser commented 2 years ago

Remove application authorization; AuthorizeApplication() and UnauthorizeApplication() or simply return Unimplemented

That's also what gRPC will return if we remove the implementations.

The rpc GetInfoByJoinEUI() is only taking a JoinEUI. Whether claiming is supported by a JoinEUI is pretty much public, it will be in DNS in the future anyway.

We can apply the same logic as with some of our other "public" RPCs: accepting any valid auth token on the network.

Considering a TTS cluster with AS and DCS one "Application Server" at the Join Server. [...] The downside is that TTS has to make sure that you can't unclaim devices that are not registered in the application (DCS would basically need to get the device from IS).

How would this work with self-hosted Open Source / Enterprise deployments and with Dedicated Cloud deployments? Wouldn't it make more sense to have only a single DCS for each network, deployed together with the IS?

johanstokking commented 2 years ago

Considering a TTS cluster with AS and DCS one "Application Server" at the Join Server. [...] The downside is that TTS has to make sure that you can't unclaim devices that are not registered in the application (DCS would basically need to get the device from IS).

How would this work with self-hosted Open Source / Enterprise deployments and with Dedicated Cloud deployments?

Per Backend Interfaces, Join Server associates an AS-ID with an end device. This is a string, fortunately not an EUI64 this time; I'd say for TTS we use cluster addresses as AS-IDs.

Wouldn't it make more sense to have only a single DCS for each network, deployed together with the IS?

We could take the IS address as the AS-ID, and indeed deploy DCS with IS, but it's not only DCS that needs to authenticate with JS but also AS (to recover the AppSKey). Therefore, I think it is reasonable to assign an AS-ID to a cluster, so JS can authenticate an AS by its cluster address. That way, we do not have to provision multi-cluster deployments with the same credentials to authenticate as one AS-ID, and DCS and AS can use the same credentials to authenticate with JS.

johanstokking commented 2 years ago

@KrishnaIyer please see https://github.com/TheThingsIndustries/lorawan-join-server/pull/5.

The idea is that DCS gets a map of JoinEUI to client settings. The client settings contain the API to use as well as authentication methods. In case of our new JS, that will be the new claiming API and HTTP basic authentication settings. DCS authenticates as Application Server and needs to claim, unclaim, get claim status and update a claim on behalf of a user.