Skip to content

Commit

Permalink
Adding readme to explain authentication, retry and timeouts in Device…
Browse files Browse the repository at this point in the history
…Client (#2096)
  • Loading branch information
vinagesh authored Jul 14, 2021
1 parent c76a64d commit c1b707c
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 7 deletions.
85 changes: 85 additions & 0 deletions DeviceConnectionAndReliabilityReadme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Azure IoT Device Client .NET SDK

## Device connection and messaging reliability

### Overview

In this document you will find information about:

- The connection authentication and renewal methods.
- The reconnection logic and retry policies.
- The timeout controls.

### Connection authentication

Authentication can be done using one of the following:

- [SAS tokens for the device](https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-sas?tabs=node#use-sas-tokens-as-a-device) - Using IoT hub [device shared access key](https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-sas?tabs=node#use-a-shared-access-policy-to-access-on-behalf-of-a-device) or [symmetric key](https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-sas?tabs=node#use-a-symmetric-key-in-the-identity-registry) from DPS identity registry
- [x509 certificate](https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-sas#supported-x509-certificates) - Self signed or [CA-signed](https://docs.microsoft.com/azure/iot-hub/iot-hub-x509ca-overview)
- [TPM based authentication](https://azure.microsoft.com/blog/device-provisioning-identity-attestation-with-tpm/)

Samples:
- IoT hub device shared access key based authentication sample - [DeviceReconnectionSample](https://github.com/Azure-Samples/azure-iot-samples-csharp/blob/master/iot-hub/Samples/device/DeviceReconnectionSample/DeviceReconnectionSample.cs#L102)
- Device provisioning service symmetric key based authentication sample - [ProvisioningDeviceClientSample](https://github.com/Azure-Samples/azure-iot-samples-csharp/blob/master/provisioning/Samples/device/SymmetricKeySample/ProvisioningDeviceClientSample.cs#L62)
- x509 based authentication sample using CA-signed certificates - [X509DeviceCertWithChainSample](https://github.com/Azure-Samples/azure-iot-samples-csharp/blob/master/iot-hub/Samples/device/X509DeviceCertWithChainSample/Program.cs#L43)
- TPM based authentication sample - [ProvisioningDeviceClientSample](https://github.com/Azure-Samples/azure-iot-samples-csharp/blob/master/provisioning/Samples/device/TpmSample/ProvisioningDeviceClientSample.cs#L49)

When using SAS tokens, authentication can be done by:

- Providing the shared access key of the IoT hub and letting the SDK create the SAS tokens by using one of the `CreateFromConnectionString` methods on the [DeviceClient](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceclient).

If you choose this option, the SDK will create the SAS tokens and renew them before expiry. The default values for time-to-live and renewal buffer can be changed using the `ClientOptions` properties.

- [SasTokenTimeToLive](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.clientoptions.sastokentimetolive): The suggested time-to-live value for tokens generated for SAS authenticated clients. Default value is 60 minutes.
- [SasTokenRenewalBuffer](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.clientoptions.sastokenrenewalbuffer): The time buffer before expiry when the token should be renewed, expressed as a percentage of the time-to-live. Acceptable values lie between 0 and 100. Default value is 15%.

> Note: If the shared access policy name is not specified in the connection string, the audience for the token generation will be set by default to - `<iotHubHostName>/devices/<deviceId>`
- Providing only the shared access signature

If you only provide the shared access signature, there will never be any renewal handled by the SDK.

- Providing your own SAS token using [DeviceAuthenticationWithTokenRefresh](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtokenrefresh)

If you choose to use `DeviceAuthenticationWithTokenRefresh` to provide your own implementation of token generation, you can provide the time-to-live and time buffer before expiry through the `DeviceAuthenticationWithTokenRefresh` constructor. The `ClientOptions` only apply to other `IAunthenticationMethod` implementations.

When using x509 certificates, [DeviceAuthenticationWithX509Certificate](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithx509certificate) can be used. The client authentication will be valid until the certificate is valid. Any renewal will have to be done manually and the client needs to be recreated.

When using TPM based authentication, the [DeviceAuthenticationWithTpm](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtpm) can be used. TPM based authentication will eventually generate a SAS token but is more secure than using the shared access key of the IoT hub to generate the token.

### Authentication methods implemented by the SDK

The different `IAuthenticationMethod` implementations provided by the SDK are:

- [DeviceAuthenticationWithRegistrySymmetricKey](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithregistrysymmetrickey) - Authentication method that uses the symmetric key associated with the device in the device registry.
- [DeviceAuthenticationWithSharedAccessPolicyKey](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithsharedaccesspolicykey) - Authentication method that uses a shared access policy key.
- [DeviceAuthenticationWithToken](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtoken) - Authentication method that uses a shared access signature token.
- [DeviceAuthenticationWithTokenRefresh](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtokenrefresh) - Abstract class that can be implemented to generate a shared access signature token and allows for token refresh.
- [DeviceAuthenticationWithTpm](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithtpm) - Authentication method that uses a shared access signature token generated using TPM and allows for token refresh.
- [DeviceAuthenticationWithX509Certificate](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.deviceauthenticationwithx509certificate) - Authentication method that uses a X.509 certificates.

### Connection retry logic

For both AMQP and MQTT, the SDK will try to reconnect anytime there is any network related disruption. The default retry policy does not have a time limit and will follow exponential back-off.

> Note: The default retry policy has support for jitter, which ensures that if you have N devices that disconnected at the same time, all of them won't start reconnecting with the same delay.
For more details on the default retry policy and how to override it, see [retry policy documentation](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/iothub/device/devdoc/retrypolicy.md).

HTTP is a stateless protocol and will work whenever there is network connectivity.

### Timeout controls

There are different timeout values that can be configured for the `DeviceClient`/`ModuleClient` based on the protocol. These values are configuarable through the following transport settings that are passed while creating the client. Once the client is created, the settings cannot be changed. The client will need to be recreated with new settings to make changes.

AMQP timeout settings:

- [IdleTimeout](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.amqptransportsettings.idletimeout) - The interval that the client establishes with the service, for sending keep-alive pings. The default value is 2 minutes.
- [OperationTimeout](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.amqptransportsettings.operationtimeout) - The time to wait for any operation to complete. The default is 1 minute.
- [OpenTimeout](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.amqptransportsettings.opentimeout) - This value is not used (TODO: Confirm and update)

MQTT timeout settings:

- [ConnectArrivalTimeout](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.transport.mqtt.mqtttransportsettings.connectarrivaltimeout) - The time to wait for receiving an acknowledgment for a CONNECT packet. The default is 1 minute.
- [KeepAliveInSeconds](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.transport.mqtt.mqtttransportsettings.keepaliveinseconds) - The interval, in seconds, that the client establishes with the service, for sending keep-alive pings. The default value is 5 minutes. The client will send a ping request 4 times per keep-alive duration set. It will wait for 30 seconds for the ping response, else mark the connection as disconnected.
- [DeviceReceiveAckTimeout](https://docs.microsoft.com/dotnet/api/microsoft.azure.devices.client.transport.mqtt.mqtttransportsettings.devicereceiveacktimeout) - The time a device will wait for an acknowledgment from service. The default is 5 minutes.
15 changes: 12 additions & 3 deletions iothub/device/src/AmqpTransportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,18 @@ public AmqpTransportSettings(TransportType transportType, uint prefetchCount, Am

/// <summary>
/// Specify client-side heartbeat interval.
/// The interval, that the client establishes with the service, for sending keep alive pings.
/// The default value is 2 minutes.
/// </summary>
/// <remarks>
/// The client will consider the connection as disconnected if the keep alive ping fails.
/// Setting a very low idle timeout value can cause aggressive reconnects, and might not give the
/// client enough time to establish a connection before disconnecting and reconnecting.
/// </remarks>
public TimeSpan IdleTimeout { get; set; }

/// <summary>
/// The operation timeout
/// The time to wait for any operation to complete. The default is 1 minute.
/// </summary>
public TimeSpan OperationTimeout
{
Expand All @@ -129,8 +135,11 @@ public TimeSpan OperationTimeout
}

/// <summary>
/// The open timeout
/// The open timeout. The default is 1 minute.
/// </summary>
/// <remarks>
/// This property is currently unused.
/// </remarks>
public TimeSpan OpenTimeout
{
get => _openTimeout;
Expand Down Expand Up @@ -172,7 +181,7 @@ public TransportType GetTransportType()
}

/// <summary>
/// Returns the default current receive timeout
/// The time to wait for a receive operation. The default value is 1 minute.
/// </summary>
public TimeSpan DefaultReceiveTimeout => DefaultOperationTimeout;

Expand Down
5 changes: 4 additions & 1 deletion iothub/device/src/Http1TransportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.Azure.Devices.Client
/// </summary>
public sealed class Http1TransportSettings : ITransportSettings
{
private static readonly TimeSpan s_defaultOperationTimeout = TimeSpan.FromSeconds(60);
private static readonly TimeSpan s_defaultOperationTimeout = TimeSpan.FromMinutes(1);

/// <summary>
/// Initializes a new instance of the <see cref="Http1TransportSettings"/> class.
Expand All @@ -40,6 +40,9 @@ public TransportType GetTransportType()
/// <summary>
/// The time to wait for a receive operation. The default value is 1 minute.
/// </summary>
/// <remarks>
/// This property is currently unused.
/// </remarks>
public TimeSpan DefaultReceiveTimeout => s_defaultOperationTimeout;

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion iothub/device/src/ITransportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface ITransportSettings
TransportType GetTransportType();

/// <summary>
/// The default receive timeout.
/// The time to wait for a receive operation.
/// </summary>
TimeSpan DefaultReceiveTimeout { get; }
}
Expand Down
6 changes: 4 additions & 2 deletions iothub/device/src/Transport/Mqtt/MqttTransportSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public bool CertificateRevocationCheck
public bool DeviceReceiveAckCanTimeout { get; set; }

/// <summary>
/// The time a device will wait, for an acknowledgment from service.
/// The time a device will wait for an acknowledgment from service.
/// The default is 5 minutes.
/// </summary>
/// <remarks>
Expand Down Expand Up @@ -182,12 +182,14 @@ public bool CertificateRevocationCheck
public bool CleanSession { get; set; }

/// <summary>
/// The interval, in seconds, that the client establishes with the service, for sending keep alive pings.
/// The interval, in seconds, that the client establishes with the service, for sending keep-alive pings.
/// The default is 300 seconds.
/// </summary>
/// <remarks>
/// The client will send a ping request 4 times per keep-alive duration set.
/// It will wait for 30 seconds for the ping response, else mark the connection as disconnected.
/// Setting a very low keep-alive value can cause aggressive reconnects, and might not give the
/// client enough time to establish a connection before disconnecting and reconnecting.
/// </remarks>
public int KeepAliveInSeconds { get; set; }

Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ This repository contains [provisioning service client SDK](./provisioning/servic
- [Set up your development environment](./doc/devbox_setup.md) to prepare your development environment as well as how to run the samples on Linux, Windows or other platforms.
- [API reference documentation for .NET](https://docs.microsoft.com/dotnet/api/overview/azure/devices?view=azure-dotnet)
- [Get Started with IoT Hub using .NET](https://docs.microsoft.com/azure/iot-hub/iot-hub-csharp-csharp-getstarted)
- [Device connection and messaging reliability](https://github.com/Azure/azure-iot-sdk-csharp/blob/master/DeviceConnectionAndReliabilityReadme.md)

> Device Explorer is no longer supported. A replacement tool can be found [here](https://github.com/Azure/azure-iot-explorer).
Expand Down

0 comments on commit c1b707c

Please sign in to comment.