Automating .NET Security Updates

Microsoft .NET

Every few weeks Microsoft pushes out a .NET SDK update to patch zero day security vulnerabilities. It's important to keep up to date with these to ensure that your software is protected. The problem is, keeping up to date is a manual and boring process but what if you could automate it?

In this post, I'll talk through how you can get most of the way to a fully automated solution with the last hurdle requiring some of your help.

Single Source of Truth

The first problem we need to solve is to enforce a specific version of the .NET SDK to be used to build our code. We can do this by adding a global.json file to the root of our repository. We can set the .NET SDK version in it like so:

{
  "sdk": {
    "version": "3.1.402"
  }
}

Security vs Convenience

If a developer doesn't have the version of the .NET SDK you've specified in your global.json file, Visual Studio will fail to load the projects and show a pretty good error in the output window telling you to update the SDK. It would be nice if it also contained a link to the exact SDK install you needed to smooth the experience.

Continuous Integration

Continuous integration servers like GitHub Actions, Azure Pipelines or AppVeyor all have a version of the .NET SDK pre-installed for your convenience. However, when a new version is released it takes them days to update to the latest version.

In my opinion, it's just better to install the .NET SDK yourself, which is pretty easy to do. The trick is to read the .NET SDK version number from the global.json file, so that there is a single source of truth for the version number and it's easier to update.

It's worth noting that this adds a few seconds to your build time. However, if the build server already has the version installed which is usually true, it's very quick.

GitHub Actions

For GitHub Actions, we can use the first party actions/setup-dotnet GitHub action to install the .NET SDK. You can provide it a hard coded version number but it turns out omitting this causes it to lookup the version number from any global.json file it finds.

- name: 'Install .NET Core SDK'
  uses: actions/setup-dotnet@v1

Azure Pipelines

Azure Pipelines has a similar first party UseDotNet task that can install the .NET SDK. It's a bit more verbose, as you need to set the useGlobalJson flag to true.

- task: UseDotNet@2
  displayName: 'Install .NET Core SDK'
  inputs:
    packageType: 'sdk'
    useGlobalJson: true

PowerShell

.NET ships with a PowerShell and Bash script to install the .NET SDK. They both ship with an argument you can pass to tell them to use the global.json file to read the version number. Here is a short cross-platform PowerShell 7 (previously known as PowerShell Core) script that you can use:

if ($isWindows) {
    Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./dotnet-install.ps1"
    ./dotnet-install.ps1 -JSonFile global.json
}
else {
    Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh"
    sudo chmod u+x dotnet-install.sh
    sudo ./dotnet-install.sh --jsonfile global.json
}

AppVeyor

AppVeyor has some issues with installing the .NET SDK using the PowerShell and Bash scripts. For reasons I'm not too clear on, you have to set the installation directory. So here is the updated script I use for that:

if ($isWindows) {
    Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./dotnet-install.ps1"
    ./dotnet-install.ps1 -JSonFile global.json -InstallDir 'C:\Program Files\dotnet'
}
else {
    Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh"
    sudo chmod u+x dotnet-install.sh
    if ($isMacOS) {
        sudo ./dotnet-install.sh --jsonfile global.json --install-dir '/Users/appveyor/.dotnet'
    } else {
        sudo ./dotnet-install.sh --jsonfile global.json --install-dir '/usr/share/dotnet'
    }
}

Dependabot

Dependabot is an amazing tool that GitHub recently acquired. It automatically submits pull requests to your repository to update packages of various kinds including NuGet and NPM packages.

This is where I need your help. The Dependabot GitHub repository has an open issue (dependabot-core#2442) to also do the same for the .NET SDK version in the global.json file. Upvoting the issue will really help raise it's profile and get it implemented.

Conclusions

Security is hard. Keeping up to date is important but a never ending boring chore. It doesn't have to be that way. With a little extra work, we can get as close to making a .NET SDK update a three character commit every few weeks and with your help, maybe even that can be automated with Dependabot.

Web Mentions

What's this?

0 Replies

Comment

Initializing...