Comment stocker les configurations d'accès aux environnements de façon sécurisée

icon Tags de l'article : , , ,

Septembre 13, 2019
Bonjour à tous et toutes,

Aujourd'hui on va parler fichiers de configuration, variables d'environnement, stockage, sécurité et contrôleur de source.

Quand je parle de variables d'environnement, je parle par exemple des identifiants pour se connecter à la BDD, des clefs analytics, ou encore d'autres identifiants critiques.
Il s'agit en général de variables que les développeurs doivent posséder pour les environnements intermédiaires (développement, qualification, préproduction) mais pas pour certains environnements (production, analytics, BI, etc.).
Ces variables sont, en général, stockées dans un gros fichier de configuration qui sera utilisé par le logiciel pour ses différentes connexions.

Du coup la question qui revient à CHAQUE fois : comment stocker de façon sécurisée quelque part ces variables, afin que les développeurs puissent y avoir accès facilement, sans pour autant les rendre récupérables par n'importe qui de passage dans la société ?
Exit donc la feuille collée au mur avec les mots de passe.

Dans ces 5 dernières années, je suis passé par plusieurs solutions :
  • Le service production/exploitation qui s'occupe lui-même de renseigner les clefs de production dans le fichier de configuration. Avantage : sécurité, inconvénient : mise à jour des clefs de configuration ultra complexe. (on doit spécifier à chaque fois les champs ajoutés, les champs modifiés, les champs supprimés, etc. et les fails arrivent souvent)
  • Les développeurs ont toutes les clefs de tous les environnements, et ils les remplacent eux-même pour faire des builds en production. Avantage : simple, inconvénient : sécurité très faible.
  • Les fichiers de configuration sont archivés avec la solution. Avantage : ultra simple, inconvénient : aucune sécurité, n'importe qui ayant accès aux sources a accès à tous les environnements.
  • Les clefs sont enregistrés dans un keepass archivé avec la solution, et seules les personnes concernées connaissent son mot de passe. Avantage : sécurité, inconvénient : très chiant à modifier et saisie constante du mot de passe.

Afin de simplifier les choses sur le projet sur lequel je suis, j'ai proposé la solution suivante :
1) Nous avons un fichier config.zip archivé et chiffré avec mot de passe à la racine du projet
2) Nous avons développé un script nommé init.sh, qui a pour mission d'initialiser le projet.
3) Lorsqu'on lance le script init.sh, il va se charger :
  • De vérifier les versions des packages globaux installés (par exemple les versions de NPM, d'Ionic, de Cordova, ...)
  • De demander le mot de passe du fichier config.zip
  • De dézipper le fichier config.zip grâce au mot de passe renseigné, pour récupérer le fichier de configuration .config
  • De supprimer tous les dossiers générés (nodes_modules, www, plugins, etc.)
  • De lancer les commandes nécessaires à l'initialisation du projet (npm i par exemple)
4) Nous avons ajouté une commande "zip:config" qui sert à chiffrer notre fichier de configuration (en saisissant à nouveau le mot de passe)
5) Nous avons ajouté dans le gitignore notre fichier de configuration.

Ainsi, nous pouvons archiver le fichier config.zip qui n'est dézippable qu'avec le mot de passe.
Dès qu'une personne doit mettre à jour le fichier de configuration, elle fait un "npm run zip:config", tape le mot de passe, et archive ensuite le nouveau fichier config.zip.
Dès qu'une personne change de branche ou merge la branche principale dans sa branche, elle a juste à faire un "npm run init", puis de saisir le mot de passe.

Cette solution nous permet de garder un process très simple sans pour autant sacrifier la sécurité du projet !

Voici le fichier init.sh que nous utilisons :

#!/usr/bin/env bash
expectedIonicVersion="5.2."
expectedCordovaVersion="9.0."

echo "Config file password (ask your colleagues):"
read -s password

ionicVersion="$(ionic -v)"

if [[ "$ionicVersion" != "$expectedIonicVersion"* ]]; then
    echo "Wrong Ionic version, you need to install the $expectedIonicVersion"
    exit;
else
    echo Ionic version OK"
fi

cordovaVersion="$(cordova -v | cut -c-5)"

if [[ "$cordovaVersion" != "$expectedCordovaVersion"* ]]; then
    echo "Wrong Cordova version, you need to install the $expectedCordovaVersion"
    exit;
else
    echo "Cordova version OK"
fi

unzip -o -P "$password" config.zip > /dev/null
if [[ $? == 0 ]]; then
  echo "Successfully unzipped the .env file"
else
  echo "Wrong Password for env file"
  exit;
fi

echo "Now removing generated folders..."

rm -rf ./node_modules/
echo "nodes_modules folder removed"

rm -rf ./plugins/
echo "plugins folder removed"

rm -rf ./platforms/
echo "platforms folder removed"

rm -rf ./www/
echo "www folder removed"

npm i

Enfin, voici les commandes qu'on peut trouver dans notre package.json :
{
  "scripts": {
    "zip:config": "zip -o -re config.zip .config",
    "init": "./build-scripts/init.sh"
  }
}

A noter :
  • zip -o -re target origin permet de zipper un fichier de façon chiffrée en demandant un mot de passe
  • read -s password dans le fichier .sh permet de lire un texte saisi sans qu'il s'affiche à l'écran
  • unzip -o -P "$password" config.zip > /dev/null permet de décompresser et déchiffrer le fichier config.zip à l'aide du mot de passe récupéré préalablement
  • Si vous voulez gérer plusieurs fichiers de configuration, par exemple pour l'environnement dev & l'environnement de production, vous pouvez avoir un fichier dev.config.zip et prod.config.zip, et deux scripts d'initialisation, chaque zip ayant son propre mot de passe. Ainsi seules les personnes habilitées pourront dézipper le fichier prod.config.zip :)

En espérant que ça vous soit utile, bon dev à tous et toutes !

Quelques outils que tout bon développeur .Net devrait utiliser sur ses projets

icon Tags de l'article : , , , ,

Mai 15, 2018
J'ai entendu dire, il y a longtemps, que Bill Gates avait dit :



Et c'est vrai. Quelqu'un qui n'aime pas travailler inutilement trouvera toujours des voies pour travailler plus efficacement et supprimer les tâches chiantes inutiles.

Au fil des années, je me suis rendu compte que trop peu de développeurs se posaient une question pourtant évidente : quelle tâche quotidienne et contraignante pourrais-je simplifier dans mon process de développement/test ?

La réponse est souvent : ben merde y'en a plein en fait !!!

Qu'il s'agisse de purger la base de données, de créer un compte utilisateur, de remplir la BDD avec de fausses données... il y a souvent énormément de tâches qu'un développeur pourrait automatiser pour vite gagner un maximum de temps. Et si en plus ce développement est mutualisé entre les développeurs... ben c'est un gain énorme pour toute l'équipe.

Pour ça, je voulais partager avec vous les outils que tout bon développeur .Net devrait utiliser pour ça.

1) Une extension Visual Studio

Coder sa propre extension Visual Studio n'est pas forcément évident... mais ça peut vous permettre de gagner un maximum de temps en ajoutant directement dans VS les choses chiantes que vous devez faire régulièrement.

Quelques exemples (dont certains tirés de l'extension VS de mon poste actuel) :
  • purger la base de données
  • créer un compte utilisateur de test
  • démarrer le noeud Selenium
  • tuer tous les process Chrome Selenium qui restent
  • changer la configuration de la BDD (local / tests de perfs / preprod)
  • etc.

Avoir ces options directement dans votre Visual Studio peut vous faire gagner un temps précieux. Car même juste 2 minutes par jour, sur une année ça représente une journée entière de travail...

2) Le #if DEBUG

En local, on a parfois besoin d'avoir des fonctionnements différents du fonctionnement en production. Que ce soit à cause du cache, de la quantité de données, ou même de l'initialisation de la base de données... on a parfois envie d'avoir un fonctionnement différent, pour se simplifier la vie.

Voici quelques exemples d'actions que j'ai pu automatiser par le passé, grâce au #if DEBUG :
  • au lieu d'aller chercher le catalogue complet de données en BDD (ce qui prenait 2 minutes à chaque lancement de l'application), on le stocke sérialisé sur le disque dur et on l'utilise comme tel (bim, 10 secondes de chargement au lieu de 2 minutes)
  • création automatique d'un compte par défaut si aucun compte n'existe déjà
  • connexion automatique au compte par défaut
  • extraction, anonymisation et stockage sérialisé dans des fichiers de données venant de la production, afin de pouvoir faire des calculs statistiques sans avoir à requêter directement la BDD de prod
  • forcer la connexion à la BDD locale

3) Un dossier de ressources

Là on est dans l'évidence, mais parfois ça ne fait pas de mal de rappeler les évidences : prenez des notes.

Vous galérez à trouver une procédure spécifique ? Notez là quand vous avez enfin trouvé.
Un collègue vous montre une procédure compliquée pour faire quelque chose ? Notez là.
Vous découvrez gadget super cool que vous pourriez avoir à utiliser plus tard ? Mettez le de côté.

Quand on développe, il faut aussi savoir prendre des notes. Personnellement, j'ai toujours un dossier de ressources (personnelles) chiffré.

Qu'est ce qu'on trouve dans le mien ? Enormément de choses :
  • Les logins/mdp pour chaque compte partagé lié à notre application
  • Des scripts windows/powershell pour certaines actions (backup d'une base de données, restauration, création d'un certificat)
  • Comment faire certaines actions simples/complexes dans la solution
  • Des scripts SQL pour certaines actions BDD (purge et réindex Azure, identifier la fragmentation des index, batch de suppression des anciens logs, etc.)
  • Des rappels sur certains concepts qui ont du mal à rentrer (oui, même après plus de 15 ans de dev, ça doit être le grand âge)

Ca peut sembler idiot, car souvent en 2/3 minutes sur stackoverflow on peut retrouver la solution... mais :
1) Ca permet d'avoir du spécifique pour notre situation
2) Si nos fichiers sont bien triés et nommés, on gagne du temps même par rapport à stackoverflow
3) Ca peut vous sauver la vie si vous devez refaire une opération compliquée (prévue à l'origine comme un one-shot, vous savez, le célèbre "ne t'en fais pas, c'est juste pour cette fois" d'il y a 6 mois)

4) Les tests unitaires

Bon, je ne vais pas insister sur l'importance des tests unitaires dans un projet, mais sachez ceci : vous pouvez très bien utiliser des tests unitaires pour automatiser certaines actions de dev/debug.

Quelques exemples :
  • Tester la connectionstring du projet
  • Vérifier que toutes les procédures stockées appelées sont bien présentes dans la BDD
  • Tester une procédure stockée
  • Vérifier qu'une convention de codage est bien respectée sur le projet (quand on a des règles spécifiques)

Ou même encore : créer des données en dur en base. Après tout pourquoi pas ?

4) Un logiciel d'automatisation dans le navigateur

Lorsqu'on fait du dev web, on a souvent besoin de remplir des formulaires pour tester certaines choses. Et remplir 10 fois d'affilée les même 10 champs... ben ça fatigue très vite.

Or... il existe une solution simple : les extensions Chrome/Firefox d'automatisation. Par exemple iMacros.

Ces extensions permettent d'enregistrer un enchainement d'actions faites dans le navigateur pour les reproduire ensuite. Grâce à ça, vous pourrez créer un compte, vous logger, remplir en formulaire, etc... en un seul clic.

5) Les tests Selenium

Même si les tests Selenium sont, à la base, conçus pour tester votre application, vous pouvez les utiliser pour de nombreuses choses pas forcément évidentes à première vue :
  • Tester une API
  • Tester l'interconnexion entre 2 applications
  • Aller vérifier l'état d'un autre service en ligne
  • Créer une surcouche de monitoring (quand vous n'avez qu'un board figé de monitoring et pas d'API)
  • ...

6) Les macros de Notepad++

Si vous ne les avez jamais utilisé, sachez que Notepad++ permet d'enregistrer toutes les actions produites sur une ligne, pour ensuite les reproduire sur toutes les lignes d'un fichier.

Vous avez un fichier où le format ne va pas du tout, vous devez passer un bloc à gauche, supprimer quelques caractères et rajouter un morceau à la fin ? Record => modifications => Fin => Jouer en boucle jusqu'à la fin => terminé.

Voilà, je pense que ça fait déjà pas mal,

Je vous ai épargné les grands classiques, comme les environnements d'intégration continue, car si vous n'en avez pas déjà, il y a de fortes chances que ce soit indépendant de votre volonté (je voulais concentrer cet article sur ce que les développeurs peuvent faire eux-même, sur leur poste).

J'espère que cet article vous a plu, bonne journée et bon dev à tous et toutes !

Refactoring : la règle des trois

icon Tags de l'article : ,

Mars 16, 2018
Salut tout le monde,

Aujourd'hui on va parler Refactoring.

Je pense que vous vous êtes déjà tou·tes retrouvé·es dans une situation où vous avez besoin de reprendre du code... mais ça vous obligerait à faire un copier coller.

Donc, en tant que bon·ne dev, vous vous dites : "hors de question, je vais refacto pour réutiliser cette méthode/vue ailleurs". Et vous vous lancez dans votre refacto.

Sauf que voilà. En général une refacto de ce type prendra au moins 3x le temps qu'il aurait fallu pour faire un copier/coller... Et rien ne vous assure qu'elle sera utile plus tard.

Ca se trouve, vous perdrez des heures à refacto du code qui ne sera jamais plus utilisé.

Face à cette interrogation, mes collègues m'ont fait découvrir une règle que je ne connaissais pas : la règle de trois.

Elle est très simple : quand vous avez besoin de réutiliser un morceau de code, faites un copier/coller. Si, en revanche, vous en avez à nouveau besoin plus tard, là vous pourrez vous lancer dans une refacto.

En résumé : on peut copier/coller du code, mais une seule fois. Au delà, il faut refacto notre code.

Cette "autorisation de copier/coller" peut permettre d'éviter de se lancer dans d'énormes refacto couteuses qui n'auront aucune utilité. Et le cout sera quasi-nul, car un simple copier/coller c'est souvent l'affaire de quelques minutes...

Bon dev à tou·tes !