I'm working on a .NET desktop application and need to send logs to AWS CloudWatch. My team created a NuGet package to standardize Serilog logging across all our projects.
Our setup works fine for ECS-hosted applications, but for desktop applications, we're looking for the best way to send logs to CloudWatch.
public static Serilog.Core.Logger CreateEndpointLoggerWithCloudWatch(
string applicationName, string logGroup, string region, LogOutput output = LogOutput.None)
{
AWSLoggerConfig awsConfiguration = new(logGroup) { Region = region };
LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
.WriteTo.AWSSeriLog(awsConfiguration, textFormatter: new ExpressionTemplate(JsonLogTemplate));
return loggerConfiguration.CreateLogger();
}
This works fine in ECS, but for desktop applications, we face challenges such as:
The first solution we tried was to set AWS credentials in the .aws file. While this approach works well, I am not fully convinced about its reliability and security.
Another approach was to create a Cognito Identity Pool for guest users and define an IAM role that allows the application to send logs to CloudWatch.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CloudWatchLogsFullAccess",
"Effect": "Allow",
"Action": [
"logs:*",
"cloudwatch:GenerateQuery"
],
"Resource": "*"
}
]
}
the trust relationship
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws:aud": "eu-xxx-1:xxx-xxx-xxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws:amr": "unauthenticated"
}
}
}
]
}
To authenticate our application, we need to pass credentials to the AWSLoggerConfig
object using the Cognito Identity Pool ID:
public static Serilog.Core.Logger CreateEndpointLoggerWithCloudWatch(
string applicationName, string logGroup, string region, LogOutput output = LogOutput.None, string identityPoolId)
{
AWSLoggerConfig awsConfiguration = new(logGroup)
{
Region = region,
Credentials = new CognitoAWSCredentials(identityPoolId, RegionEndpoint.GetBySystemName(region));
};
LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
.WriteTo.AWSSeriLog(awsConfiguration, textFormatter: new ExpressionTemplate(JsonLogTemplate));
return loggerConfiguration.CreateLogger();
}
This solution works and allows us to log unauthenticated actions. However, I am concerned about potential security risks associated with this approach.
Another option would be to implement a background service that acts as a gateway between our application and CloudWatch. However, I am not convinced that this is the best approach, as it adds an additional layer of complexity and potential failure points.