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
// 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" />
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
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
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.");
}
}
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;
}