Article - 29 février 2024

Private endpoint & infrastructure devops hybride

Ibrahim Lakkis Tech Lead DevOps senior
Accueil / Private endpoint & infrastructure devops hybride

Je souhaite partager avec vous mon expérience concernant l’implication sur la CI / CD azure devops du passage en privé des ressources azure. Pour répondre à la question comment utiliser les agents azure devops managés (« microsof hosted ») avec des ressources azures privées.

Mais commençons par le début, pourquoi répondre à cette question ?

En effet nous avons reçu une recommandation forte de la sécurité qui est de passer entièrement en privé les ressources azure applicative. Le choix de l’implémentation que nous avons choisi – qui est hors scope de cet article – est d’utiliser les private endpoints sur chaque ressource pour laquelle nous allons de plus couper les accès publics. Ce choix d’implémentation a un impact majeur sur notre CI/CD.

L’impact sur la CI/CD

Pourquoi cet impact majeur ?

La problématique est la suivante : nous avons une offre CI/CD managée par azure, dans le sens où nous utilisons des agents microsoft hosted et donc nous bénéficions des fonctions de build et de deploy fournies par azure. Ceci nous facilite un certain nombre de choses que nous assumons, notamment :

  • Déléguer à azure la disponibilité d’un ou de plusieurs agents de build (sous réserve des licences utilisées pour la parallélisation des jobs)
  • Déléguer à azure la maintenance de ces agents aussi bien d’un point de vue sécurité que compatibilité avec les derniers standards,
  • S’appuyer sur l’offre azure managée pour télécharger les outils nécessaires à la compilation du code dans nos stacks technologiques
  • S’appuyer sur azure pour la gestion des versions des différentes stacks téléchargées,
  • Donner l’agilité aux développeurs qui souhaitent expérimenter de nouvelles stacks ou versions technologiques,

Nous étions alors dans la configuration suivante :

Cependant cette configuration n’est plus possible lorsque nous aurons, pour des raisons de sécurité, configuré les private endpoints azure privés sur chaque ressource utilisée pour déployer (keyvault, webapp, storage, azure functions, ..).

En effet les agents microsoft-hosted étant public, il n’existe pas à l’heure actuelle de possibilité d’utiliser des agents microsoft hosted avec des ressources privées et de manière générale, les agents microsoft-hosted n’ont aucune possibilité d’interagir avec la zone privée azure (Microsoft backbone network).

Les recommandations de Microsoft, ainsi que les différentes veilles, sont que nous devons alors utiliser les agents self-hosted pour pouvoir accéder aux ressources azure privées.

Ceci nous pose un problème dans le sens où nous devons produire un panel de services conséquent reprenant l’ensemble des offres de build utilisées par azure dans nos différents périmètres applicatifs.

Nous aurons à passer du temps à les mettre en place sans compter que nous devrons sans doute frustrer nos développeurs, puisque allons perdre l’agilité dont les agents microsoft hosted nous font bénéficier pour la partie build.

Pour citer un exemple, la task UsePythonVersion@0 ne prend pas en charge l’installation automatique des outils python sur les agents self-hosted, et nous allions devoir fournir ces outils dans les différentes versions de python disponibles et en gérer la maintenance.

Exploration d’une infra CI / CD hybride : self-hosted / managed

Nous avons alors exploré une piste hybride qui est de continuer à utiliser les agents managés pour la partie build et les agents self-hosted uniquement pour la partie deploy.

En effet, nous souhaitons continuer à faire bénéficier nos développeurs de l’offre CI managée sur azure.

Nous avons alors expérimenté la configuration suivante décrite par le schéma suivant :

Ainsi comme le montre le schéma ci-dessus toute la partie CI est exécutée sur la partie publique sur un agent microsoft managed. En sortie nous produisons un artefact avec le mécanisme de publication (ou stash) de l’artefact pour que l’on puisse le réutiliser en entrée du stage de deploy. La partie deploy s’effectuant sur un agent self-hosted est privée et peut donc accéder à l’ensemble des ressources privées sous azure.

A noter qu’il est tout à fait possible de rajouter un stage de publication (absent ici pour des raisons de simplification) pour sauvegarder l’artefact dans une registry privée. Elle serait par exemple nécessaire pour produire un artfefact docker que vous souhaitez pousser dans une container registry ou bien dans un artifactory.

Analyse et évaluation des impacts

Pour notre choix final nous avons mis en balance les choix suivants :

  • Solution 1 : fournir une infrastructure complète self-hosted
  • Solution 2 : mettre en place une infra hybride CI sur du microsoft managed / CD sur du self hosted.

Solution 1

Dans la première solution l’impact est à évaluer aussi bien côté infrastructure que CI / CD. Nous retrouvons ci-dessous quelques liens intéressants qui permettent de créer des agents self-hosted à partir d’images disponibles sur github et ainsi reconstituer entièrement une offre de CI / CD :

azuredevops-buildagents/scripts at main · YannickRe/azuredevops-buildagents · GitHub

GitHub – actions/runner-images: GitHub Actions runner images

Dans tous les cas l’offre en self-hosted complète va imposer à minima une modification du pool des développeurs et une perte d’agilité de la partie build. En revanche, elle ne va pas profondément modifier l’architecture de leurs pipelines. Il faut toutefois retester la compilation de chaque technologie utilisée dans l’entreprise pour valider les différents cas d’usage ainsi que le déploiement de chaque stack.

Solution 2

La deuxième solution présente l’avantage de ne pas modifier la partie build. Il est toutefois nécessaire, comme dans la solution 1 de retester le déploiement de chaque stack pour la partie deploy uniquement, en plus de mettre en place les recommandations côté développeurs pour adapter l’ensemble des pipelines applicatifs à une infra hybride.

Pour déployer le self hosted dédié au fonctions CD, nous avons besoin sur l’agent self-hosted de docker, de l’azure cli, et de l’extension azure pipeline agent.

Nous avons utilisé le script du caf landing zone pour le déployer :

caf-terraform-landingzones/caf_solution/add-ons/azure_devops_agent/scripts/devops_runtime_baremetal.sh at main · Azure/caf-terraform-landingzones · GitHub

dans lequel nous avons désactivé le pull de l’image rover non nécessaire à la ligne 68 : docker pull « ${rover_version} » 2>/dev/null.

Nous avons ajouté à ce script la commande zip sudo apt-get install -y zip nécessaire pour utiliser les outils Terraform disponibles avec les tasks charleszipp.azure-pipelines-tasks-terraform.

En alternative, vous pourrez toujours trouver l’explication générique de microsoft learn Deploy an Azure Pipelines agent on Linux – Azure Pipelines | Microsoft Learn.

Cette configuration nous suffit pour déployer les container app, les webapp, azure functions, storage via Terraform ou en utilisant les task azure disponibles via l’extension azure pipeline agent (par exemple les tasks AzureWebAppContainer@1 AzureRmWebAppDeployment@4 ou AzureAppServiceManage@0, sans compter les task charleszipp.azure-pipelines-tasks-terraform pour Terraform…).

Côté CI, nous avons la chance que les pipelines soient déjà bien séparés entre les stages de build et de deploy.

Si ce n’est pas le cas il faudra évaluer l’impact de séparation entre les deux. D’autre part nous avons déjà un mécanisme de publication de l’artefact (que l’on appelle parfois « stash » dans certaines CI) qui existent.

Vous pouvez donc utiliser la task PublishBuildArtifacts@1 pour la partie publication. Sinon il vous faut évaluer l’impact de rajout de cette task côté développement :

task: PublishPipelineArtifact@1
displayName: ‘Publish Artifact: drop’
inputs:

targetPath: ‘$(build.SourcesDirectory)\dist’
artifact: ‘drop’
publishLocation: ‘pipeline’

Attention également si vos développeurs ont l’habitude de déployer certaines task sous windows et que l’agent self hosted que vous allez utiliser est du linux. C’était notre cas, et nous avons pu ajouter un paramètre optionnel au stage de deploy sur l’option DeploymentType pour utiliser runFromZip au lieu de webDeploy sous windows.

task: AzureRmWebAppDeployment@4
displayName: « Azure App Service Deploy »
inputs:

azureSubscription: « yourserviceconnexion »
WebAppName: « yourwebappname »
packageForLinux: « $(Pipeline.Workspace)/drop/ »
enableCustomDeployment: true
DeploymentType: « runFromZip » #  webDeploy pour windows
TakeAppOfflineFlag: false
RemoveAdditionalFilesFlag: true
ExcludeFilesFromAppDataFlag: false

Implémentation finale

Pour notre part nous avons choisi la solution 2 grâce à la solution de publication de l’artefact et du fait que les stages sont déjà bien séparés côté développement entre la partie CI et CD. De plus, comme nous devons dans tous les cas réaliser le redéploiement des ressources en privés de l’ensemble de notre infrastructure de manière progressive, puisque nous allons revoir nos 70 applications une par une, des recettes métiers étant nécessaire pour les valider, nous pouvons mener des recommandations ciblées pour chaque groupe de développeurs concerné et mener une transformation qui n’est pas complètement transparente mais qui a le mérite d’être accompagnée et maîtrisée.

Nous pouvons donc bénéficier des avantages suivants :

  • Continuer à déléguer à azure la disponibilité d’un ou de plusieurs agents de build, leur maintenance et sécurité,
  • Continuer à maintenir l’agilité des développeurs sur leur accessibilité aux différentes stacks de compilation disponibles,
  • Maintenir le moins possible les agents self-hosted.

Nous avons pris à notre charge la maintenance des agents self-hosted pour la partie deploy mais cette maintenance reste à l’heure relativement réduite. Nous avons depuis réalisé un upgrade automatisé de nos agents azure cli en trois mois.