The Daily Parker

Politics, Weather, Photography, and the Dog

Another outage

Even as Garmin picks up the pieces from what they now admit was a massive ransomware attack, bulk email provider SendGrid has gone down spectacularly.

I use SendGrid, as does my company, for status emails and such.

Here's my problem, though: I have a code update to put out that specifically targets a bug in SendGrid's .NET library that they claim to have fixed. My automated build pipelines won't release new code unless all the unit tests pass. Right now, the SendGrid tests fail sporadically, and at least one fails every time the tests run.

Ah, technology.

How to pass secrets into your custom log target

Today I finally solved a problem that has nagged me for months: Given a .NET Core 3.1 Web API, NLog, and a custom log target for NLog, how could I pass secrets into the log target using Azure Key Vault?

The last bit required me to add Azure Key Vault support to the InnerDrive.Logging NuGet package, which I did back in February. The KeyVaultSecretProvider class allows you to retrieve secrets from a specified Azure Key Vault. (I'm in the process of updating it to handle keys as well.) Before that, you'd have to put your secrets in configuration files, which anyone on your development team or who has access to your Git repository can see. For example, to use our SendGridTarget class, you would have to put this in your nLog.config file:

<extensions>
	<add assembly="NLog.Web.AspNetCore"/>
	<add assembly="InnerDrive.Logging"/>
</extensions>

<targets async="false">
	<target xsi:type="SendGridTarget"
	        name="sendgrid"
		apiKey="{supposedly secret key}"
		applicationName="My Cool App"
	        from="service@contoso.org"
	        to="admin@contoso.org"
	/>
</targets>

That is...suboptimal. Instead, you want to use a class that implements ISecretProvider and inject it into the SendGridTarget class through this constructor:

/// <summary>
/// Creates a new instance of <see cref="SendGridTarget"/> with
/// a specified <see cref="ISendGridSender"/> implementation.
/// </summary>
/// <param name="sender">The <see cref="ISendGridSender"/> to use</param>
/// <param name="secretProvider">The <see cref="IConfiguration"/> to use</param>
/// <param name="apiKey">The API key to use</param>
public SendGridTarget(
	ISendGridSender sender, 
	ISecretProvider secretProvider = null, 
	string apiKey = null)
{
	IncludeEventProperties = true;
	if (null != secretProvider) Configuration = secretProvider;
	if (!string.IsNullOrWhiteSpace(apiKey)) ApiKey = apiKey;
	_sender = sender;
}

And now I'm going to save you about 30 hours of research and frustration. To get NLog to inject the secret provider into the target, I added this method to Startup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IComponentContext container)
{
	// Setup code elided
	ConfigureLogging(container);
}

public static void ConfigureLogging(IComponentContext container)
{
	var defaultConstructor = ConfigurationItemFactory.Default.CreateInstance;
	var secretProvider = container.Resolve<ISecretProvider>();
	ConfigurationItemFactory.Default.CreateInstance = type =>
	{
		if (type == typeof(SendGridTarget))
		{
			var sendGridSender = container.Resolve<ISendGridSender>();
			return new SendGridTarget(sendGridSender, secretProvider);
		}

		return defaultConstructor(type);
	};
	LogManager.Configuration = LogManager.Configuration.Reload();
	NLogBuilder.ConfigureNLog(LogManager.Configuration);
}

(Note that the ISecretProvider and ISendGridSender classes need to be registered with your dependency-injection framework.)

Today was a good day.

Lunchtime reading

It has cooled off slightly from yesterday's scorching 36°C, but the dewpoint hasn't dropped much. So the sauna yesterday has become the sticky summer day today. Fortunately, we invented air conditioning a century or so ago, so I'm not actually melting in my cube.

As I munch on some chicken teriyaki from the take-out place around the corner, I'm also digesting these articles:

Can you believe we're only 99 days from the election? How time flies.

Garmin offline

Four days after I switched from Fitbit to Garmin, all of Garmin's online services have gone offline:

The problems with those services also mean that a range of features can't be used on Garmin's own devices: it is not possible to create new routes to go running or cycling, for instance, or to share those activities on services like Strava once they are completed.

The devices themselves continue to work as normal with the data they do have, however, meaning that any data collected during the outage will be safe.

Garmin wrote on its official Twitter pages that the problems were also affecting its call centres, leaving users unable to get in touch through calls or online messages.

"We are currently experiencing an outage that affects Garmin Connect, and as a result, the Garmin Connect website and mobile app are down at this time," it wrote.

"This outage also affects our call centres, and we are currently unable to receive any calls, emails or online chats. We are working to resolve this issue as quickly as possible and apologise for this inconvenience."

This is not what Garmin customers want to see:

The error message on the Garmin Connect website suggests the problem is with their Cloudflare equipment:

Update: Based on Garmin employee's social-media posts, ZDNet now reports that the company experienced a catastrophic ransomware attack, most likely a new strain of WastedLocker. Fortunately, my Venu can hold 200 hours of data. So as long as they get it back up within a week or so, I shouldn't lose anything—unless the ransomware attack already destroyed my data from this past week.

Mid-morning news round-up

I'll get to the final head-to-head comparison between my Garmin Venu and Fitbit Ionic later today. Meanwhile:

And finally, because our Covid-19 numbers have started creeping up, indoor bar service will halt on Friday.

A bit of news overload today

Happy tax day! And now, we're off to the races:

Finally, Bloomberg takes a backward glance at the rise and fall of the Segway.

Today's lunchtime reading

As I take a minute from banging away on C# code to savor my BBQ pork on rice from the local Chinese takeout, I have these to read:

And today's fortune cookie says: "Hope for the best, but prepare for the worst in bed."

In the news this morning

Vox has called the US Senate Democratic Party primary in Kentucky for Amy McGrath, but the main national outlets don't have it yet. [Note: I have contributed financially to Amy McGrath's campaign.] So while I wait for confirmation from the Washington Post (or, you know, the Kentucky State Board of Elections), here's other fun stuff:

Finally, Jeffrey Toobin attempts to explain "Why the Mueller Investigation Failed."

Update: NBC calls Kentucky for McGrath.

So much to read

I'm back in the office tomorrow, after taking a 7:15 am call with a colleague in India. So I won't spend a lot of time reading this stuff tonight:

OK, I need 3,700 steps before 10pm, and then I need to empty my dog and go to bed.

Afternoon news roundup

My inbox does not respect the fact that I had meetings between my debugging sessions all day. So this all piled up:

Finally, conferencing app Zoom will roll out true end-to-end encryption in July.