Was ist die beste Vorgehensweise für den Umgang mit Passwörtern in Git-Repositories?

225

Ich habe ein kleines Bash-Skript, mit dem ich auf Twitter zugreifen und in bestimmten Situationen eine Growl-Benachrichtigung anzeigen kann. Was ist der beste Weg, um mein Passwort mit dem Skript zu speichern?

Ich möchte dieses Skript für das Git-Repo festlegen und auf GitHub verfügbar machen, frage mich jedoch, wie ich mein Login / Passwort dabei am besten privat halten kann. Derzeit ist das Passwort im Skript selbst gespeichert. Ich kann es nicht direkt vor dem Push entfernen, da alle alten Commits das Passwort enthalten. Entwickeln ohne Passwort ist keine Option. Ich stelle mir vor, dass ich das Passwort in einer externen Konfigurationsdatei speichern sollte, aber ich dachte, ich würde prüfen, ob es einen etablierten Weg gibt, damit umzugehen, bevor ich versuchte, etwas zusammenzustellen.

kubi
quelle

Antworten:

256

Der typische Weg, dies zu tun, besteht darin, die Passwortinformationen aus einer Konfigurationsdatei zu lesen. Wenn Ihre Konfigurationsdatei aufgerufen wird foobar.config, schreiben Sie eine aufgerufene Datei foobar.config.examplean das Repository, die Beispieldaten enthält. Um Ihr Programm auszuführen, erstellen Sie eine lokale (nicht verfolgte) Datei, die foobar.configmit Ihren tatsächlichen Kennwortdaten aufgerufen wird .

Informationen zum Herausfiltern Ihres vorhandenen Kennworts aus früheren Commits finden Sie auf der GitHub-Hilfeseite zum Entfernen vertraulicher Daten .

Greg Hewgill
quelle
4
Übrigens können Sie dem Repo ein Beispiel für foobar.config hinzufügen und dann der .ignore-Datei foobar.config hinzufügen. Auf diese Weise wird das Beispiel foobar.config beim Klonen angezeigt und Ihre tatsächlichen Passwörter werden nicht zum Repo hinzugefügt.
Mr_Chimp
16
@Mr_Chimp: Die .gitignoreDatei gilt nicht für verfolgte Dateien, die sich bereits im Repository befinden. Fügt beispielsweise git add -ueine geänderte Datei hinzu, auch wenn sie bereits vorhanden ist .gitignore.
Greg Hewgill
1
Als Ergänzung finden Sie hier einen interessanten Link für den Fall, dass Sie die Konfigurationsdatei versehentlich hinzugefügt haben und sie aus dem Git-Verlauf löschen möchten: help.github.com/articles/remove-sensitive-data
Loïc Lopes
16
Wie würden Sie diese Passwörter mit Ihrem Team teilen? Eine Sache ist, eine lokale Kopie zu haben (nicht an das Repo gebunden), die andere ist, sie mit einem größeren Team von sogar mit automatischen Tools (für die Bereitstellung usw.) zu
teilen
2
Ich habe die gleiche Frage wie @dangonfast. Dies scheint für ein großes Team nicht praktisch zu sein.
Jacob Stamm
25

Ein Ansatz kann darin bestehen, ein Kennwort (oder einen API-Schlüssel) mithilfe einer Umgebungsvariablen festzulegen. Dieses Passwort befindet sich also außerhalb der Revisionskontrolle.

Mit Bash können Sie Umgebungsvariablen mit festlegen

export your_env_variable='your_password'

Dieser Ansatz kann mit kontinuierlichen Integrationsdiensten wie Travis verwendet werden. Ihr in einem GitHub- Repository gespeicherter Code (ohne Kennwort) kann von Travis ausgeführt werden (wobei Ihr Kennwort mithilfe der Umgebungsvariablen festgelegt wird).

Mit Bash können Sie den Wert einer Umgebungsvariablen abrufen, indem Sie:

echo "$your_env_variable"

Mit Python können Sie den Wert einer Umgebungsvariablen abrufen, indem Sie:

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

PS: Seien Sie sich bewusst, dass es wahrscheinlich ein bisschen riskant ist (aber es ist eine weit verbreitete Praxis). Https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2: Dieser dev.toArtikel mit dem Titel "So speichern Sie API-Schlüssel sicher" ist möglicherweise interessant zu lesen.

scls
quelle
1
Wie kann verhindert werden, dass der potenzielle "unsichere" Code, der erstellt wird, den Inhalt Ihrer Umgebungsvariablen liest?
Gorootde
16

Was Greg gesagt hat, aber ich möchte hinzufügen, dass es eine gute Idee ist, eine Datei einzuchecken foobar.config-TEMPLATE.

Es sollte Beispielnamen, Kennwörter oder andere Konfigurationsinformationen enthalten. Dann ist es sehr offensichtlich, was die echte foobar.config enthalten sollte, ohne im gesamten Code nachsehen zu müssen, in foobar.configwelchen Werten vorhanden sein muss und welches Format sie haben sollten.

Oft sind Konfigurationswerte nicht offensichtlich, wie z. B. Datenbankverbindungszeichenfolgen und ähnliche Dinge.

Prof. Falken Vertrag verletzt
quelle
7

Der Umgang mit Passwörtern in Repositorys wird je nach genauem Problem unterschiedlich behandelt.

1. Tu es nicht.

Und Möglichkeiten, dies zu vermeiden, werden in einigen Antworten behandelt - .gitignore, config.example usw.

oder 2. Repository nur autorisierten Personen zugänglich machen

Dh Leute, die das Passwort kennen dürfen. chmodund Benutzergruppen kommen in den Sinn; Auch Probleme wie sollten Github- oder AWS-Mitarbeiter sehen dürfen, wenn Sie Ihre Repositorys oder Server extern hosten?

oder 3. Verschlüsseln Sie die sensiblen Daten (Zweck dieser Antwort)

Wenn Sie Ihre Konfigurationsdateien, die vertrauliche Informationen (wie Kennwörter) enthalten, an einem öffentlichen Ort speichern möchten, müssen diese verschlüsselt werden. Die Dateien können bei der Wiederherstellung aus dem Repository entschlüsselt oder sogar direkt aus ihrer verschlüsselten Form verwendet werden.

Ein Beispiel für eine Javascript-Lösung zur Verwendung verschlüsselter Konfigurationsdaten ist unten dargestellt.

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

Entschlüsselte Konfigurationsdatei

So können Sie eine verschlüsselte Konfigurationsdatei wiederherstellen, in der nur wenige Zeilen Javascript geschrieben sind.

Beachten Sie, dass das Einfügen einer Datei config.RSAin ein Git-Repository diese effektiv zu einer Binärdatei machen würde und daher viele der Vorteile von etwas wie Git verlieren würde, z. B. die Möglichkeit, Änderungen daran vorzunehmen.

Die Lösung hierfür könnte darin bestehen, Schlüsselwertpaare oder möglicherweise nur Werte zu verschlüsseln. Sie können alle Werte verschlüsseln, z. B. wenn Sie eine separate Datei für vertrauliche Informationen haben, oder nur die vertraulichen Werte verschlüsseln, wenn Sie alle Werte in einer Datei haben. (siehe unten)

Mein Beispiel oben ist für jeden, der einen Test damit durchführen möchte, oder als Beispiel für den Anfang, da davon ausgegangen wird, dass einige RSA-Schlüssel und eine verschlüsselte Konfigurationsdatei vorhanden sind, etwas nutzlos config.RSA.

Hier sind einige zusätzliche Codezeilen, die zum Erstellen von RSA-Schlüsseln und einer Konfigurationsdatei zum Spielen hinzugefügt wurden.

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

Nur Werte verschlüsseln

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

Geben Sie hier die Bildbeschreibung ein

Mit so etwas können Sie eine Konfigurationsdatei mit verschlüsselten Werten entschlüsseln.

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

Mit jedem Konfigurationselement in einer separaten Zeile (z. B. Hellound Goodbyehöher) erkennt Git besser, was in einer Datei vor sich geht, und speichert Änderungen an Informationen als Unterschiede und nicht als vollständige Dateien. Git wird auch in der Lage sein, Zusammenführungen und Cherry Picks usw. besser zu verwalten.

Je mehr Sie Änderungen an vertraulichen Informationen in der Versionskontrolle vornehmen möchten, desto mehr bewegen Sie sich in Richtung einer SAFE REPOSITORY-Lösung (2) und weg von einer ENCRYPTED INFO (3) -Lösung.

Ivan
quelle
3

Man kann Vault verwenden, das den Zugriff auf Token, Kennwörter, Zertifikate, API-Schlüssel usw. sichert, speichert und steuert. Ansible verwendet beispielsweise Ansible Vault, das sich mit Kennwörtern oder Zertifikaten befasst, die in Playbooks verwendet werden

El Ruso
quelle
Ich finde Ansible Vault sicherlich zu komplex im Vergleich zum Erstellen einer Beispielkonfigurationsdatei.
icc97
@ icc97 Ja es ist traurig wahr. Aber wir müssen diese Möglichkeit erwähnen. Meiner Meinung nach ist es für Aufgaben, die komplexer sind als das Speichern weniger Kennwörter für eine Einzelbenutzerumgebung, besser, von Anfang an spezielle Lösungen zu verwenden.
El Ruso
2
Um zukünftigen Lesern zu helfen: Vault und Ansible Vault sind ganz unterschiedliche, nicht verwandte Projekte mit ähnlichen Namen
bltavares
2

Hier ist eine Technik, die ich benutze:

Ich erstelle in meinem Home-Ordner einen Ordner mit dem Namen: .config

In diesem Ordner platziere ich die Konfigurationsdateien für eine beliebige Anzahl von Dingen, die ich Passwörter und Schlüssel auslagern möchte.

Ich verwende normalerweise die umgekehrte Domainnamensyntax wie:

com.example.databaseconfig

Dann mache ich im Bash-Skript Folgendes:

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

Das || exit 1bewirkt , dass das Skript zu beenden , wenn es nicht in der Lage ist , die Konfigurationsdatei zu laden.

Ich habe diese Technik für Bash-, Python- und Ant-Skripte verwendet.

Ich bin ziemlich paranoid und denke nicht, dass eine Gitignore-Datei robust genug ist, um ein versehentliches Einchecken zu verhindern. Außerdem wird es nicht überwacht. Wenn also ein Check-in stattfinden würde, würde niemand herausfinden, ob er damit umgehen kann.

Wenn eine bestimmte Anwendung mehr als eine Datei benötigt, erstelle ich einen Unterordner anstelle einer einzelnen Datei.

Michael Potter
quelle
1

Wenn Sie Rubin auf Schienen verwenden, ist der Figaro-Edelstein sehr gut, einfach und zuverlässig. Es hat auch in der Produktionsumgebung einen geringen Kopfschmerzfaktor.

ahnbizcad
quelle
4
Können Sie einige Details darüber geben, was dieses Juwel tut? Auf diese Weise könnte es (möglicherweise) als eine "Praxis" angesehen werden, die in vielen Sprachen anwendbar ist.
Mattumotu
medium.com/@MinimalGhost/… hat einen Überblick, es scheint im Grunde zu verwalten, Sachen aus einer Konfigurationsdatei zu ziehen
Tripleee
0

Vertrauen, aber überprüfen.

In .gitignorediesem Fall würde ein "sicheres" Verzeichnis vom Repo ausgeschlossen:

secure/

Aber ich teile @ Michael Potters Paranoia. So .gitignore , um zu überprüfen, hier ist ein Python Unit - Test , der eine klaxon erhöhen würde , wenn diese „sicher“ Verzeichnis jemals wird eingecheckt und die Prüfung zu überprüfen, ein legitimes Verzeichnis zu getestet wird.:

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)
Bob Stein
quelle