Apa praktik terbaik untuk berurusan dengan kata sandi di repositori git?

225

Saya punya skrip Bash kecil yang saya gunakan untuk mengakses twitter dan memunculkan pemberitahuan Growl dalam situasi tertentu. Apa cara terbaik untuk menangani penyimpanan kata sandi saya dengan skrip?

Saya ingin mengkomit skrip ini ke git repo dan membuatnya tersedia di GitHub, tapi saya bertanya-tanya apa cara terbaik untuk menjaga kerahasiaan kata sandi / login saya saat melakukan ini. Saat ini, kata sandi disimpan dalam skrip itu sendiri. Saya tidak dapat menghapusnya tepat sebelum saya mendorong karena semua komitmen lama akan berisi kata sandi. Mengembangkan tanpa kata sandi bukanlah pilihan. Saya membayangkan bahwa saya harus menyimpan kata sandi dalam file konfigurasi eksternal, tetapi saya pikir saya akan memeriksa untuk melihat apakah ada cara yang mapan untuk menangani ini sebelum saya mencoba dan menyatukan sesuatu.

kubi
sumber

Jawaban:

256

Cara khas untuk melakukan ini adalah membaca info kata sandi dari file konfigurasi. Jika file konfigurasi Anda disebut foobar.config, maka Anda akan melakukan file bernama foobar.config.exampleke repositori, yang berisi data sampel. Untuk menjalankan program Anda, Anda akan membuat file lokal (tidak dilacak) yang disebut foobar.configdengan data kata sandi asli Anda .

Untuk memfilter kata sandi Anda yang ada dari komit sebelumnya, lihat halaman bantuan GitHub tentang Menghapus data sensitif .

Greg Hewgill
sumber
4
Btw, Anda dapat menambahkan contoh foobar.config ke repo dan kemudian menambahkan foobar.config ke file .ignore. Dengan cara ini contoh foobar.config akan muncul ketika dikloning dan kata sandi Anda yang sebenarnya tidak akan ditambahkan ke repo.
Mr_Chimp
16
@Mr_Chimp: .gitignoreFile tidak berlaku untuk file yang dilacak yang sudah ada di repositori. Misalnya, git add -uakan menambahkan file yang diubah meskipun sudah ada .gitignore.
Greg Hewgill
1
Sebagai pelengkap, berikut adalah tautan yang menarik jika Anda menambahkan file konfigurasi secara tidak sengaja dan Anda ingin menghapusnya dari sejarah git: help.github.com/articles/remove-sensitive-data
Loïc Lopes
16
Bagaimana cara Anda berbagi kata sandi dengan tim Anda? Satu hal adalah memiliki salinan lokal (tidak berkomitmen untuk repo), yang lain adalah untuk membagikannya kepada tim yang lebih besar bahkan dengan alat otomatis (untuk penyebaran, dll)
blueFast
2
Saya memiliki pertanyaan yang sama dengan @dangonfast. Ini sepertinya tidak praktis untuk tim besar.
Jacob Stamm
25

Suatu pendekatan dapat dengan mengatur kata sandi (atau kunci API) menggunakan variabel lingkungan. Jadi kata sandi ini di luar kendali revisi.

Dengan Bash, Anda dapat mengatur variabel lingkungan menggunakan

export your_env_variable='your_password'

Pendekatan ini dapat digunakan dengan layanan integrasi berkelanjutan seperti Travis , kode Anda (tanpa kata sandi) yang disimpan dalam repositori GitHub dapat dieksekusi oleh Travis (dengan kata sandi Anda diset menggunakan variabel lingkungan).

Dengan Bash, Anda bisa mendapatkan nilai variabel lingkungan menggunakan:

echo "$your_env_variable"

Dengan Python, Anda bisa mendapatkan nilai variabel lingkungan menggunakan:

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

PS: ketahuilah bahwa itu mungkin agak berisiko (tapi ini praktik yang cukup umum) https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2: dev.toartikel ini berjudul "Cara menyimpan kunci API dengan aman" mungkin menarik untuk dibaca.

scls
sumber
1
Bagaimana mencegah kode "tidak aman" potensial dari pembuatan dari membaca konten variabel lingkungan Anda?
gorootde
16

Apa yang dikatakan Greg tetapi saya akan menambahkan bahwa sebaiknya memeriksa file foobar.config-TEMPLATE.

Itu harus berisi contoh nama, kata sandi atau info konfigurasi lainnya. Maka sangat jelas apa yang seharusnya berisi foobar.config, tanpa harus melihat semua kode yang nilainya harus ada foobar.configdan format apa yang harus mereka miliki.

Seringkali nilai konfigurasi bisa tidak jelas, seperti string koneksi database dan hal serupa.

Prof. Falken
sumber
7

Berurusan dengan kata sandi dalam repositori akan ditangani dengan berbagai cara tergantung pada apa masalah Anda sebenarnya.

1. Jangan lakukan itu.

Dan cara untuk menghindari melakukan tercakup dalam beberapa balasan - .gitignore, config.example, dll

atau 2. Membuat repositori hanya dapat diakses oleh orang yang berwenang

Yaitu orang yang diizinkan untuk mengetahui kata sandi. chmoddan kelompok pengguna muncul di pikiran; juga masalah seperti apakah karyawan Github atau AWS diizinkan untuk melihat sesuatu jika Anda meng-host repositori atau server Anda secara eksternal?

atau 3. Enkripsi data sensitif (tujuan balasan ini)

Jika Anda ingin menyimpan file konfigurasi yang berisi informasi sensitif (seperti kata sandi) di lokasi publik, maka file itu harus dienkripsi. File-file itu dapat didekripsi ketika dipulihkan dari repositori, atau bahkan digunakan langsung dari formulir terenkripsi mereka.

Contoh solusi javascript untuk menggunakan data konfigurasi terenkripsi ditunjukkan di bawah ini.

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 Konfigurasi Terdekripsi

Jadi, Anda dapat memulihkan file konfigurasi terenkripsi dengan menulis beberapa baris Javascript.

Perhatikan bahwa menempatkan file config.RSAke dalam repositori git akan secara efektif menjadikannya file biner dan karenanya akan kehilangan banyak manfaat dari sesuatu seperti Git, misalnya kemampuan untuk memilih perubahan pada file tersebut.

Solusi untuk itu mungkin mengenkripsi pasangan nilai kunci atau mungkin hanya nilai. Anda dapat mengenkripsi semua nilai, misalnya jika Anda memiliki file terpisah untuk informasi sensitif, atau mengenkripsi hanya nilai-nilai sensitif jika Anda memiliki semua nilai dalam satu file. (Lihat di bawah)

Contoh saya di atas agak tidak berguna bagi siapa pun yang ingin melakukan tes dengannya, atau sebagai contoh untuk memulai karena mengasumsikan adanya beberapa kunci RSA dan file konfigurasi terenkripsi config.RSA.

Jadi, inilah beberapa baris kode tambahan yang ditambahkan untuk membuat kunci RSA dan file konfigurasi untuk dimainkan.

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

Mengenkripsi nilai saja

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

masukkan deskripsi gambar di sini

Anda dapat mendekripsi file konfigurasi dengan nilai terenkripsi menggunakan sesuatu seperti ini.

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

Dengan setiap item konfigurasi pada baris terpisah (mis. HelloDanGoodbye atas), Git akan mengenali lebih baik apa yang terjadi dalam file dan akan menyimpan perubahan pada item informasi sebagai perbedaan daripada file lengkap. Git juga akan dapat mengelola penggabungan dan pemilihan ceri dll dengan lebih baik.

Namun semakin Anda ingin mengubah kontrol perubahan pada informasi sensitif, semakin Anda bergerak menuju solusi SAFE REPOSITORY (2) dan menjauh dari solusi ENCRYPTED INFO (3).

Ivan
sumber
3

Seseorang dapat menggunakan Vault yang mengamankan, menyimpan, dan mengontrol akses ke token, kata sandi, sertifikat, kunci API, dll. Misalnya Ansible menggunakan Vault Ansible yang berkaitan dengan kata sandi atau sertifikat yang digunakan dalam buku pedoman

El Ruso
sumber
Saya menemukan Ansible Vault terlalu rumit tentunya dibandingkan dengan hanya membuat file konfigurasi contoh.
icc97
@ icc97 Ya itu menyedihkan benar. Tetapi kita perlu menyebutkan kemungkinan ini. Menurut pendapat saya, untuk tugas yang lebih kompleks daripada menyimpan beberapa kata sandi untuk lingkungan pengguna tunggal lebih baik menggunakan solusi khusus dari awal.
El Ruso
2
Untuk membantu pembaca di masa mendatang: Vault dan Ansible Vault adalah proyek yang tidak terkait yang sangat berbeda dengan nama yang serupa
bltavares
2

Berikut adalah teknik yang saya gunakan:

Saya membuat folder di folder rumah saya bernama: .config

Dalam folder itu saya menempatkan file konfigurasi untuk sejumlah hal yang ingin saya eksternalisasi kata sandi dan kunci.

Saya biasanya menggunakan sintaks nama domain terbalik seperti:

com.example.databaseconfig

Kemudian dalam skrip bash saya melakukan ini:

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

The || exit 1menyebabkan script untuk keluar jika tidak mampu memuat file konfigurasi.

Saya menggunakan teknik itu untuk skrip bash, python, dan semut.

Saya cukup paranoid dan tidak berpikir bahwa file .gitignore cukup kuat untuk mencegah check-in yang tidak disengaja. Plus, tidak ada yang memonitornya, jadi jika check-in benar-benar terjadi, tidak ada yang akan mengatasinya.

Jika aplikasi tertentu memerlukan lebih dari satu file, saya membuat subfolder daripada satu file.

Michael Potter
sumber
1

Jika Anda menggunakan ruby ​​pada rel, permata Figaro sangat bagus, mudah, dan dapat diandalkan. Ini memiliki faktor sakit kepala yang rendah dengan lingkungan produksi juga.

ahnbizcad
sumber
4
Bisakah Anda memberikan beberapa detail tentang apa yang permata lakukan? Dengan begitu, hal itu dapat (berpotensi) dianggap sebagai 'praktik' yang berlaku di banyak bahasa.
mattumotu
medium.com/@MinimalGhost/… memiliki ikhtisar, pada dasarnya sepertinya mengelola menarik hal-hal dari file konfigurasi
tripleee
0

Percaya tapi verifikasi.

Dalam .gitignorehal ini akan mengecualikan direktori "aman" dari repo:

secure/

Tapi saya berbagi paranoia @ Michael Potter . Jadi untuk memverifikasi .gitignore, berikut ini adalah unit test Python yang akan menaikkan klaxon jika direktori "aman" ini diperiksa. Dan untuk memeriksa cek, direktori yang sah juga diuji:

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
sumber