Search code examples
c#.netazuredockerssl

Why do my azure c# sdk device client shows "TLS authentication error"


So i have a program written in c# using azure sdk (both for iot hub device and event hub)

the program summarized:

// for Event Hub
var token = createToken("sb://my-event.servicebus.windows.net/", "my-policy", "mymsaskey");
var credential = new AzureSasCredential(token);
var producer = new EventHubProducerClient("my-event.servicebus.windows.net", "my-event-hub", credential);

using EventDataBatch eventBatch = await producer.CreateBatchAsync();
// the logic to send the batch

or

// for IoT Hub
DateTime expiresOn = DateTime.UtcNow.AddMinutes(1440);
string sasToken = GenerateSasToken(ResourceUri + "/devices/" + targetDevice, sharedaccesskeydevice, null, expiresOn);

var authenticationMethod = new DeviceAuthenticationWithToken(targetDevice, sasToken);
deviceClient = DeviceClient.Create(ResourceUri, authenticationMethod);

await deviceClient.OpenAsync();
// logic for sending data to cloud

when i build and run them on host ( whether its in my local, or i copy the binary to another remote server ), it runs just fine

but when i run this binary inside the docker, by copying the binary to the mounted folder of the docker (/var/lib/docker/blabla/_app) and restart the docker

it shows error:

TLS authentication error.
Inner Exception: System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Threading.Tasks.TaskToApm.End(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at Microsoft.Azure.Amqp.Transport.TlsTransport.HandleOpenComplete(IAsyncResult result, Boolean syncComplete)
--- End of stack trace from previous location ---
   at Microsoft.Azure.Amqp.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at Microsoft.Azure.Amqp.AmqpObject.OpenAsyncResult.End(IAsyncResult result)
   at Microsoft.Azure.Amqp.AmqpObject.EndOpen(IAsyncResult result)
   at Microsoft.Azure.Amqp.Transport.TlsTransportInitiator.OnTransportOpened(IAsyncResult result)
--- End of stack trace from previous location ---
   at Microsoft.Azure.Amqp.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at Microsoft.Azure.Amqp.Transport.AmqpTransportInitiator.<>c.<ConnectAsync>b__17_1(IAsyncResult r)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location ---
   at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpIotTransport.InitializeAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpIotConnector.OpenConnectionAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpConnectionHolder.EnsureConnectionAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpConnectionHolder.OpenSessionAsync(IDeviceIdentity deviceIdentity, CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpUnit.EnsureSessionIsOpenAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpUnit.OpenAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpTransportHandler.OpenAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.ProtocolRoutingDelegatingHandler.OpenAsync(CancellationToken cancellationToken)
   at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.<>c__DisplayClass27_0.<<ExecuteWithErrorHandlingAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.ExecuteWithErrorHandlingAsync[T](Func`1 asyncOperation)
Microsoft.Azure.Devices.Client

so i tried mounting the host /etc/ssl/certs to the docker, it works fine again

the thing is, i was not suppose to mount all of the host cert to the docker, but i dont understand, how do i know which certificate is used by defaults by the azure? because i cant remember setting any certificate beforehand

as in: even when i copy the binary to another remote server, i just copied it and run it as is and it still works

i might missed something because im not too familiar with all this ssl protocol and certification, so i would really appreciate any help

EDIT

  1. i develop the program using dotnet console with packages
// Event Hub
<PackageReference Include="Azure.Messaging.EventHubs" Version="5.10.0" />
<PackageReference Include="Azure.Core" Version="1.35.0" />

// IoT Hub
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.41.2" />
  1. No, I didn't use certification for connecting to IoT Hub. As seen in the snippet above for the IoT Hub I use SasToken by using the DeviceAuthenticationWithToken

  2. as for the docker configuration the dockerfile:

# Base Image
FROM ubuntu:22.04
LABEL maintainer=boo

# Install library
RUN apt-get -y update \
 && apt-get install -y \
   libicu-dev \
 && apt-get -y clean \
 && rm -rf /var/cache/apt/archives

# Copy Binary and Configuration
RUN mkdir /home/stem/
COPY ./bin /home/stem/bin
COPY ./project /home/stem/project

# Data Link
RUN ln -sf /home/stem/project /data
RUN ln -sf /home/stem/bin /app

# Command
WORKDIR /
ENTRYPOINT ["/app/BIN_CLOUD"]
"Binds": [
    "cloud_app:/app",
    "cloud_data:/data",
    "/etc/localtime:/etc/localtime:ro",
    "/etc/timezone:/etc/timezone:ro"
],

and the case where the certificate works i add -v /etc/ssl/certs:/etc/ssl/certs when creating the docker

  1. as for the link, thank you very much, i'm looking more into it. this tls link works for event hub too? is it like azure in general? or specifically for IoT Hub?

Solution

  • Refer to this MSDOC for configuring Transport Layer Security (TLS) for an Event Hubs client application.

    {
       
        System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
    
       
        string connectionString = "<NAMESPACE CONNECTION STRING>";
        
        
        string eventHubName = "<EVENT HUB NAME>";
        
       
        var producer = new EventHubProducerClient(connectionString, eventHubName);
        
      
        using EventDataBatch eventBatch = await producer.CreateBatchAsync();
        var eventData = new EventData("This is an event body");
    
        if (!eventBatch.TryAdd(eventData))
        {
            throw new Exception($"The event could not be added.");
        }
    }
    
    
    
    • The below code is for sending events to Azure Event Hubs using the Event Hubs SDK, creates a Shared Access Signature (SAS) token and then uses it to authenticate an EventHubProducerClient for sending events.
        string serviceBusNamespace = "HostName";
        string eventHubName = "AzureEventHubName";
        string sasKeyName = "RootManageSharedAccessKey";
      
        string sasKey = "Primary key";
    
        var token = CreateSasToken(serviceBusNamespace, sasKeyName, sasKey);
        var credential = new AzureSasCredential(token);
        var producer = new EventHubProducerClient(serviceBusNamespace, eventHubName, credential);
    
        try
        {
            using (EventDataBatch eventBatch = await producer.CreateBatchAsync())
            {
                
                var eventData = new EventData(Encoding.UTF8.GetBytes("Hello, Event Hub!"));
                eventBatch.TryAdd(eventData);
    
                
                await producer.SendAsync(eventBatch);
            }
    
            Console.WriteLine("Events sent successfully.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
        finally
        {
    
            await producer.CloseAsync();
        }
    }
    
    static string CreateSasToken(string resourceUri, string keyName, string key)
    {
        TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
        var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 3600); // 1 hour expiration
    
        string stringToSign = Uri.EscapeDataString(resourceUri) + "\n" + expiry;
        HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
        var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
    
        var sasToken = $"SharedAccessSignature sr={Uri.EscapeDataString(resourceUri)}&sig={Uri.EscapeDataString(signature)}&se={expiry}&skn={keyName}";
    
        return sasToken;
    }
    
    

    enter image description here

    • Refer to this MSDOC Azure IoT Hub TLS support