Creating a REST API Wrapper for VBR - Part 1


Userlevel 6
Badge +10

Something I have seen in many online discussions is Veeam’s (until recently) lack of a REST API for Backup & Replication. Until version 11, API functionality was only possible via Enterprise Manager or a PowerShell cmdlet. With version 11, this cmdlet was upgraded to a more modern PowerShell module and a REST API was introduced, albeit with limited functionality.

 

I have also found that the PowerShell module has its own limitations, such as:

  • Much slower command execution (~30 seconds for Get-VBRBackupRepository vs. ~2 seconds for equivalent REST API)
  • No support for PowerShell Core (cannot utilize module directly on MacOS/Linux devices, must leverage PSRemoting)

 

Utilizing ASP.NET Core, you can create your own REST API service, granting your organization the following Veeam functionality:

  • Remotely manage VBR servers via REST API, utilizing Veeam’s REST API where it exists and the PowerShell module where it doesn’t
  • Keep PSRemoting turned off in your environment
  • Securely pass credentials/encryption passwords to the VBR remotely
  • Communicate with multiple resources from the same API endpoint (such as VBR servers, VB365 servers, VMware clusters, etc.)
  • (Service Providers) Insert a middleman between your customers and your VSPC instance, allowing for API access to the console without giving public internet access to the machine
  • Host your public APIs on Linux machines or inside containers

 

Here on the automation desk, I’ll be posting a series of articles detailing the process of creating and configuring your own ASP.NET Core MVC application, covering topics such as:

  • Initial configuration (Project creation, packages, Swagger UI, Windows Authentication)
  • Authenticating with the VBR REST API & Creating Scheduled Tasks
  • Embedding PowerShell commands & calling PowerShell from PowerShell Core

 

For the purposes of these articles, I will be running the service on a B&R server and only building sample APIs for VBR to keep complexity down. A sample project will be available on my GitHub to follow along with. We will also be developing with .NET 6 even though 7 has recently been released, as not all NuGet packages we need for the project support 7 as of writing. Additionally, .NET 6 is an LTS release while .NET 7 is only an STS release.

 

Without further ado, here is part 1.

 

Pre-requisites:

 

First, we will begin by creating a new ASP.NET Core MVC Project. Begin by browsing to an empty folder where you would like the project to be saved. Then, in the terminal window, copy and paste the following command:

 

dotnet new webapi -f net6.0

 

Once the command executes, you should now have a new .csproj file and associated project files. Some of these files are samples, but we will follow the same file format throughout this series. You may receive an error like “error NU1100: Unable to resolve 'Swashbuckle.AspNetCore (>= 6.4.0)' for 'net6.0'.” while building or running the project. If this happens, run the following commands:

 

dotnet nuget add source --name nuget.org https://api.nuget.org/v3/index.json

dotnet restore

 

Now that the project is created, we will begin by customizing the Swagger UI. Start by adding the following to the top of Program.cs:

 

using Microsoft.OpenApi.Models;

 

Then, replace line 10 with the following:

 

builder.Services.AddSwaggerGen(options =>

{

    options.SwaggerDoc("v1", new OpenApiInfo

    {

        Version = "v1",

        Title = "Veeam B&R Custom API",

        Description = "An ASP.NET Core Web API for Veeam Backup & Replication",

    });

});

 

This will update the title, version number, and description shown at the top of the Swagger UI. Next, replace line 26 with the following:

 

app.UseSwaggerUI(c =>

    {

        c.SwaggerEndpoint("/swagger/v1/swagger.json", "VBR API v1");

    });

 

This changes the swagger endpoint and customizes the name displayed in the “Select a definition” dropdown. Finally, attempt to run your project with the following command:

 

dotnet run

 

If the project builds successfully, you will see an output like the following:

 

 

 

With the project running, we should be able to access the swagger UI from a web browser.

 

 

Next, we will add a few packages that will be needed throughout the project:

  • Microsoft.PowerShell.SDK
  • Microsoft.AspNetCore.Authentication.Negotiate (6.0.12)

 

These two packages will allow for integrated PowerShell scripting and Windows Authentication while the application is hosted via IIS or Kestrel.

 

As the final step of Part 1, we will configure the service to use Windows authentication, allowing for SSO with an Active Directory domain. First, we will add the following line to the top of Program.cs:

 

using Microsoft.AspNetCore.Authentication.Negotiate;

 

Next, add the following under var builder = WebApplication.CreateBuilder(args):

 

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)

   .AddNegotiate();

 

builder.Services.AddAuthorization(options =>

{

    options.FallbackPolicy = options.DefaultPolicy;

});

builder.Services.AddRazorPages();

 

The final change to make to Program.cs is to add the following above app.UseAuthorization():

 

app.UseAuthentication();

 

Now that Program.cs is configured for Windows authentication, there are a few configuration changes we will need to make. The first change will be to ensure IIS Express uses Windows authentication when VS Code debugs the code. To do this, open LaunchSettings.json and change the following configuration settings under iisSettings:

 

"windowsAuthentication": true

"anonymousAuthentication": false

 

Finally, Kestrel requires SPNs to be set for the account running the service on the production machine. You can read more about this here. Information on some additional configuration that may be needed for operation on Linux and macOS systems can be found here.

 

This concludes Part 1 of the series. In the next part, we will configure the service to authenticate with the VBR REST API at startup and set up a scheduled task to renew the API token before it expires.


10 comments

Userlevel 7
Badge +20

Very cool topic Jonah.  Thanks for sharing.

Userlevel 7
Badge +17

Very interesting article.

I will try this, I wanted to play around with the REST API for some time now.  😁

Userlevel 7
Badge +6

Very nice.  I don’t do a lot of automation and am mostly hear to learn from those of you that do a lot….and this one (or series) does not disappoint.  I need to learn more about REST API’s in general as I find the API in the Service Provider Console somewhat of a challenge, even with the Swagger UI, but I’m sure once I get over the hump of it, I’m sure I’ll get it.  This certainly gives me some more/different insight.

Userlevel 6
Badge +10

Very nice.  I don’t do a lot of automation and am mostly hear to learn from those of you that do a lot….and this one (or series) does not disappoint.  I need to learn more about REST API’s in general as I find the API in the Service Provider Console somewhat of a challenge, even with the Swagger UI, but I’m sure once I get over the hump of it, I’m sure I’ll get it.  This certainly gives me some more/different insight.

I usually end up using Postman or PowerShell’s Invoke-RestMethod command when testing out VSPC APIs. The VSPC Swagger page doesn’t seem to like me trying to test APIs through it and I haven’t taken the time to figure out why yet.

Userlevel 7
Badge +6

Very nice.  I don’t do a lot of automation and am mostly hear to learn from those of you that do a lot….and this one (or series) does not disappoint.  I need to learn more about REST API’s in general as I find the API in the Service Provider Console somewhat of a challenge, even with the Swagger UI, but I’m sure once I get over the hump of it, I’m sure I’ll get it.  This certainly gives me some more/different insight.

I usually end up using Postman or PowerShell’s Invoke-RestMethod command when testing out VSPC APIs. The VSPC Swagger page doesn’t seem to like me trying to test APIs through it and I haven’t taken the time to figure out why yet.

 

I think my single biggest issue is just trying to authenticate with MFA.  I can’t seem to figure out creating a token, and it can’t be that hard, but once I get over that hump, I’m betting it’s easier.  It seems like the documentation for that sort of thing is lacking, or perhaps I’m not seeing it or am expected to know more about what I’m doing when I get started.  I’m not familiar with Postman and haven’t used Invoke-RestMethod but I’ll check into them….good to have all of those tools in the repository.

Userlevel 6
Badge +10

Very nice.  I don’t do a lot of automation and am mostly hear to learn from those of you that do a lot….and this one (or series) does not disappoint.  I need to learn more about REST API’s in general as I find the API in the Service Provider Console somewhat of a challenge, even with the Swagger UI, but I’m sure once I get over the hump of it, I’m sure I’ll get it.  This certainly gives me some more/different insight.

I usually end up using Postman or PowerShell’s Invoke-RestMethod command when testing out VSPC APIs. The VSPC Swagger page doesn’t seem to like me trying to test APIs through it and I haven’t taken the time to figure out why yet.

 

I think my single biggest issue is just trying to authenticate with MFA.  I can’t seem to figure out creating a token, and it can’t be that hard, but once I get over that hump, I’m betting it’s easier.  It seems like the documentation for that sort of thing is lacking, or perhaps I’m not seeing it or am expected to know more about what I’m doing when I get started.  I’m not familiar with Postman and haven’t used Invoke-RestMethod but I’ll check into them….good to have all of those tools in the repository.

I’m unfortunately not of much help there. I generate simple API keys in VSPC, usually one per project, and use those. Iirc, it bypasses the need for creating a token like with a user. Plus, then any API actions performed should be linked in logs to that particular key for auditing. Of course, using a service account would accomplish something similar.

 

I do wish that you could set permissions for the API keys so they could be restricted to certain functions for better access control (i.e. read-only access or only capable of the APIs you plan to use with it). Maybe that will be a feature in a future release.

Userlevel 7
Badge +17

Access control or permissions would be good for all kind of API… perhaps we will see it in the future. 😎

Userlevel 2
Badge

nice work! Thank you for sharing 👏🏻

Userlevel 7
Badge +8

Very cool and unique content. Thank’s for sharing. Looking forward to #2-8... 😁

Userlevel 2
Badge +1

@JonahMay I wish we had found this sooner as we are doing something similar. Still very useful thank you, will you be publishing a part 2?

Comment