Automatiser le processus d’audit statique avec SonarCloud et le déploiement de votre application python (Github Actions)

Automatiser le processus d’audit statique avec SonarCloud et le déploiement de votre application python (Github Actions)

Bonjour à tous, dans cet article nous allons voir comment nous prendre un peu la tête afin d’améliorer le processus d’audit et déploiement d’une application dans un environnement de préproduction/production. Je vous encourage à lire les deux articles de la section préambule si-ne vous n’avez qu’une connaissance limitée du monde du DevOps

I. Préambule

Je vous encourage vivement à lire ces deux articles :

Si-vous souhaitez mettre en place simplement une pipeline CI (continous integration) pour réaliser un audit de code statique avec sonarCloud, regardez cette vidéo :

Je n’explique pas cette première partie (cf vidéo). Si cela ne vous intéresse pas d’intégrer sonar, supprimez le bloc de code identifiant le job sonarcloud plus bas dans l’article.

Dans un premier temps, nous allons générer une paire de clef SSH afin de réaliser l’interconnexion entre nos deux instances. (Github runner et mon serveur de production)

Pour rappel un « runner » une machine (virtuelle) ou un container exécute des tâches orchestrées par des GitHub Actions (équivalent Gitlab CI). Sur Github, il existe deux type de runner :

  • Shared Runners
  • Self Hosted runners

Pour plus d’informations : https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions

Source : https://dev.to/techschoolguru/how-to-setup-github-actions-for-go-postgres-to-run-automated-tests-81o

II. Génération d’une paire de clé SSH

Reprenons. Comme je l’ai dis en début d’article, je dois générer une nouvelle paire de clés, pour que notre runner puisse se connecter à notre VPS :

ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/github_action

Copiez votre clé publique sur votre serveur distant, par l’intermédiaire de la commande suivante, afin que votre serveur de production ait déjà en « mémoire » votre clé publique.

Note : Lorsque vous exécutez cette commande, votre clé publique est inscrite dans le fichier : ~/.ssh/authorized_keys

ssh-copy-id -i ~/.ssh/github_action.pub [email protected]

III. Créez deux « secrets » dans votre repository

Ajoutez le contenu de votre clé privé aux « secrets » de votre repository (SSH_PRIVATE_KEY). Pour cela allez dans votre repository sur Github et cliquez sur Settings , puis Secrets, Actions . Vous devriez voir un bouton indiquant New repository secret.

Ajoutez le contenu de votre clé privée, afin que le runner github puisse se connecter en ssh sans soucis à votre serveur de production.

  • SSH_PRIVATE_KEY

Vous aurez également besoin du contenu de votre fichier ~/.ssh/known_hosts. L’option la plus simple consiste à exécuter la commande suivante à partir de votre ordintauer qui héberge votre environnement de développement (kali linux dans mon cas) en remplaçant IP_ADDRESS par votre serveur de destination (mon VPS in my case).

Pour rappel : Le fichier known_hosts est un fichier « côté client » contient la clé publique du serveur SSH (identifiant le serveur, pas un utilisateur !!!). Par défaut SSH en génère plusieurs dans un but d’interopérabilité. Je vais prendre celle qui utilise l’algorythme de condensat (hash) ssh-ed25519

ssh-keyscan -H IP_ADDRESS

Choisissez une des clés publique du serveur de « prod » (VPS). Dans mon cas, je vais copier celle utilisant l’algo ed25519.

|1|tNnxxxxxxxxxxxxxxxxxPcs=|o1bbxxxxxxxxxxxxxxxxxxxxxxQES8= ssh-ed25519 AAAAC3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxY

Ajoutez la valeur à un nouveau « secret » Github nommé comme ci-dessous :

Vous pouvez aussi utiliser ssh -o StrictHostKeyChecking=no [email protected] ‘blablabla’, au lieu de créer le secret SSH_KNOW_HOST, si vous rencontrez des difficultés à cette étape.

IV. Création de notre pipeline avec Github Actions

Nous allons maintenant créer notre workflow. Accédez à votre référentiel sur Github et cliquez sur l’onglet Actions , puis set up a workflow yourself. Choisissez un petit nom utile et utilisez le script en s’appuyant du modèle ci-dessous.

Exécutez la commande Git pull afin de pouvoir recevoir les modifications (la création des deux dossiers et du fichier .yml par défaut) ou bien alors tenter d’éditer le fichier directement depuis Github. (Faite cela uniquement si votre code est à jour sur github)

Dans le fichier que je vais nommer pipeline.yml, insérez le snippet de code suivant, et adaptez le en fonction de votre contexte :

name: CI/CD - code analysis and if it's ok auto deploy 
on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened]
jobs:
  sonarcloud:
    name: SonarCloud
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
  deploy:
    needs: sonarcloud 
    runs-on: ubuntu-latest 
    steps : 
      - name : Install private SSH Key 
        uses : shimataro/ssh-key-action@v2 
        with : 
          key : ${{ secrets.SSH_PRIVATE_KEY }} # copy and paste a private key to a github secret of your current repo
          known_hosts : ${{ secrets.SSH_KNOW_HOST }} # optional, but add at the beggining of your line : ssh -o StrictHostKeyChecking=no [email protected]
          if_key_exists: ignore
      - name : Pull
        run : | 
          ssh ${{ secrets.USER }}@${{ secrets.IP }} '/usr/bin/screen -X -S weathergilant quit'
          ssh ${{ secrets.USER }}@${{ secrets.IP }} '
          cd /home/${{ secrets.USER }}/weathergilannt
          /usr/bin/git pull origin main
          /usr/bin/screen -S weathergilant -d -m /usr/bin/python3 /home/${{ secrets.USER }}/weathergilannt/index.py'
  • Le workflow est instancié par le runner uniquement si nous mettons la branche main
  • Dans un premier temps, le premier job va s’exécuter (analyse statique du code depuis sonarcloud)
  • Si le scan est réussi (que le code passe toutes les étapes), alors le job sonarcloud va renvoyé « True » à github runner, qui lui va se charger d’exécuter le second job deploy
  • Le job deploy va :
    • Stopper l’exécution de ma session screen qui éxecute le script de mon projet (index.py) –> clé de voute de mon programme
    • Récupérer les dernière mise à jour de mon code (git pull automatique réalisé dans le bon dossier)
    • Création d’une nouvelle session screen, en exécutant de nouveau mon programme index.py

Tout cela fait que l’interruption de service très courte (de l’ordre de moins de 5 secondes environ, en fonction du poids informatique de votre mise à jour)

Note : Vous pouvez utiliser aussi des sessions screen, si-vous n’avez pas en place un système de « Logging » pour votre programme

Pour testez, enregistrez vos modifications (commit) et poussez-les sur votre branche affecté par la pipeline (dans mon cas main)

Vu que notre pipeline ne comporte que deux jobs, nous n’avons réelement besoin de surcharger notre script .yml en définissant deux stages (groupe de jobs). Néanmoins, gardez à l’esprit, que si-vous deviez avoir plus de 4 jobs, cela serait plus clair de les compartimenter en stages.

Lors de vos différents tests, n’hésitez pas à

  • Activer le mode debug et à lire les logs du runner (menu « … » cf photo).
  • Ouvrir la console de vos jobs (SonarCloud, Deploy)

J’espère que cet article vous aura plus. Je ne suis clairement pas un expert DevOps (Heureusement, c’est trop fatiguant ^^, et éreintant), mais parfois il peut s’avérer plaisant d’automatiser certaines redondante et fastidieuse ^^. Comme je dis souvent : Le devops c’est comme le mayonnaise, c’est bon, mais il ne faut pas trop en abuser.

Si-vous n’avez pas tout compris, je vous encourage à visiter un de mes projets hébergés en public sur Github, qui utilisent les Github Actions :

++

Geoffrey

Geoffrey Sauvageot-Berland

Ingénieur diplômé par l’état en Informatique et Cybersécurité. Généraliste, à l'origine administrateur systèmes et réseaux, j’occupe actuellement un poste d’auditeur en sécurité offensive. J’apprécie également la programmation/automatisation. Fondateur du blog : "Le Guide du SecOps", anciennement "Le Guide du SysOps"

Related Posts

Git Repository Hijacking – Reconstruire le code source à partir d’un répertoire .git, puis analyser l’historique du projet

Git Repository Hijacking – Reconstruire le code source à partir d’un répertoire .git, puis analyser l’historique du projet

SonarLint – Plugin d’audit de qualité et de sécurité de votre code « on the fly »

SonarLint – Plugin d’audit de qualité et de sécurité de votre code « on the fly »

Publier un site web sur le réseau Tor (hidden-service)

Publier un site web sur le réseau Tor (hidden-service)

Vulnérabilité PwnKit : Démonstration de l’escalade de privilège – (Contexte post exploitation) [CVE-2021-4034]

Vulnérabilité PwnKit : Démonstration de l’escalade de privilège – (Contexte post exploitation) [CVE-2021-4034]