7.6. Studio Part 1: Deploy Coding Events API with AADB2C

In this studio your mission is to practice accessing protected resources in the final version of the Coding Events API.

You will begin by working with the API locally to make sure that the latest updates are functioning properly. Afterwards, you will deploy the API to Azure to be served securely over HTTPS.

Before we continue let’s consider what we have already set up in the previous walkthroughs:

  • An AADB2C tenant for managing user identity accounts
  • Two registered applications: the Coding Events API and its consumer, the Postman desktop client application
  • A configuration for access tokens with a user_impersonation scope to protect the API by only allowing requests from the registered Postman application
  • A configuration for the Postman application to request an access token and use it for making requests to the new endpoints available in the Coding Events API collection

At a high level this studio will require you to:

  • Update the Coding Events API source code with settings to integrate with your AADB2C tenant and validate the access tokens it receives from Postman
  • Deploy the API to Azure with the correct VM, Key vault and security configurations that you have seen in previous deployments
  • Run setup scripts that configure the VM and serve the API over a secure connection as a background service
  • Test out the protected endpoints on your own or with a partner

At the end of the studio you will share the public IP address of your deployed API to your TA for review.

7.6.1. Setup

Before you deploy the API you will set up a local environment to test it. For this setup you will need to:

  1. set up a local MySQL coding_events database
  2. update your Coding Events API appsettings.json to integrate with AADB2C

7.6.1.1. Set Up Local MySQL

You will use the MySQL Workbench GUI you installed in the previous unit to run the user and database setup script. This is the same script you have seen in previous deployments:

Coding Events API MySQL database setup script
CREATE DATABASE coding_events;
CREATE USER 'coding_events'@'localhost' IDENTIFIED BY 'launchcode';
GRANT ALL PRIVILEGES ON coding_events.* TO 'coding_events'@'localhost';
FLUSH PRIVILEGES;

First open the MySQL Workbench application by searching for it in your taskbar:

Windows search for MySQL Workbench application

Then log in to your local server instance:

MySQL Workbench log in to local server instance

In the script area paste in the setup script from above:

MySQL Workbench paste in setup script

You can run the script using the lightning icon, ctrl+shift+enter or using the menu option at the top:

MySQL Workbench paste in setup script

You should then see a success output from the executed script like the image below:

MySQL Workbench paste in setup script

7.6.1.2. Set Up Local Secrets Manager

Recall that the Key vault that provides the database connection string, ConnectionStrings--Default, to the API is only used in the deployed Production environment.

When working locally, in the Development environment, your API will expect the default connection string to be available via the dotnet user-secrets tool. Refer to the previous chapter for a refresher on how to use this tool.

Warning

The syntax for local secret names is slightly different than what you have used for the Key vault. You will need to use ConnectionStrings:Default as the name of the local secret.

7.6.1.3. Update the Coding Events API

Warning

Before continuing make sure you are working from inside your forked repo directory on the 3-aadb2c branch.

In the appsettings.json project configuration file you will notice some familiar fields as well as a few new ones:

coding-events-api/CodingEventsAPI/appsettings.json
{
   "Logging": {
      "LogLevel": {
         "Default": "Information",
         "Microsoft": "Warning",
         "Microsoft.Hosting.Lifetime": "Information"
      }
   },
   "AllowedHosts": "*",
   "ServerOrigin": "",
   "KeyVaultName": "",
   "JWTOptions": {
      "Audience": "",
      "MetadataAddress": "",
      "RequireHttpsMetadata": true,
      "TokenValidationParameters": {
         "ValidateIssuer": true,
         "ValidateAudience": true,
         "ValidateLifetime": true,
         "ValidateIssuerSigningKey": true
      }
   }
}

To complete this studio you will need to update the following fields before deploying the API:

  • KeyVaultName: populate this field after provisioning your resources used in the deployment
  • ServerOrigin: a new field (discussed below)
  • JWTOptions: a new object field (discussed below)

7.6.1.3.1. ServerOrigin

The ServerOrigin field is used to define the origin of a server. The API has been configured to use this origin for creating resource links (for actions or relations to other resources). The term origin is defined by where the server is hosted and is comprised of:

Locally, your API ServerOrigin will be:

  • https://localhost:5001 (as seen in the appsettings.Development.json file).

However, after you deploy the API the ServerOrigin will need to be updated to reference the new location it is hosted from (the host VM’s public IP address):

  • https://<public IP> (where port 443 is implied by the https protocol in the origin)

7.6.1.3.2. JWTOptions

The JWTOptions are used to configure the JWT authentication middleware used by the API to validate the access tokens it receives. The nested TokenValidationParameters object set the boolean flags for controlling which claims in the token should be validated:

  • the issuer is your AADB2C tenant
  • the audience is the client ID for the correct registered application
  • the token is not expired
  • the token was signed using your AADB2C tenant signing key (which it automatically retrieves from the metadata document)

The two fields within the JWTOptions object entry that you will need to update are:

  • MetadataAddress: the URL of the JSON metadata document that describes the OIDC capabilities and endpoints for your AADB2C service
  • Audience: the application ID (client ID) of the intended audience for the token.

You may need to refer to your notes or previous walkthroughs to get these values.

Tip

Be careful with the Audience field. Consider which registered application client ID is appropriate, that of your Postman client application or of the Coding Events API. If the incorrect client ID is used you will receive a 401 response from the API.

Hint – look at the claims on the access token from the previous walkthrough. One of these client IDs refers to the authorized party while the other is the audience you are after.

7.6.2. Run Locally

7.6.2.1. Checklist

  • set up your coding_events database locally
  • update the AADB2C fields (JWTOptions) of your appsettings.json file
  • request a valid access token (refer to the previous walkthrough for a refresher on this process)

7.6.2.2. Viewing Documentation

The API serves documentation from the Swagger UI page at the root of the server. This time you will notice that the endpoints have been separated into the respective Roles (RBAC) and Attributes (ABAC) used for authorization of requests. Although you will be using Postman to issue requests, the Swagger UI is a helpful resource for exploring the endpoints and resource schemas.

Swagger UI for final version of Coding Events API

7.6.2.3. Make Requests to Protected Endpoints

Before you deploy the API you should practice making a few requests to ensure that you have configured everything properly. It is much easier to debug and fix issues locally than wasting time and resources troubleshooting a deployed application.

For this step make sure the API is listening on https://localhost:5001 (to match the pre-configured baseUrl variable in the Postman collection)

After getting everything running make requests to the following endpoints:

  • POST /api/events
  • POST /api/tags
  • PUT /api/events/{codingEventId}/tags/{tagId}
  • DELETE /api/events/{codingEventId}

7.6.3. Limited Guidance: API Deployment

The majority of this deployment will be familiar to you based on your previous learning. However, the setup scripts will be new to you.

The scripts will be responsible for:

  • configure-vm.sh: configures the runtime environment for the API, nearly identical to the script you wrote in your previous deployment
  • configure-ssl.sh: installs and configures the NGINX web server and provisions a self-signed certificate for serving the API over a secure connection
  • deliver-deploy.sh: delivers and deploys Coding Events API as a background service running in the VM

7.6.3.1. Provision Resources

For this deployment you will need to provision the same resources as you did in the previous studio. Configuring these resources will be similar as well, with the exception of the three new scripts that must be executed using the RunCommand console.

Rather than creating a new resource group you should provision and configure the VM and Key vault within the adb2c-deploy-rg group created in the first AADB2C walkthrough.

Note

After setting up the VM and Key vault you will need to update the entries in your appsettings.json.

Don’t forget to commit and push these changes before deploying!

7.6.3.2. Configuration Scripts

Aside from the first script the other two will appear foreign to you. Even if you don’t believe that currently you are capable of writing them, you will likely surprise yourself with how much you are able understand.

Take some time to look over and discuss these scripts with your classmates and TA to decipher what they are doing. We will explore these in more detail in the upcoming scripting lessons.

Warning

You must run these scripts in the following order:

  1. configure-vm.sh
  2. configure-ssl.sh
  3. deliver-deploy.sh

7.6.3.2.1. Configure the VM

The configure-vm.sh script should look familiar to you based on the script you wrote in the previous deployment.

7.6.3.2.2. Configure Nginx for TLS Termination

As mentioned previously, AADB2C requires a secure connection for authenticating and requesting an access token. In order to support the https encrypted connection a Web Server uses a SSL certificate to perform something called a TLS handshake.

Tip

The Secure Socket Layer (SSL) protocol was succeeded by the more recent Transport Layer Security (TLS) protocol. Although TLS is what is used in modern development, the term SSL was ubiquitous for so long that SSL and TLS are often used interchangeably.

If you are curious this TLS/SSL article provides a great breakdown of the history behind these protocols and terms.

In a production environment you would fully utilize Public Key Infrastructure (PKI) to ensure the security of communication between your applications and their users. However, delving into these topics would require an entire course dedicated to exploring them!

Because we are in a learning environment we will relax our security considerations and use a self-signed certificate instead. This certificate is similar to the one you set up when first running a dotnet project locally on your machine.

While all of this is complex there are numerous tools available for simplifying the process. We will narrow the scope of our learning by abstracting this process behind the configure-ssl.sh script that utilizes the following tools:

  • openssl: a CLI tool that will create the self-signed certificate
  • nginx: a web server that will perform TLS/SSL termination using the self-signed certificate

Note

In production settings on Linux servers NGINX is the standard because of it’s advanced features and performance.

In an upcoming lesson we will deploy the API to Windows Server and use the IIS web server instead of NGINX. On Windows server machines the Microsoft IIS web server is the clear choice because of it’s native Windows and .NET integrations.

For now all you need to understand is that within the VM there will be two Web Servers, NGINX and the built-in Kestrel Web Server of the Coding Events API. The NGINX Web Server acts as a reverse proxy (a request middle-man) for requests to and from the API.

As the middle-man, NGINX is responsible for decrypting incoming requests and encrypting outgoing responses from the API. Effectively, requests go through NGINX to reach the API.

7.6.3.2.3. Deliver & Deploy the Coding Events API

The final script will configure the VM to run the Coding Events API as a Systemd unit instead of executing the API manually in the foreground as you have done before. Aside from how the API artifact is executed, the majority of the script (cloning and publishing) should look familiar to you.

Note

Configuring an application to run as a background service provides many benefits including:

  • the service can be configured to start automatically when the VM starts up
  • the service runs in the background (does not attach to the Terminal)
  • the service and any output logs can be easily monitored using systemctl
  • the service can be automatically restarted if it fails

The deliver-deploy.sh script will require you to fill in the following two environment variables used in the delivery step:

  • github_username: your username used to create the URL of your forked repo
  • solution_branch: the updated 3-aadb2c branch

This file creates a Systemd Unit file which describes the API service. In addition, it will set up a new user account: api-user. This service account can not be logged into like a traditional user account such as student.

As a security best practice, the api-user account is used exclusively to execute the API artifact that starts the underlying dotnet process of the background service.

Note

The script sets up the permissions that restrict all users except root and the api-user service account from reading, writing or executing the published API artifact.

By compartmentalizing the service account from the login account (student). An attacker who is able to enter the VM as the student user will be restricted from controlling the API service or accessing its related files.

7.6.4. Gotchas

7.6.4.1. Expired or Missing Access Token

If your request fails due to a missing access token you will, expectedly, receive a 401 (failed authentication) response:

Postman failed authentication due to missing token

Similarly if your access token has expired you will receive a 401 response indicating this failure in the WWW-Authenticate (challenge) header.

Postman failed authentication due to expired token

Refer to your notes or the previous walkthrough for a solution to this issue.

7.6.4.2. Incorrect Configuration in appsettings.json

The JWT authentication middleware is fickle. As it should be – there is no margin for error in the security space of a project. In addition to the JWT settings the API will crash if the Key vault and origin values are not configured correctly.

Make sure that all of the following fields are updated before deploying the API:

  • ServerOrigin: available after provisioning your Azure VM
  • KeyVaultName: available after provisioning your Azure Key vault
  • JWTOptions:Audience: available in the AADB2C tenant, updated in the local steps
  • JWTOptions:MetadataAddress: available in the AADB2C tenant, updated in the local steps

7.6.4.3. Opening the Correct Port

For this deployment the API will be served over https. For security reasons AADB2C does not support authentication over insecure connections. You will need to open the correct port for your deployed API to function properly.

7.6.5. Deliverable

At the end of this setup studio you will need to provide your TA with the public IP address of your fully functional deployed API.