web-dev-qa-db-fra.com

Quelle est la meilleure pratique pour gérer les mots de passe dans les référentiels git?

J'ai un petit script Bash que j'utilise pour accéder à Twitter et faire apparaître une notification de Growl dans certaines situations. Quelle est la meilleure façon de gérer le stockage de mon mot de passe avec le script?

Je voudrais valider ce script dans le dépôt Git et le rendre disponible sur GitHub, mais je me demande quel est le meilleur moyen de garder mon identifiant/mon mot de passe confidentiel tout en faisant cela. Actuellement, le mot de passe est stocké dans le script lui-même. Je ne peux pas l'enlever juste avant I Push car tous les anciens commits contiendront le mot de passe. Développer sans mot de passe n'est pas une option. J'imagine que je devrais stocker le mot de passe dans un fichier de configuration externe, mais je pensais que je vérifierais s'il existait un moyen établi de gérer cela avant d'essayer de mettre quelque chose en place.

196
kubi

Pour ce faire, vous devez généralement lire les informations de mot de passe à partir d'un fichier de configuration. Si votre fichier de configuration s'appelle foobar.config, vous devez alors valider un fichier nommé foobar.config.example au référentiel contenant des exemples de données. Pour exécuter votre programme, vous devez créer un fichier local (non suivi) appelé foobar.config avec vos vrais données de mot de passe.

Pour filtrer votre mot de passe existant des validations précédentes, voir la page d'aide de GitHub sur Supprimer les données sensibles .

230
Greg Hewgill

Une approche peut être de définir un mot de passe (ou une clé API) à l'aide d'une variable d'environnement. Donc, ce mot de passe est hors contrôle de révision.

Avec Bash, vous pouvez définir une variable d'environnement à l'aide de

export your_env_variable='your_password'

Cette approche peut être utilisée avec des services d'intégration continue tels que Travis , votre code (sans mot de passe) étant stocké dans un GitHub Le référentiel peut être exécuté par Travis (votre mot de passe étant défini à l'aide d'une variable d'environnement).

Avec Bash, vous pouvez obtenir la valeur d'une variable d'environnement en utilisant:

echo "$your_env_variable"

Avec Python, vous pouvez obtenir la valeur d’une variable d’environnement en utilisant:

import os
print(os.environ['your_env_variable'])

PS: sachez que c'est probablement un peu risqué (mais que c'est une pratique assez courante) https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment -variables/

PS2: ceci dev.to article intitulé "Comment stocker en toute sécurité des clés d’API" peut être intéressant à lire.

24
scls

Quoi dit Greg mais j'ajouterai que c'est une bonne idée de archiver un fichier foobar.config-TEMPLATE.

Il devrait contenir des exemples de noms, mots de passe ou autres informations de configuration. Il est alors très évident que le vrai foobar.config doit contenir, sans avoir à chercher dans tout le code pour lequel des valeurs doivent être présentes dans foobar.config et quel format ils devraient avoir.

Les valeurs de configuration peuvent souvent ne pas être évidentes, comme les chaînes de connexion à la base de données et des choses similaires.

16
Prof. Falken

On peut utiliser Vault qui sécurise, stocke et contrôle l’accès aux jetons, mots de passe, certificats, clés API, etc. Par exemple Ansible utilise le Ansible Vault qui traite des mots de passe ou des certificats utilisés dans les playbooks

2
El Ruso

Voici une technique que j'utilise:

Je crée un dossier dans mon dossier personnel appelé: .config

Dans ce dossier, je place les fichiers de configuration pour un nombre quelconque d'éléments pour lesquels je souhaite externaliser des mots de passe et des clés.

J'utilise généralement une syntaxe de nom de domaine inversé telle que:

com.example.databaseconfig

Ensuite, dans le script bash, je fais ceci:

#!/bin/bash
source $HOME/.config/com.example.databaseconfig ||exit 1

Le || exit 1 provoque la fermeture du script s’il ne parvient pas à charger le fichier de configuration.

J'ai utilisé cette technique pour les scripts bash, python et ant.

Je suis assez paranoïaque et je ne pense pas qu'un fichier .gitignore soit suffisamment robuste pour empêcher un enregistrement accidentel. De plus, il n'y a rien à surveiller, donc si un enregistrement se produisait, personne ne le découvrirait.

Si une application particulière nécessite plusieurs fichiers, je crée un sous-dossier plutôt qu'un seul fichier.

2
Michael Potter

Traiter les mots de passe dans les référentiels serait traité de différentes manières en fonction de votre problème exact.

1. Ne le fais pas.

Et des moyens d'éviter de faire sont abordés dans certaines réponses - .gitignore, config.example, etc.

ou 2. Rendre le référentiel accessible uniquement aux personnes autorisées

C'est à dire. les personnes autorisées à connaître le mot de passe. chmod et les groupes d’utilisateurs me viennent à l’esprit; Des problèmes tels que les employés de Github ou AWS devraient-ils être autorisés à voir les choses si vous hébergez vos référentiels ou vos serveurs en externe?

ou 3. Crypter les données sensibles (objet de cette réponse)

Si vous souhaitez stocker vos fichiers de configuration contenant des informations sensibles (telles que des mots de passe) dans un emplacement public, vous devez les chiffrer. Les fichiers peuvent être déchiffrés une fois récupérés du référentiel, ou même utilisés directement à partir de leur forme chiffrée.

Un exemple de solution javascript permettant d’utiliser des données de configuration chiffrées est présenté ci-dessous.

const fs = require('fs');
const NodeRSA = require('node-rsa');

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));
const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');

console.log('decrypted: ', config);

Decrypted Config File

Ainsi, vous pouvez récupérer un fichier de configuration chiffré en écrivant quelques lignes Javascript.

Notez que mettre un fichier config.RSA dans un référentiel git en ferait un fichier binaire, ce qui ferait perdre beaucoup des avantages de quelque chose comme Git, par exemple. capacité à choisir les changements.

La solution à ce problème pourrait être de chiffrer des paires clé-valeur ou peut-être simplement des valeurs. Vous pouvez chiffrer toutes les valeurs, par exemple si vous avez un fichier distinct pour les informations sensibles, ou chiffrer uniquement les valeurs sensibles si vous avez toutes les valeurs dans un seul fichier. (voir ci-dessous)

Mon exemple ci-dessus est un peu inutile pour quiconque veut faire un test avec, ou comme exemple de départ car il suppose l'existence de certaines clés RSA et d'un fichier de configuration chiffré. config.RSA.

Voici donc quelques lignes de code supplémentaires ajoutées pour créer des clés RSA et un fichier de configuration pour jouer.

const fs = require('fs');
const NodeRSA = require('node-rsa');

/////////////////////////////
// Generate some keys for testing
/////////////////////////////

const examplekey = new NodeRSA({b: 2048});

fs.writeFileSync('private.key', examplekey.exportKey('pkcs8-private'));
fs.writeFileSync('public.key', examplekey.exportKey('pkcs8-public'));

/////////////////////////////
// Do this on the Machine creating the config file
/////////////////////////////

const configToStore = {Goodbye: 'Cruel world'};

let publickey = new NodeRSA();
publickey.importKey(fs.readFileSync('public.key', 'utf8'));

fs.writeFileSync('config.RSA', publickey.encrypt(configToStore, 'base64'), 'utf8');

/////////////////////////////
// Do this on the Machine consuming the config file
/////////////////////////////

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));

const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');
console.log('decrypted: ', config);

Cryptage de valeurs uniquement

fs.writeFileSync('config.RSA', JSON.stringify(config,null,2), 'utf8');

enter image description here

Vous pouvez déchiffrer un fichier de configuration avec des valeurs chiffrées en utilisant quelque chose comme ceci.

const savedconfig = JSON.parse(fs.readFileSync('config.RSA', 'utf8'));
let config = {...savedconfig};
Object.keys(savedconfig).forEach(key => {
    config[key] = privatekey.decrypt(savedconfig[key], 'utf8');
});

Avec chaque élément de configuration sur une ligne distincte (par exemple, Hello et Goodbye ci-dessus), Git reconnaîtra mieux ce qui se passe dans un fichier et stockera les modifications apportées aux éléments d'information sous forme de différences plutôt que de fichiers complets. . Git sera également capable de mieux gérer les fusions et les choix de cerises, etc.

Cependant, plus vous souhaitez contrôler la version des modifications apportées aux informations sensibles, plus vous vous dirigez vers une solution SAFE REPOSITORY (2) et plus loin qu'une solution ENCRYPTED INFO (3).

1
Ivan

Si vous utilisez Ruby sur Rails, le bijou Figaro est très bon, facile et fiable. Il a également un facteur de mal de tête faible dans l'environnement de production.

0
ahnbizcad

Faites confiance mais vérifiez.

Dans .gitignore ceci exclurait un répertoire "sécurisé" du référentiel:

secure/

Mais je partage la paranoïa de @ Michael Potter . Donc, pour vérifier .gitignore, voici un test unitaire Python qui déclencherait un klaxon si ce répertoire "sécurisé" est vérifié Et pour vérifier, un répertoire légitime est également testé:

def test_github_not_getting_credentials(self):
    safety_url = 'https://github.com/BobStein/fliki/tree/master/static'
    danger_url = 'https://github.com/BobStein/fliki/tree/master/secure'

    self.assertEqual(200, urllib.request.urlopen(safety_url).status)

    with self.assertRaises(urllib.error.HTTPError):
        urllib.request.urlopen(danger_url)
0
Bob Stein