Github Actions : Azure CLI & Service Principal

Github Actions : Azure CLI & Service Principal

2020, Jan 27    

Cet article est le troisième d’une série sur Github Actions et la mise en place d’une chaîne CI/CD.

Dans les derniers articles, nous avons vu comment créer un pipeline de CI/CD avec Github Actions et Azure.

Aujourd’hui, nous verrons comment optimiser notre pipeline de déploiement d’applications sur Azure pour y apporter modernité et sécurité en utilisant az cli et service principal.

Préparation

Tout d’abord, je vous invite à vous réferer aux étapes des articles précédents pour comprendre les différents éléments qui composent le pipeline “classique” au format YAML.

Une fois ces révisions effectuées et les concepts acquis, nous pouvons commencer avec un pipeline tout fait et prêt à être modifié.

Voici donc le fichier auquel nous avions abouti, avec de très légères améliorations esthétiques dont l’usage de variables:

name: CI/CD Classic
on: [push]
env:
  ARTIFACT_NAME : webapp
  AZURE_WEBAPP_NAME: actionsSampleApp
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Setup .NET Core
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 2.2.108
    - name: Build with dotnet
      run: dotnet build ./src --configuration Release
    - name: Package with dotnet
      run: dotnet publish ./src --configuration Release
    - name: Publish artifact
      uses: actions/upload-artifact@master
      with:
        name: ${{ secrets.ARTIFACT_NAME }}
        path: src/bin/Release/netcoreapp2.2/publish
  deploy:
    needs: build
    runs-on: windows-latest
    steps:
      - name: Download Artifacts
        uses: actions/download-artifact@master
        with:
          name: ${{ env.ARTIFACT_NAME }}
      - name: Deploy to Azure App Service
        uses: azure/appservice-actions/webapp@master
        with:
          app-name: ${{ env.AZURE_WEBAPP_NAME }}
          package: ${{ env.ARTIFACT_NAME }}
          publish-profile: ${{ secrets.webappPublishProfile }}

Azure Actions

La première étape pour notre modernisation de pipeline est de remplacer l’usage de l’action azure/appservice-actions/webapp@master par une action azure plus récente et non dépréciée.

Nous pourrions donc modifier notre step de déploiement de cette manière:

# deploy web app using Azure credentials
- name: 'Azure webapp deploy'
  uses: azure/webapps-deploy@v1
  with:
    creds: ${{ secrets.azureWebAppPublishProfile }}

C’est un bon début mais on utilise toujours le Publish Profile comme mécanisme de connexion et le Publish Profile… c’est mal !

Azure CLI

L’action azure/webapps-deploy peut se passer d’un Publish Profile et utiliser az cli. Parfait! Mais, pour cela, elle nécessite d’être authentifiée auparavant.

Nous allons donc remplacer notre job deploy pour y ajouter les steps utilisant les actions azure/login et azure/webapps-deploy.

deploy:
  needs: build
  runs-on: windows-latest
  steps:
    - name: Download Artifacts
      uses: actions/download-artifact@master
      with:
        name: ${{ env.ARTIFACT_NAME }}
    # set up az cli login
    - uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    # deploy web app using Azure credentials
    - name: 'Azure webapp deploy'
      uses: azure/webapps-deploy@v1
      with:
        app-name: ${{ env.AZURE_WEBAPP_NAME }}
        package: 'webapp'

Hmmm, ok mais en fait on remplace juste un secret Publish Profile par un autre : AZURE_CREDENTIALS. C’est quoi l’intérêt ?!

Service Principal

Dans les steps de déploiements, nous avons utilisé une action basé sur la cli d’azure. Pour cela nous avons introduit un nouveau secret: ${{ secrets.AZURE_CREDENTIALS }}.

  • Le Publish Profile est un profil d’authentification permettant de publier notre app mais ne permettant pas réellement d’identifier l’auteur du déploiement ni de gérer finement les droits.
  • Le Service Principal, quant à lui est une identification liée à une attribution de rôle qui fournit l’accès à des ressources Azure. Dans notre cas, le Service Principal sera donc lié à notre workflow de déploiement via Github Actions et pourra être administré de manière précise depuis Azure.

L’identité nécessaire pour publier notre application doit donc avoir les droits associés. Cela se fait en générant un Service Principal sur un scope défini via la cli depuis Azure Cloud Shell par exemple.

Plusieurs options s’offrent à nous. Soit on scope la souscription, soit le ressource group contenant l’appservice, soit la ressource app service directement. Dans une approche least privilege je ne saurais que vous conseiller de restreindre les droits à la ressource.

az ad sp create-for-rbac --name "my-service-principal-name" --role contributor --scopes /subscriptions/<subscription-id>/resourceGroups/<group-name>/providers/Microsoft.Web/sites/<app-name> --sdk-auth

Dans cet exemple, remplacez les espaces réservés dans la ressource par votre ID d’abonnement, votre groupe de ressources et le nom de votre application.

L’éxécution de cette commande génère un output au format JSON fournissant l’accès à votre App Service.

A la manière du Publish Profile des articles précédents, nous allons donc pouvoir ajouter un secret via l’interface d’administration de Github. Vous pourrez donc copier-coller l’output de la commande précédente dans un secret Github, nommé AZURE_CREDENTIALS.