How to scaffold entity type classes and DbContext based on an existing database schema

Install these NuGet packages in the project:

  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFramework.SqlServer

Create a folder called “Models” at the root of the project.

Run this command in the package manager console of Visual Studio (make sure you have the correct startup project selected):

Scaffold-DbContext "Data Source=<{SERVER_NAME};Initial Catalog={DATABASE_NAME};Persist Security Info=True;User ID={USERNAME};Password={PASSWORD}" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

Source: https://docs.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=vs

How to enable TLS endpoint to a Azure Container Instance container group

This article describes the process for enabling a TLS endpoint for an application deployed to an Azure Container Instance. At the time of this writing, ACI does not provide an out-of-the-box solution for TLS/SSL, so Microsoft recommends setting up a separate container with a Nginx (“engine-x”) web server. This approach uses a sidecar pattern to allow TLS connections for your application without changing your application code. Nginx is a web server that can be used as a reverse proxy, load balancer, and HTTP cache. It also has support for TLS/SSL, URL rewriting, and redirection.

1.First obtain a certificate. This can be a self-signed certificate for non-production environments. Production environments will require a certificate issued by a trusted authority (CA). You will need the .crt and .key files from the certificate. The .crt file is the public part of the SSL certificate. Do not commit the .key file in source control or display its contents anywhere in plain text. This is the private key and therefore highly sensitive information.

2. Save the .crt and .key files somewhere in your local file system.

3. Create a configuration file for Nginx to use TLS. Start by copying the following text into a new file named nginx.conf. Commit this file to source control. It doesn’t really matter where you put it in the repository.

# Configuration file for Nginx to use TLS
# https://docs.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl#create-nginx-configuration-file

# Run as a less privileged user for security reasons.
user nginx;

worker_processes auto;

events {
  worker_connections 1024;
}

pid        /var/run/nginx.pid;

http {

    # Redirect to https, using 307 instead of 301 to preserve post data

    server {
        listen [::]:443 ssl;
        listen 443 ssl; # the server will only accept SSL connections on Port 443
        
        server_name _;

        # Protect against the BEAST attack by not using SSLv3 at all. If you need to support older browsers (IE6) you may need to add
        # SSLv3 to the list of protocols below.
        ssl_protocols              TLSv1.2;

        # Ciphers set to best allow protection from Beast, while providing forwarding secrecy, as defined by Mozilla - https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx
        ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
        ssl_prefer_server_ciphers  on;

        # Optimize TLS/SSL by caching session parameters for 10 minutes. This cuts down on the number of expensive TLS/SSL handshakes.
        # The handshake is the most CPU-intensive operation, and by default it is re-negotiated on every new/parallel connection.
        # By enabling a cache (of type "shared between all Nginx workers"), we tell the client to re-use the already negotiated state.
        # Further optimization can be achieved by raising keepalive_timeout, but that shouldn't be done unless you serve primarily HTTPS.
        ssl_session_cache    shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions
        ssl_session_timeout  24h;


        # Use a higher keepalive timeout to reduce the need for repeated handshakes
        keepalive_timeout 300; # up from 75 secs default

        # remember the certificate for a year and automatically connect to HTTPS
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';

        ssl_certificate      /etc/nginx/ssl.crt;
        ssl_certificate_key  /etc/nginx/ssl.key;

        location / {
            proxy_pass http://localhost:80; # TODO: replace port if app listens on port other than 80

            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
    }

    server {
        listen 80; # This instructs the system to catch all HTTP traffic on Port 80
        return 307 https://$host$request_uri; # This is a short code to specify the HTTPS version of whatever the user has typed
    }
}

The first server block allows the server to only accept SSL connections on port 443. The second server block (or rule) instructs the web server to automatically redirect server connections on port 80 (HTTP) to use HTTPS.

4. In location, be sure to set proxy_pass with the correct port for your app. In this example, we set it to port 80. Nginx will listen for traffic on port 443 and redirect it to your internal app listening on port 80.

5. The next step is to Base64-encode the Nginx configuration file, the TLS/SSL certificate, and the TLS key. Run the commands below in a shell prompt replacing for the name of your .crt and .key files (or rename your cert and key files to ssl.crt and ssl.key)

cat nginx.conf | base64 > base64-nginx.conf
cat ssl.crt | base64 > base64-ssl.crt
cat ssl.key | base64 > base64-ssl.key

6. Update the YAML file or ARM template by:

Opening port 443:

Declaring the Nginx container:

Declaring a volume of type secret and call it “nginx-config” in the volumes node. Paste in the Base64-encoded values for ssl.crt, ssl.key, and nginx.conf generated previously. Do not include the ssl.key in plain text. Instead, consider injecting it through a pipeline runtime variable.

Caption: supplying the Base64-encoded values for the certificate and nginx.conf files as a secret volume

7. Deploy the container group. Test the settings by issuing a HTTP request with Postman. You should see the request redirected to HTTPS and/or it will return an error saying that HTTP requests are not allowed.

8. Confirm the certificate is installed. Open a CLI prompt in the nginx container. Change directory to /etc/nginx and you should see the certificates installed there.

If you deploy your container group in an Azure virtual network, you can consider other options to enable a TLS endpoint for a backend container instance, including:

  • Azure Functions Proxies
  • Azure API Management
  • Azure Application Gateway

Sources:

https://docs.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl

https://docs.microsoft.com/en-us/azure/container-instances/container-instances-quickstart-template

https://docs.microsoft.com/en-us/azure/container-instances/container-instances-volume-secret

How to install a trusted certificate in a Docker container

How to install a trusted certificate in a Docker container

This document describes the process of installing a certificate inside a Docker container’s trusted root certificate store.

  1. The first step is to load the .crt file into the container’s file system. Have in mind that .crt is the public part of an SSL certificate. You should never store sensitive information, secrets and passwords alike, in a container or in a source control repository.
  2. Add the .crt file in the same folder as your Dockerfile
  3. Make sure the .crt file is included in your build’s output directory (e.g., the ‘bin’ folder). In Visual Studio, you can do this by right-clicking the file and enabling the “Copy to Output Directory” property.
  4. Add these lines to the bottom of your Dockerfile but before the ENTRYPOINT.
    1. COPY my-cert.crt usr/local/share/ca-certificates/my-cert.crt
    2. RUN chmod 644 /usr/local/share/ca-certificates/my-cert.crt && update-ca-certificates
  5. The COPY statement adds the certificate to the container’s trusted root certificate store which is located in usr/local/share/ca-certificates. If the certificate is not copied or if you get a “file not found” error, make sure the source path is relative to your application’s build context and the target path to the WORKDIR.
  6. The RUN statement gives read and write access to the owner in the file and updates the trusted certificates.
  7. Confirm the certificate was successfully installed by inspecting the etc/ssl/certs folder inside of the container. Your certificate should appear here with a .pem extension.

And that’s it! That’s all you should need to install a trusted certificate. You can test if the certificate was configured correctly by curling the target server:

curl --verbose https://<host>:<port>

If the connection is successful and verified by the root certificate, you should see a “ssl certificate verify ok” message in the response.

How to read appsettings.json from PowerShell in .NET

In this example, I create a PowerShell script that authenticates to a container registry in Azure (ACR) using an access token provided in the appsettings.json configuration file.


# Use ConvertFrom-Json to access the appsettings.json as an object (requires PowerShell 7+)
$appsettings = Get-Content -Path appsettings.json | ConvertFrom-Json
# get the access token
$acrpwd = $appsettings.AzureContainerRegistry.AccessToken
# run docker login by hardcoding the username provided by the access token* and suppling the password through stdin which is more secure
echo $acrpwd | docker login -u myacr-azurecr-io-token --password-stdin myacr.azurecr.io

*when I created the access token in ACR, Azure generated a username along with the access token. The username is what you see above as myacr-aurecr-io-token

Pulling images from an Azure Container Registry in Docker Compose

Step 1: obtain credentials from ACR

1. In the Azure portal, navigate to your existing container registry
2. Go to Access Keys
3. Create an access key if there isn’t one yet
4. Copy the username and password that was generated. These are the credentials you will use to authenticate with ACR

Step 2: docker login

1. From a terminal window, run docker login using the username and password provided by ACR in step 1. If there are cached credentials, you might want to run first ‘docker logout’ and remove any existing credentials stored in KeyChain (MacOS), WinCred (Windows), or pass (Linux). By default, Docker looks for the native binary on each platform for storing credentials

Step 3: docker compose

1. Navigate to Azure portal > > Repositories > and click on the latest image tag. From here you will be able to copy the URL to pull down the image
2. Add the image in Docker Compose. For example:

services:
notificationservice:
image: myacr.azurecr.io/ordersapi:721

3. Run ‘docker compose up’ at this point. If the project fails to pull the image, try running a ‘docker pull’ command from a separate terminal and make sure you are able to pull the image using the credentials supplied by ACR

How to securely store and load secrets in .NET apps with Azure Key Vault (using a client secret)

This document describes the process of using Key Vault for storing and loading secrets inside your .NET Core application.

Step 1: Register your application in Azure Active Directory

You will register the application to generate a ClientID and Client Secret so your application can have permissions to access the Key Vault resource.

a. Navigate to portal.azure.com and access the Azure Active Directory page (requires AD Tenant Admin permissions)
b. Navigate to the App Registrations page
c. Select New Registration
d. In the  Nam e section, enter a meaningful application name that will be displayed to users of the app
e. In the  Supported account types  section, select  Accounts in this organizational directory only ({tenant name})
f. Select  Register  to create the application
g. On the app  Overview  page, find the  Application (client) ID  value and record it for later. You’ll need it to configure the Visual Studio configuration file for this project
h. From the  Certificates & secrets  page, choose  New client secret
i. Type a key description
j. Select a key duration of either  12 months, 24 months, or  Custom
k. When you press the Add button, the key value will be displayed, copy, and save the value in a safe location
l. You’ll need this key later to configure the project in Visual Studio. This key value will not be displayed again, nor retrievable by any other means, so record it as soon as it is visible from the Azure portal.

Step 2: Create the Key Vault resource in Azure

a. Create Key Vault using the convention az{region}{env}{appName}-kv. azuse2devmyapp-kv, for example
b. Go to Access Policies in Key Vault
c. Click Add Access Policy
d. Click Secrets Management from the template
e. Click Select principal
f. Select the registered app in step 1

Step 3: Add the secrets

a. Navigate to the Secrets page in your Key Vault instance
b. Click Generate/Import
c. Enter a name and value. Use a double dash in the key name to create a hierarchy with the keys. For example, if I enter the key name AzureTableStorage–ConnectionString, it would be equivalent to the key declaration below in appSettings json:

AzureTableStorage: {
ConnectionString: “<>”
}

Step 4: Client App Code changes

a. Install the Nuget packages Azure.Identity, Azure.Extensions.AspNetCore.Configuration.Secrets, and Azure.Security.KeyVault.Secrets
b. Add the following to your appSettings.json file:

“KeyVault”: {
“Url”: “https://azeus2myapp-kv.vault.azure.net/&#8221;,
“ClientSecretId”: “”
“TenantId”: “”
“ClientId”: “”
}

Url: copy this from the Overview page of your Key Vault in Azure
ClientSecretId: the secret generated for your app in step 1
TenantId: the Active Directory tenant ID used to register your app in step 1
ClientId: the unique client ID generated for your app in step 1

c. Update IHostBuilder CreateHostBuilder():

Picture1

d. This is all you need to do to configure your app with Key Vault. In the example below, the HostName is retrieved from configuration[“EventBus:HostName”]. It will look in Key Vault for a key with name EventBus–HostName (notice the usage of double dash to indicate a hierarchy). It will override the EventBus:HostName value you have in your local appSettings.json with the value created in Key Vault.

Picture2

Fixing “Unable to load project templates. Directory not empty.” error in Visual Studio for Mac

You have to clear the Visual Studio template folder.

  1. In your Mac, navigate to C:\Users\<username>\.templateengine\Visual Studio folder. If you don’t see .templateengine, it may be hidden, so press Command + Shift + . to display hidden folders.
  2. In this folder, you should see version numbers like 7.0 or 8.0. Rename these directories or delete them.
  3. You should now be able to add projects and files to your solution again.

Securing a .NET API using Bearer Authentication, JSON Web Tokens, and Azure Active Directory (AAD)

The scenario is a sample daemon app (console) that uses the Microsoft Identity Platform to access the data from a protected Web API, in a non-interactive process. The console application will:

  • Acquire an access token from the Microsoft Identity Platform as an application (no user interaction)
  • Access the secure REST API to get or modify a resource

Step 1: Register the resource API in AAD

  1. Navigate to portal.azure.com and access the Azure Active Directory page (requires permissions)
  2. Navigate to the App Registrations page
  3. Select New Registration
  4. In the Name section, enter a meaningful application name that will be displayed to users of the app, for example TodoList-webapi-daemon-v2
  5. Leave Supported account types on the default setting of Accounts in this organizational directory only
  6. Leave the redirect URI empty
  7. Select Register
  8. On the app Overview page, find the Application (client) ID and Tenant ID values and record them for later. You’ll need it to configure the Visual Studio configuration file for the project
  9. Select the Expose an API section 
  10. Use the ‘Set’ button to generate the default AppID URI in the form of api://<web api client id>
  11. Click Save
  12. Now you will expose an application role by updating the API’s appRoles section of the application manifest to specify the type of application role(s) that can access this secure API

Your app registration must expose at least one scope or one application role

  • Scopes are exposed by web APIs that are called on behalf of a user
  • Application roles are exposed by web APIs called by daemon applications (that calls your web API on their own behalf)
  1. Select the Manifest section
    1. Update the appRoles section with the JSON snippet below. Leave the allowedMemberTypes to Application only. You can add multiple appRoles to this section, we need only one, although if you do decide to add some additional roles you’ll need to ensure that the “id” attribute is a unique GUID.

{

  …

    “appRoles”: [

        {

            “allowedMemberTypes”: [

                “Application”

            ],

            “description”: “Daemon apps in this role can consume the web api.”,

            “displayName”: “DaemonAppRole”,

            “id”: “<GENERATE AND PASTE A UNIQUE GUID HERE>”,

            “isEnabled”: true,

            “value”: “DaemonAppRole”

        }

    ],

 …

}

  • In the resource API’s appSettings.json file, put these values:
    • ResourceId: the secured API’s application ID URI created when registering the application with the format “api://APP-ID”
    • TenantId: the unique identifier of the active directory being used. The one used in the sample below is merely for demonstration
    • Instance: the Microsoft Identity Platform URL

“AAD”: { 

              “ResourceId”: “api://6752d64d-d461-416f-b739-c66a42fc54f7”,

              “TenantId”: “793b88f3-aea8-43a2-babb-0bdf257265ee”

              “Instance”: “https://login.microsoftonline.com/”

            }

*The steps above will soon be available to complete through the Microsoft Graph API endpoints. This is currently in beta phase, and it’s not recommended for production applications but it’s worth revisiting it in the future to speed up the process. 

Step 2: Register the client app (daemon-console) in AAD

  1. Navigate to portal.azure.com and access the Azure Active Directory page (requires AD Tenant Admin permissions)
  2. Navigate to the App Registrations page
  3. Select New Registration
  4. In the Name section, enter a meaningful application name that will be displayed to users of the app, for example daemon-console-v2.
  5. In the Supported account types section, select Accounts in this organizational directory only ({tenant name}).
  6. Select Register to create the application.
  7. On the app Overview page, find the Application (client) ID value and record it for later. You’ll need it to configure the Visual Studio configuration file for this project. There’s no need to set up an Application ID URI like you did with the resource API since this is only the client application
  8. From the Certificates & secrets page, in the Client secrets section, choose New client secret
    1. Type a key description (of instance app secret),
    1. Select a key duration of either 12 months, 24 months, or Custom.
    1. When you press the Add button, the key value will be displayed, copy, and save the value in a safe location.
    1. You’ll need this key later to configure the project in Visual Studio. This key value will not be displayed again, nor retrievable by any other means, so record it as soon as it is visible from the Azure portal.
  9. In the list of pages for the app, select API permissions
  10. Click the Add a permission button 
  11. Ensure that the My APIs tab is selected
  12. Select the API created in the previous step
  13. In the Application permissions section, ensure that the right permissions are checked: DaemonAppRole
  14. Select the Add permissions button
  15. Click the Grant admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all account in the tenant. You need to be an Azure AD tenant admin to do this.
  16. In the client app’s appSettings.json, put these values:

“AzureADD”: {

    “Instance”: “https://login.microsoftonline.com/&#8221;,

    “TenantId”: “793b88f3-aea8-43a2-babb-0bdf257265ee”,

    “ClientId”: “838f6866-0814-47a4-b49d-d46f2ae63afc”,

    “ClientSecret”: “”,

    “BaseAddress”: “https://localhost:64788/notifications&#8221;,

    “ResourceId”: “api://6752d64d-d461-416f-b739-c66a42fc54f7/.default”

  }

  • Instance: the Microsoft Identity Platform URL
  • TenantId: the unique identifier of the active directory being used. It should be the same for both resource and client applications. The one used in the sample is merely for demonstration
  • ClientId: the id of the daemon app wanting to access the resource API
  • ClientSecret: the secret generated for the daemon app in the previous steps. It must not be stored in plain text in appSettings.json. Instead, the secret should be stored and retrieved from a secure source, like iVault.
  • BaseAddress: the resource API’s endpoint address
  • ResourceId: the application Id URI from the resource API created in step 1

Step 3: Resource API Code Changes

  • Add the Microsoft.Identity.Web NuGet package to the project
  • Add the Microsoft.AspNetCore.Authentication.JwtBearer NuGet package to the project
  • Startup.cs 

ConfigureServices(IServiceCollection services) {

   // …

   services

.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

             .AddMicrosoftIdentityWebApi(Configuration, “AzureAd”);

}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

{

   app.UseAuthentication();

      app.UseAuthorization();

}

  • Add the [Authorize] attribute to the controller

So with that our API is now locked down with Bearer Authentication

Step 4: Client (daemon console) Code Changes

  • Install the Microsoft.Identity.Client NuGet package
  • Create the MSAL confidential client application
  • Define the scopes
  • Acquire the token
  • Call the API with the access token as a bearer token

And that’s it. It’s simple right? RIGHT?

A Learning Path for Software Engineers

A Learning Path for Software Engineers

There’s no denying that the amount of skills required in software engineering can feel overwhelming. With the fast advancement in technology, it seems that everyday there’s a new library, framework, programming paradigm, or programming language to be learned. It’s not uncommon for job postings to include more than a dozen technical requirements, even for entry-level positions. This can seem intimidating, especially if you are new to the field. In order to help navigate through this landscape, I’ve compiled a list of skills I would learn if I had to start over. A lot has changed in the 12 years since I learned how to program so I’ve tried to keep this list relevant to the skills that are in demand today. I have also ordered the skills more or less in the order in which I would learn them. This is not a comprehensive list. It’s intended as a starting point. Each skill is important enough to have made it into the list and you will most certainly encounter them in any project you’re involved with.

Entry Level

  • Must-know
    • HTML
    • CSS
    • JavaScript
    • OOP Principles (abstraction, encapsulation, inheritance, and polymorphism)
      • Make sure you understand what each of these concepts mean. I would recommend writing some code examples demonstrating each principle in practice.
    • SQL querying
    • One backend language such as C#, Java, or Python
      • One tip. Being skilled at any of these languages will give you endless opportunities. If you have no preference, pick C#. The .NET community is amazing!
  • Bonus
    • MVC pattern
      • It appears this pattern is beginning to lose popularity but it’s still quite popular (42%) according to a recent survey. Not only that, it will also teach you about separation of concerns.
    • Data Structures
    • Git
  • Learning Resources
    • freeCodeCamp
    • CodeAcademy
    • Edx or Coursera
    • CodeWithMosh
    • For data structures, it’s good to know what are the main data structures and how they are implemented. The best way to learn this is to implement them yourself (stacks, queues, lists, dictionaries, and deques). Almost any freely available course on DS will do, but I would recommend this one on Coursera: https://www.coursera.org/learn/algorithms-part1

Junior Level

Senior Level

I believe that once you’re about half-way through the senior must-knows list, you start focusing more on perfecting your craft, expanding your knowledge to new frontiers, going deeper into other subjects you are familiar with, or tinkering with the cool new framework in the block. The world is your oyster!

Connect to your Git repos in Azure DevOps with SSH on a Mac

In a terminal:

  1. Run ssh-keygen -C "contoso@domain.com"
  2. Enter the file path in which to save the key or press Enter to use the default path (C:/Users/<username>)
  3. Enter a new passphrase and press Enter
  4. Enter the same passphrase and press Enter. The SSH key is now created
  5. In Finder, go to C:/Users/<username>/.ssh folder. If you can’t see this folder press Command + Shift + . to display hidden items and folders
  6. Open id_rsa.pub and copy the public key
  7. In Azure DevOps, go to User Settings > SSH Public Keys
  8. Click + New Key
  9. Add a label to the key and paste the public key
  10. Save
  11. In a Mac terminal, test the connection by running the following command: ssh -T git@ssh.dev.azure.com.
  12. Type ‘yes’ when prompted if you want to continue to connect
  13. If everything is working correctly, you’ll receive a response which says: remote: Shell access is not supported.
  14. In Azure DevOps repository, go to Repos > Files > Clone
  15. Select the SSH command line option and copy the clone URL
  16. In a Mac terminal, type git clone git@ssh.your.repository.url
  17. Enter your SSH public key passphrase

Git will still require you to enter your passphrase every time you pull or push to the repository. You can avoid this by adding the SSH key to the ssh-agent. See instructions here: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#adding-your-ssh-key-to-the-ssh-agent