Lorsquâon exĂ©cute un programme, il est souvent nĂ©cessaire de le configurer, de le paramĂ©trer ou de lui associer des Ă©lĂ©ments spĂ©cifiques Ă lâenvironnement depuis lequel il est lancĂ©. Par exemple, il peut sâagir de travailler avec des donnĂ©es stockĂ©es dans un rĂ©pertoire particulier ou dâinjecter des paramĂštres de connexion Ă une base de donnĂ©es que lâon souhaite garder confidentiels et non versionnĂ©s.
Heureusement, il est possible dâinjecter dans un programme des variables externes, qui serviront Ă configurer son comportement tout en restant indĂ©pendantes du code source.
Pourquoi externaliser la configuration dâun programme ?
Pour garantir la flexibilitĂ© et la sĂ©curitĂ© dâune application, il est souvent judicieux dâexternaliser certaines configurations. Voici quelques exemples courants :
- ĂlĂ©ments dĂ©pendants de lâenvironnement cible : Par exemple, lâURL dâune base de donnĂ©es, un lien vers un jeu de donnĂ©es dans un datalake, le chemin dâun fichier externe, ou encore une rĂšgle mĂ©tier configurable comme un seuil dâerreur.
- AccĂšs sĂ©curisĂ© Ă des ressources : Les mots de passe ou clĂ©s dâauthentification tel que les clĂ©s d’API, ne doivent pas ĂȘtre versionnĂ©s dans le code source pour Ă©viter tout risque de fuite.
La configuration dâune application regroupe tout ce qui est susceptible de varier entre diffĂ©rents environnements (dĂ©veloppement, validation, production, etc.). Une bonne pratique consiste Ă sĂ©parer strictement la configuration du code. Tandis que le code reste inchangĂ© Ă travers les dĂ©ploiements, la configuration peut varier considĂ©rablement.
Un bon test pour sâassurer de cette sĂ©paration consiste Ă se demander si lâapplication pourrait ĂȘtre rendue open source Ă tout moment, sans risquer de compromettre des identifiants ou dâautres donnĂ©es sensibles.
Cela peut ĂȘtre mis en Ćuvre de plusieurs façons :
- Par la lecture de variables dâenvironnement.
- Par lâinjection de paramĂštres lors du lancement du programme.
- Par lâajout de fichiers de configuration situĂ©s Ă un emplacement connu et attendu par le programme.
Ces trois techniques sont diffĂ©rentes interfaces pour fournir des donnĂ©es au programme, mais elles servent toutes le mĂȘme objectif : injecter des informations externes dans le code.
Ce qui reste le plus prĂ©conisĂ©, c’est l’utilisation de variable d’environnement dans l’applicatif (cf https://12factor.net)
Toutefois, les diffĂ©rentes mĂ©thodes d’injection existent et sont plus ou moins maintenues selon le language.
Configuration par fichier de configuration externe
Dans de nombreux langages, il existe des formats spécifiques pour gérer la configuration via des fichiers.
En Python, les fichiers de configuration sont couramment utilisĂ©s, souvent dans des formats standardisĂ©s, parmi lesquels le format TOML (Tomâs Obvious, Minimal Language) et le format INI.
Exemple de fichier INI
# config.ini Ă la racine du projet
[section_name]
key1 = value1
key2 = value2
[another_section]
keyA = valueA
keyB = valueB
# Exemple avec des paramÚtres par défaut
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[forge.example]
User = hg
[topsecret.server.example]
Port = 50022
ForwardX11 = no
Dans la bibliothĂšque standard de Python, on trouve le module configparser
, qui permet de gérer des fichiers de configuration au format INI. Ces fichiers sont habituellement nommés avec une extension descriptive comme .ini
, et ce module permet également de les lire facilement :
import configparser
# Création d'un objet ConfigParser
config = configparser.ConfigParser()
# Lecture du fichier config.ini
config.read('config.ini')
# Exemple dâaccĂšs aux donnĂ©es
server_interval = config['DEFAULT']['ServerAliveInterval']
user = config['forge.example']['User']
print(server_interval) # Affiche : 45
print(user) # Affiche : hg
Feuilleter la documentation https://docs.python.org/3/library/configparser.html
Note :
Ce type de configuration est présent dans pratiquement tous les langages, bien que chaque langage ait ses conventions. Par exemple :
- En Java :
application.properties
ouapplication.yml
- En Node.js :
config.json
- En Python :
.ini
(ou plus récemment,TOML
)
Configuration par arguments en ligne de commande
L’utilisation de la ligne de commande est une mĂ©thode historique pour gĂ©rer la configuration des programmes. Elle permet de crĂ©er des variables de CLI (command-line interface), facilitant ainsi l’exĂ©cution de programmes directement via le terminal.
De nombreux programmes informatiques, qu’ils soient conçus pour effectuer des tĂąches rapidement (comme des scripts ou des outils en ligne de commande) ou pour fonctionner en arriĂšre-plan en tant que serveurs (comme les serveurs web ou les bases de donnĂ©es), peuvent recevoir des paramĂštres (variables) directement via la ligne de commande lorsque vous les exĂ©cutez. En Python, il est possible de rĂ©cupĂ©rer ces paramĂštres Ă l’aide du module sys
.
Prenons, par exemple, le fichier main.py
que nous avons construit précédemment. En ajoutant le code suivant :
import sys
import logging
arguments = sys.argv
logging.basicConfig(filename=arguments[1], encoding='utf-8', level=logging.DEBUG)
et en lançant la commande :python main.py toto.log
nous pouvons écrire les logs dans le fichier toto.log
.
Cependant, un inconvĂ©nient de cette approche est qu’avec un nombre accru d’arguments, il devient plus facile de commettre des erreurs d’ordonnancement ou d’oublier un paramĂštre.
Clique est une bibliothÚque pour Python qui facilite la création d'interfaces en ligne de command https://click.palletsprojects.com/en/stable/
Ă noter que cette mĂ©thode ne sera pas approfondie ici, car nous nous concentrerons principalement sur la configuration par variables d’environnement.
Configuration par variable d’environnement
Les variables dâenvironnement sont des variables disponibles dynamiquement pour votre programme pendant lâexĂ©cution. Contrairement Ă des valeurs codĂ©es en dur, elles sont adaptables Ă l’environnement dans lequel l’application s’exĂ©cute. Cela permet une plus grande flexibilitĂ© et facilite les Ă©ventuelles modifications de configuration.
L’injection par variable d’environnement est une solution optimale, notamment pour des personnes extĂ©rieures au projet. Cette approche permet de surcharger facilement la configuration en renseignant des paramĂštres sous la forme :
CLE=valeur
Remarque : Les noms des variables d’environnement suivent la notation
UPPER_SNAKE_CASE
.
En Python, la gestion des variables d’environnement peut ĂȘtre facilitĂ©e avec la librairie python-dotenv
. Celle-ci permet de lire un fichier .env et d’exporter son contenu dans l’environnement d’exĂ©cution.
Exemple d’un fichier .env
# Configuration par défaut
CHEMIN_FICHIER_LOG=
ENVIRONNEMENT=local
Voici comment importer les variables depuis un fichier .env :
from dotenv import load_dotenv
# Charge toutes les variables d'environnement depuis le fichier .env
load_dotenv()
Une fois chargées, les variables sont accessibles via la librairie os
:
import os
chemin_fichier_log = os.getenv("CHEMIN_FICHIER_LOG")
environnement = os.getenv("ENVIRONNEMENT")
Il est également possible de définir plusieurs fichiers pour organiser les configurations et éviter de versionner des données sensibles. Par exemple, vous pouvez charger un fichier local supplémentaire :
from dotenv import load_dotenv
import os
# Charge le fichier principal
load_dotenv()
# Charge un fichier local si présent
local_env_path = ".env.local"
if os.path.exists(local_env_path):
load_dotenv(dotenv_path=local_env_path, override=True)
Variables d'environnement : https://kinsta.com/knowledgebase/what-is-an-environment-variable/
Travaux Pratiques
OBJECTIF DU TP : Créez un fichier main.py
qui, au lancement de l’application, affiche dans les logs toutes les valeurs des variables d’environnement, Ă l’exception des mots de passe.
Créez un fichier
.env.local
contenant :- Une fausse URL de base de données
- Un faux mot de passe de base de données
- La version actuelle de votre application (par défaut, utilisez
0.1
si vous n’avez pas encore commencĂ© votre projet).
Créez un fichier
.env.template
qui liste toutes les variables présentes dans le fichier.env.local
. Ce fichier servira de modÚle pour permettre aux développeurs de créer leur propre fichier.env
localement.Ajoutez le fichier
.env.local
au.gitignore
pour Ă©viter qu’il soit versionnĂ©.Dans le fichier
main.py
: ImplĂ©mentez une mĂ©thode qui charge les variables d’environnement globales ainsi que celles du fichier local (si un fichier.env.local
est prĂ©sent).Ajoutez une mĂ©thode qui affiche toutes les variables d’environnement (globales et locales), en masquant les valeurs des variables dont le nom contient les mots-clĂ©s suivants :
password
,pwd
,jeton
,token
,secret
,key
,cle
,mdp
, oumotdepasse
.
Pour ces variables, affichez des****
Ă la place de leur valeur.
Créez une nouvelle version de votre code (en veillant à ce que le fichier
.env.local
ne soit pas inclus dans la version). Envoyez ensuite cette version à votre dépÎt distant.