Qual è la migliore pratica per gestire le password nei repository git?


225

Ho un piccolo script Bash che uso per accedere a Twitter e visualizzare una notifica Growl in determinate situazioni. Qual è il modo migliore per gestire la memorizzazione della mia password con lo script?

Vorrei impegnare questo script nel repository git e renderlo disponibile su GitHub, ma mi chiedo quale sia il modo migliore per mantenere privati ​​il ​​mio login / password mentre lo faccio. Attualmente, la password è memorizzata nello script stesso. Non riesco a rimuoverlo prima di premere perché tutti i vecchi commit conterranno la password. Lo sviluppo senza password non è un'opzione. Immagino che dovrei archiviare la password in un file di configurazione esterno, ma ho pensato di verificare se esistesse un modo stabilito per gestirlo prima di provare a mettere insieme qualcosa.

Risposte:


256

Il modo tipico per farlo è leggere le informazioni sulla password da un file di configurazione. Se viene chiamato il file di configurazione, è foobar.confignecessario eseguire il commit di un file chiamato foobar.config.examplenel repository, contenente i dati di esempio. Per eseguire il programma, è necessario creare un file locale (non monitorato) chiamato foobar.configcon i dati della password reale .

Per filtrare la password esistente da precedenti commit, consultare la pagina di aiuto di GitHub su Rimozione di dati riservati .


4
A proposito, puoi aggiungere un esempio foobar.config al repository e quindi aggiungere foobar.config al file .ignore. In questo modo apparirà l'esempio foobar.config quando clonato e le tue password effettive non verranno aggiunte al repository.
Mr_Chimp,

16
@Mr_Chimp: il .gitignorefile non si applica ai file tracciati che sono già nel repository. Ad esempio, git add -uaggiungerà un file modificato anche se è già presente .gitignore.
Greg Hewgill,

1
Come complemento, ecco un link interessante nel caso in cui tu abbia aggiunto il file di configurazione per errore e desideri eliminarlo dalla cronologia git: help.github.com/articles/remove-sensitive-data
Loïc Lopes

16
Come vorresti condividere queste password con il tuo team? Una cosa è avere una copia locale (non impegnata nel repository), l'altra è condividerla con un team più grande anche con strumenti automatici (per la distribuzione, ecc.)
blueFast

2
Ho la stessa domanda di @dangonfast. Questo non sembra pratico per una grande squadra.
Jacob Stamm,

25

Un approccio può essere quello di impostare la password (o chiave API) utilizzando una variabile di ambiente. Quindi questa password è fuori controllo di revisione.

Con Bash, puoi impostare la variabile d'ambiente usando

export your_env_variable='your_password'

Questo approccio può essere utilizzato con servizi di integrazione continua come Travis , il codice (senza password) archiviato in un repository GitHub può essere eseguito da Travis (con la password impostata mediante la variabile di ambiente).

Con Bash, puoi ottenere il valore di una variabile d'ambiente usando:

echo "$your_env_variable"

Con Python, puoi ottenere il valore di una variabile d'ambiente usando:

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

PS: tieni presente che probabilmente è un po 'rischioso (ma è una pratica abbastanza comune) https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2: questo dev.toarticolo intitolato "Come archiviare in modo sicuro le chiavi API" può essere interessante da leggere.


1
Come evitare che il potenziale codice "non sicuro" creato dalla lettura del contenuto della variabile di ambiente?
Gorootde,


16

Quello che Greg ha detto, ma aggiungerei che è una buona idea archiviare un file foobar.config-TEMPLATE.

Dovrebbe contenere nomi di esempio, password o altre informazioni di configurazione. Quindi è molto ovvio che cosa dovrebbe contenere il vero foobar.config, senza dover cercare in tutto il codice per quali valori devono essere presenti foobar.confige in quale formato dovrebbero avere.

Spesso i valori di configurazione possono essere non ovvi, come stringhe di connessione al database e cose simili.


7

La gestione delle password nei repository verrebbe gestita in modi diversi a seconda del problema esatto.

1. Non farlo.

E i modi per evitare di farlo sono trattati in alcune risposte: .gitignore, config.example, ecc

o 2. Rendere il repository accessibile solo alle persone autorizzate

Vale a dire persone a cui è permesso conoscere la password. chmode vengono in mente gruppi di utenti; anche problemi come dovrebbero consentire ai dipendenti di Github o AWS di vedere cose se si ospitano i propri repository o server esternamente?

o 3. Crittografare i dati sensibili (scopo di questa risposta)

Se si desidera archiviare i file di configurazione contenenti informazioni riservate (come password) in un luogo pubblico, è necessario crittografarli. I file potrebbero essere decrittografati quando recuperati dal repository o persino utilizzati direttamente dalla loro forma crittografata.

Di seguito è mostrata una soluzione javascript di esempio per l'utilizzo di dati di configurazione crittografati.

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);

File di configurazione decrittografato

Quindi puoi recuperare un file di configurazione crittografato scrivendo solo poche righe di Javascript.

Si noti che l'inserimento di un file config.RSAin un repository git lo renderebbe effettivamente un file binario e quindi perderebbe molti dei vantaggi di qualcosa come Git, ad esempio la capacità di selezionare le modifiche.

La soluzione potrebbe essere quella di crittografare coppie di valori chiave o forse solo valori. È possibile crittografare tutti i valori, ad esempio se si dispone di un file separato per le informazioni riservate o crittografare solo i valori sensibili se si hanno tutti i valori in un unico file. (vedi sotto)

Il mio esempio di cui sopra è un po 'inutile per chiunque voglia fare un test con esso, o come esempio per iniziare dal momento che presuppone l'esistenza di alcune chiavi RSA e un file di configurazione crittografato config.RSA.

Quindi ecco alcune righe extra di codice aggiunte per creare chiavi RSA e un file di configurazione con cui giocare.

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);

Crittografia dei soli valori

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

inserisci qui la descrizione dell'immagine

Puoi decrittografare un file di configurazione con valori crittografati usando qualcosa del genere.

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

Con ogni elemento di configurazione su una riga separata (ad es. HelloE Goodbyesopra), Git riconoscerà meglio cosa sta succedendo in un file e memorizzerà le modifiche agli elementi di informazione come differenze piuttosto che come file completi. Git sarà anche in grado di gestire meglio le fusioni e le selezioni di ciliegie, ecc.

Tuttavia, più si desidera controllare le modifiche alle informazioni sensibili in una versione, più ci si sposta verso una soluzione di REPOSITORY SICURA (2) e si allontana da una soluzione di INFORMAZIONI CRIPTATE (3).


3

È possibile utilizzare Vault che protegge, archivia e controlla l'accesso a token, password, certificati, chiavi API, ecc. Ad esempio Ansible utilizza Ansible Vault che si occupa di password o certificati utilizzati nei playbook


Trovo Ansible Vault eccessivamente complesso rispetto alla semplice creazione di un file di configurazione di esempio.
icc97,

@ icc97 Sì, è triste vero. Ma dobbiamo menzionare questa possibilità. A mio avviso, per attività più complesse, quindi archiviare poche password per l'ambiente per utente singolo è meglio utilizzare soluzioni specializzate fin dall'inizio.
El Ruso,

2
Per aiutare i lettori futuri: Vault e Ansible Vault sono progetti non correlati con nomi simili
bltavares

2

Ecco una tecnica che uso:

Creo una cartella nella mia cartella home denominata: .config

In quella cartella inserisco i file di configurazione per qualsiasi numero di cose che voglio esternalizzare password e chiavi.

In genere utilizzo la sintassi del nome di dominio inverso come:

com.example.databaseconfig

Quindi nello script bash faccio questo:

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

Il || exit 1 provoca la chiusura dello script se non è in grado di caricare il file di configurazione.

Ho usato quella tecnica per script bash, python e ant.

Sono abbastanza paranoico e non credo che un file .gitignore sia sufficientemente robusto da impedire un check-in involontario. Inoltre, non c'è nulla che lo controlli, quindi se si verificava un check-in nessuno avrebbe scoperto di gestirlo.

Se una particolare applicazione richiede più di un file, creo una sottocartella anziché un singolo file.


1

Se stai usando il rubino sulle rotaie, la gemma Figaro è molto buona, facile e affidabile. Ha un basso livello di mal di testa anche nell'ambiente di produzione.


4
Puoi darci qualche dettaglio su cosa fa quella gemma? In questo modo potrebbe (potenzialmente) essere considerata una 'pratica' applicabile in molte lingue.
Mattumotu,

medium.com/@MinimalGhost/… ha una panoramica, in pratica sembra riuscire a estrarre roba da un file di configurazione
tripleee

0

Fidarsi ma verificare.

In .gitignorequesto escluderebbe una directory "sicura" dal repository:

secure/

Ma condivido la paranoia di @Michael Potter . Quindi, per verificare .gitignore, ecco un test di unità Python che solleverebbe un klaxon se questa directory "sicura" viene mai verificata. E per controllare la verifica, viene testata anche una directory legittima:

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.