Il existe plusieurs options pour stocker les mots de passe et autres secrets qu'un programme Python doit utiliser, en particulier un programme qui doit s'exécuter en arrière-plan et qui ne peut pas simplement demander à l'utilisateur de taper le mot de passe.
Problèmes à éviter :
- Vérifier le mot de passe dans le contrôle de source où d'autres développeurs ou même le public peuvent le voir.
- D'autres utilisateurs sur le même serveur lisent le mot de passe à partir d'un fichier de configuration ou d'un code source.
- Le fait d'avoir le mot de passe dans un fichier source où d'autres personnes peuvent le voir par-dessus votre épaule pendant que vous le modifiez.
Option 1 : SSH
Ce n'est pas toujours possible, mais c'est probablement la meilleure solution. Votre clé privée n'est jamais transmise sur le réseau, SSH se contente d'effectuer des calculs mathématiques pour prouver que vous avez la bonne clé.
Pour que cela fonctionne, vous devez disposer des éléments suivants :
- La base de données ou tout autre élément auquel vous accédez doit être accessible par SSH. Essayez de rechercher "SSH" plus le service auquel vous accédez. Par exemple, "ssh postgresql" . Si cette fonctionnalité n'est pas présente dans votre base de données, passez à l'option suivante.
- Créer un compte pour exécuter le service qui fera des appels à la base de données, et générer une clé SSH .
- Vous pouvez soit ajouter la clé publique au service que vous allez appeler, soit créer un compte local sur ce serveur et y installer la clé publique.
Option 2 : Variables d'environnement
Celle-ci est la plus simple et peut donc constituer un bon point de départ. Il est bien décrit dans le L'application Twelve Factor . L'idée de base est que votre code source extrait le mot de passe ou d'autres secrets des variables d'environnement, puis vous configurez ces variables d'environnement sur chaque système où vous exécutez le programme. Il peut également être intéressant d'utiliser des valeurs par défaut qui conviendront à la plupart des développeurs. Vous devez trouver un équilibre entre cela et le fait de rendre votre logiciel "sûr par défaut".
Voici un exemple qui extrait le serveur, le nom d'utilisateur et le mot de passe des variables d'environnement.
import os
server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')
db_connect(server, user, password)
Cherchez à savoir comment définir les variables d'environnement dans votre système d'exploitation et envisagez d'exécuter le service sous son propre compte. De cette façon, vous n'aurez pas de données sensibles dans les variables d'environnement lorsque vous exécutez des programmes sous votre propre compte. Lorsque vous définissez ces variables d'environnement, veillez à ce que les autres utilisateurs ne puissent pas les lire. Vérifiez les autorisations de fichiers, par exemple. Bien sûr, tous les utilisateurs disposant de l'autorisation Root pourront les lire, mais il n'y a rien à faire. Si vous utilisez systemd, regardez le fichier unité de service et veillez à utiliser EnvironmentFile
au lieu de Environment
pour tous les secrets. Environment
peuvent être consultées par n'importe quel utilisateur disposant d'un systemctl show
.
Option 3 : Fichiers de configuration
C'est très similaire aux variables d'environnement, mais vous lisez les secrets à partir d'un fichier texte. Je trouve toujours les variables d'environnement plus flexibles pour des choses comme les outils de déploiement et les serveurs d'intégration continue. Si vous décidez d'utiliser un fichier de configuration, Python supporte plusieurs formats dans la bibliothèque standard, comme JSON , INI , netrc y XML . Vous pouvez également trouver des paquets externes comme PyYAML y TOML . Personnellement, je trouve que JSON et YAML sont les plus simples à utiliser, et YAML permet les commentaires.
Trois éléments à prendre en compte pour les fichiers de configuration :
- Où se trouve le fichier ? Peut-être un emplacement par défaut comme
~/.my_app
et une option de ligne de commande pour utiliser un emplacement différent.
- Assurez-vous que les autres utilisateurs ne peuvent pas lire le fichier.
- Il est évident que le fichier de configuration ne doit pas être intégré au code source. Vous pourriez vouloir livrer un modèle que les utilisateurs peuvent copier dans leur répertoire personnel.
Option 4 : Module Python
Certains projets intègrent leurs secrets dans un module Python.
# settings.py
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'
Importez ensuite ce module pour obtenir les valeurs.
# my_app.py
from settings import db_server, db_user, db_password
db_connect(db_server, db_user, db_password)
Un projet qui utilise cette technique est Django . Il est évident que vous ne devez pas vous engager settings.py
dans le contrôle de source, bien que vous puissiez vouloir livrer un fichier appelé settings_template.py
que les utilisateurs peuvent copier et modifier.
Je vois quelques problèmes avec cette technique :
- Les développeurs peuvent accidentellement livrer le fichier au contrôle de source. En l'ajoutant à
.gitignore
réduit ce risque.
- Une partie de votre code n'est pas sous contrôle de source. Si vous êtes discipliné et ne mettez que des chaînes de caractères et des nombres, cela ne posera pas de problème. Si vous commencez à écrire des classes de filtres de journalisation ici, arrêtez !
Si votre projet utilise déjà cette technique, il est facile de passer aux variables d'environnement. Il suffit de déplacer toutes les valeurs de réglage vers des variables d'environnement et de modifier le module Python pour qu'il lise ces variables d'environnement.