DÉVELOPPER, DÉPLOYER ET SECURISER LES ACCÈS AUX RESSOURCES GRÂCE À AZURE AD

Développer, déployer et sécuriser les accès aux ressources grâce à azure AD

Azure Active Directory (AAD) est un outil précieux pour garantir la sécurité d'une solution SaaS hébergée dans Azure. Au-delà d’offrir une gestion centralisée des comptes utilisateurs, il permet de sécuriser les communications entre les ressources sans exposer des informations sensibles. En suivant les étapes de ce guide, vous pourrez développer, déployer et sécuriser efficacement vos ressources avec Azure AD. A vos marques, prêt, sécurisez ! 

Etape 1 : Développer une application


Afin de rester dans l’écosystème Microsoft, nous optons ici pour l’application Blazor WebAssembly, qui utilise Blazor Wasm au niveau front et une API .NET au niveau back. La sécurité des échanges sera assurée grâce à l'utilisation d'un token délivré par Azure AD en utilisant le protocole OpenID Connect dérivé d'OAuth 2.0.

Pour mettre en place cette sécurité, il est nécessaire d'ajouter dans Azure AD les entrées appropriées. Cela implique d'inscrire deux applications : une application serveur et une application client, et de les interconnecter pour spécifier que le client est autorisé à utiliser le serveur. Vous pouvez suivre la documentation de Microsoft pour implémenter ces applications dans Azure AD : https://learn.microsoft.com/fr-fr/aspnet/core/blazor/security/webassembly/hosted-with-azure-active-directory?view=aspnetcore-7.0

Une fois la procédure terminée, cette commande générera le projet avec les informations adéquates :

dotnet new blazorwasm -au SingleOrg --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {APP NAME} --tenant-id "{TENANT ID}"

Après avoir lancé cette nouvelle application, vous serez redirigé vers la page de connexion Azure AD pour entrer vos identifiants.

En parcourant l’application template de Blazor Wasm, vous trouverez une liste dans la page « fetch data », alimentée par un appel à l’API back dont les données sont stockées de manière statique dans l’application. Il est ainsi conseillé d'utiliser une base de données. Nous utiliserons ici une base Azure CosmosDb (Base NoSQL proposé par Azure : https://learn.microsoft.com/en-us/azure/cosmos-db/introduction). Cependant, sachez que la sécurisation de la base de données s’effectue de la même manière, quelle que soit la base choisie (Cosmos, SQL Server ou encore PostgreSQL).

Afin de relier la base de données à votre application, il est essentiel d’installer le logiciel CosmosDb Emulator et d'ajouter, dans notre solution, le package Nuget approprié :

dotnet add package Microsoft.Azure.Cosmos

Pour instancier la connexion avec CosmosDb, vous devrez vous référer aux informations de connexion accessibles sur la page d’accueil au lancement de l’émulateur : https://localhost:8081/_explorer/index.html

Il est possible d'utiliser la chaîne de connexion, mais elle ne sera pas nécessaire pour les prochaines étapes. Il est préférable d’utiliser un modèle à inclure dans le fichier « appsettings.json » :

  "CosmosDb": {

    "Account": "https://localhost:8081/",

    "Key": "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",

    "DatabaseName": "",

    "ContainerName": "",

    "PartitionKey": "/id"

  }

Bon à savoir : la clé est universelle et reste inchangée, quel que soit l’ordinateur sur lequel vous installez l’émulateur.

Pour une gestion plus efficace, vous pouvez créer un modèle C# qui va effectuer automatiquement un « binding » entre votre configuration et l'application lors de son démarrage, en utilisant le pattern "Options".:

public class CosmosDbConfigurationOptions

{

    public string Account { get; set; }

    public string Key { get; set; }

    public string DatabaseName { get; set; }

    public string ContainerName { get; set; }

    public string PartitionKey { get; set; }

}

Dans votre fichier « program.cs » vous pouvez ajouter les informations suivantes :

builder.Services.Configure<CosmosDbConfigurationOptions>(builder.Configuration.GetSection("CosmosDb"));

 

Ainsi, dans le constructeur des méthodes et grâce à l’injection de dépendance, vous récupérerez les informations de connexion par l’intermédiaire de « IOptions<T> »  :

public WeatherForecastController(ILogger<WeatherForecastController> logger, IOptions<CosmosDbConfigurationOptions> cosmosDbConfigurationOptions)

    {

        _logger = logger;

        _cosmosDbConfigurationOptions = cosmosDbConfigurationOptions;

    }

 

Vous pouvez à présent construire le client Cosmos et récupérer le container cible au sein duquel sont stockées les données :

var (account, key, databaseName, containerName, partitionKey) = _cosmosDbConfigurationOptions.Value;

 

using var cosmosClient = new CosmosClient(account,

            key);

 

var database = await cosmosClient.CreateDatabaseIfNotExistsAsync(databaseName);

 

await database.Database.CreateContainerIfNotExistsAsync(containerName,partitionKey);

 

var container = cosmosClient.GetContainer(databaseName, containerName);

 

Réalisez désormais une requête à la base de données et extraire le résultat :

 

var query = container.GetItemQueryIterator<WeatherForecast>();

var result = new List<WeatherForecast>();

while (query.HasMoreResults)

{

var current = await query.ReadNextAsync();

result.AddRange(current.Resource);

}

 

Pour une application destinée à être utilisée en production, je vous recommande de suivre les bonnes pratiques de la "Clean Architecture" en créant un projet « repository »..

Après avoir démarré l'application, vous constaterez que la liste est vide : vous pouvez à présent ajouter vos données. Une fois l’opération réalisée, nous pouvons procéder à l’étape suivante :  permettre l’accès à votre application de manière sécurisée, avec la création de ressources sur Azure !

 

Etape 2 : Création des ressources Azure

 

Plusieurs méthodes s’offrent à vous : vous avez la possibilité de créer les ressources manuellement à l’aide du portail, d’utiliser les templates ARM ou d’opter pour un outil de gestion de l'infrastructure en code tel que Terraform ou Pulumi. Pour notre démonstration, nous utiliserons le "cloud shell" directement dans le portail Azure.
 


Nous aurons besoin d'un groupe de ressources, d'un service d'application web et d'une instance CosmosDb. Pour créer le groupe de ressources, vous devrez taper la commande suivante :

az group create --name rg-programmez --location francecentral

Le groupe de ressource est ici situé en France, mais vous pouvez afficher les localisations valides à partir de la commande suivante :

az account list-locations --query "[*].name"

 

Pour créer le service d'application web, vous aurez deux étapes à suivre : la première consiste à créer l'application plan, qui représente le serveur qui hébergera l'application web :

az appservice plan create -g rg-programmez -n plan-programmez --is-linux

Dans cette commande, le -g indique le groupe de ressource cible. Il sera réutilisé à chaque création de ressources.

La deuxième étape consiste à créer l’application web proprement dite :

az webapp create -g rg-programmez -p plan-programmez -n app-programmez-csa --runtime "DOTNETCORE:7.0"

Vous pouvez accéder à la liste des différents runtime en utilisant la commande suivante :

az webapp list-runtimes

Enfin, pour créer une instance CosmosDb, tapez la commande suivante :

az cosmosdb create -g rg-programmez  -n cosmos-programmez-csa --enable-free-tier

Vous avez la possibilité de bénéficier d'une instance gratuite de CosmosDb avec chaque abonnement en utilisant l'argument -enable-free-tier. Pour créer une base de données complète, je vous recommande de créer directement la base de données :

az cosmosdb database create -n cosmos-programmez-csa  -g rg-programmez  --db-name Programmez

Ainsi que le conteneur :

az cosmosdb sql container create -g rg-programmez -a cosmos-programmez-csa -d Programmez -n Programmez-container -p "/id"

Toutes les ressources sont maintenant prêtes à être déployées et utilisées !

J'ai ajouté mon trigramme "csa" à chaque nom de ressource afin de le rendre unique. Vous pourrez ici le remplacer par le vôtre.

Pour en savoir plus sur les commandes, consultez ce lien :

https://learn.microsoft.com/en-us/cli/azure/reference-index?view=azure-cli-latest.

 

Etape 3 : Le déploiement

 

Cette étape peut être réalisée avant ou après la sécurisation des accès, car elles sont indépendantes l’une de l’autre.

Pour déployer la solution, nous utiliserons la plateforme Github sur laquelle vous retrouverez le code.

Github Actions est une fonctionnalité qui permet de créer des workflows de CI/CD. Elle s’appuie sur la syntaxe YAML pour scripter les différentes commandes nécessaires pour compiler et déployer le code. Pour plus d’informations n’hésitez pas à consulter ce lien : https://docs.github.com/fr/actions/using-workflows/workflow-syntax-for-github-actions.

Le fichier YAML se divise en deux tâches distinctes : la première étape, appelée "build", consiste à récupérer le code, restaurer les packages, compiler le programme et publier un artefact de la solution. La deuxième étape, appelée "deploy", récupère cet artefact et déploie l'application directement sur Azure.

Le script de déploiement est le suivant :

name: Build and deploy Blazor app to an Azure Web App

 

env:

  AZURE_WEBAPP_NAME: app-programmez-csa    # set this to the name of your Azure Web App

  AZURE_WEBAPP_PACKAGE_PATH: '.'      # set this to the path to your web app project, defaults to the repository root

  DOTNET_VERSION: '7.0.x'                 # set this to the .NET Core version to use

  PATH_SOLUTION : 'ProgrammezAzureSecurity'

 

on:

  push:

    branches: [ "main" ]

  workflow_dispatch:

 

permissions:

  contents: read

 

jobs:

  build:

    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v3

 

      - name: Set up .NET Core

        uses: actions/setup-dotnet@v2

        with:

          dotnet-version: ${{ env.DOTNET_VERSION }}

 

      - name: Set up dependency caching for faster builds

        uses: actions/cache@v3

        with:

          path: ~/.nuget/packages

          key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}

          restore-keys: |

            ${{ runner.os }}-nuget-

      - name: Build with dotnet

        run: dotnet build ${{env.PATH_SOLUTION}}/*.sln --configuration Release

 

      - name: dotnet publish

        run: dotnet publish ${{env.PATH_SOLUTION}}/*.sln -c Release -o ${{env.DOTNET_ROOT}}/myapp

 

      - name: Upload artifact for deployment job

        uses: actions/upload-artifact@v3

        with:

          name: .net-app

          path: ${{env.DOTNET_ROOT}}/myapp

 

  deploy:

    permissions:

      contents: none

    runs-on: ubuntu-latest

    needs: build

    environment:

      name: 'Development'

      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

 

    steps:

      - name: Download artifact from build job

        uses: actions/download-artifact@v3

        with:

          name: .net-app

 

      - name: Deploy to Azure Web App

        id: deploy-to-webapp

        uses: azure/webapps-deploy@v2

        with:

          app-name: ${{ env.AZURE_WEBAPP_NAME }}

          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}

          package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}

 

Le script de déploiement contient des variables d'environnement en début de script qui facilitent la transition d'un projet à un autre. Vous pouvez également remarquer à la fin du script la variable secrets.AZURE_WEBAPP_PUBLISH_PROFILE. Github Action attend le profil de publication dans la section "secrets". Ce profil se trouve sur la Web Application dans Azure :

Il est nécessaire de copier / coller le contenu de ce profil dans un secret « Actions » de Github. Pour ce faire, rendez-vous dans les paramètres de votre projet :

Attention, le nom de la variable doit être identique à celui défini dans la section « secrets », au quel cas Github ne sera pas en mesure de récupérer le profil de l’application.

Une fois que l'application est déployée, elle peut être lancée, mais n'a pas encore accès à la base de données. C’est le sujet de notre prochain chapitre.

 

Etape 4 : Sécurisation de l’accès aux ressources

Il existe plusieurs méthodes pour sécuriser l’accès à une ressource. Tout d'abord, vous pouvez sécuriser les données sensibles telles que les mots de passe en utilisant un coffre-fort. Azure Key-Vault de Microsoft Azure offre une solution de chiffrement et de sécurisation des informations sensibles très performante.

D’autre part, vous pouvez confier la sécurité des accès à Azure AD en utilisant des identités « managées ». Cela vous permet d'éviter de transmettre des informations de connexion. (https://learn.microsoft.com/fr-fr/azure/active-directory/managed-identities-azure-resources/overview)
Pour cela, l’application web doit nécessairement disposer d’une identité. Il existe deux façons de l'obtenir : en vous connectant au portail et en accédant à la Web App :

ou en utilisant le cloud shell :

az webapp identity assign -g rg-programmez -n app-programmez-csa

Conservez précieusement votre ID pour les prochaines étapes.

Une fois que vous avez obtenu l'identité, vous pouvez assigner un rôle d'accès à l'application Web via son "principal ID". CosmosDB dispose de deux rôles préconfigurés : Read-only et Contributeur. Pour accorder le rôle Contributeur à la Web App, vous devez utiliser la commande :

az cosmosdb sql role assignment create --account-name cosmos-programmez-csa --resource-group rg-programmez --role-definition-id 00000000-0000-0000-0000-000000000002 --principal-id {service principal id}--scope "/"

L'identifiant par défaut pour le rôle contributeur est 00000000-0000-0000-0000-000000000002. Si vous voulez activer le rôle en lecture seule, l'identifiant correspondant est 00000000-0000-0000-0000-000000000001.

Pour vérifier que le rôle a été correctement assigné, vous pouvez utiliser la commande suivante :

az cosmosdb sql role assignment list --account-name cosmos-programmez-csa --resource-group rg-programmez

Il reste une dernière étape à considérer pour accéder à vos données dans votre application web. Actuellement, nous tentons de nous connecter avec les identifiants de l'émulateur. Il est dès lors nécessaire de modifier la façon dont nous nous connectons à la base de données dans notre code. Voici la modification à apporter :

using var cosmosClient = new CosmosClient(account,

            new DefaultAzureCredential());

Dans cette nouvelle version, nous n'avons plus besoin d'une clé mais d'utiliser l'authentification via Azure. Effectuez un git push pour lancer le déploiement automatique et en quelques secondes, vous verrez apparaître la liste des données sur la page "fetchdata".


Vous disposez à présent des clés pour garantir la sécurité de vos ressources avec Azure AD !

 

Pour retrouver mon code, rendez-vous sur  : https://github.com/csannierfr/Programmez-AzureSecurity

 

Vous souhaitez échanger avec un expert ?

Contactez-nous