Rahasia di Repository Git: .gitignore, Environment Variable, dan Membersihkan History
Kesalahan yang paling mengerikan bagi seorang developer adalah ketika secara tidak sengaja melakukan git commit dan git push pada berkas yang berisi API Key, password database, atau SSH private key. Kepanikan biasanya muncul saat menyadari bahwa menghapus berkas tersebut dalam commit baru tidak benar-benar menghilangkan rahasia dari repository.
Git dirancang untuk tidak pernah melupakan. Setiap perubahan disimpan dalam snapshot permanen. Jika sebuah rahasia pernah masuk ke dalam riwayat commit, maka rahasia itu akan ada di sana selamanya—sampai riwayat tersebut ditulis ulang secara paksa.
Artikel ini membahas cara mengelola rahasia dengan benar, mencegah kebocoran melalui .gitignore, dan langkah-langkah pemulihan ketika kebocoran sudah terjadi.
Ringkasan
- Menghapus berkas di commit baru tidak menghapus datanya dari riwayat Git.
.gitignoremencegah berkas masuk ke index, tapi tidak berlaku untuk berkas yang sudah terlanjur di-track..git/info/excludedigunakan untuk mengabaikan berkas lokal tanpa membagikan aturan tersebut ke anggota tim lain.git log -S(pickaxe) dapat digunakan untuk melacak kapan sebuah string rahasia pertama kali masuk ke riwayat.- Solusi satu-satunya untuk kebocoran rahasia adalah rotasi key segera, diikuti dengan pembersihan riwayat jika diperlukan.
- Penggunaan Environment Variable dan file
.envadalah standar industri, namun file.envtidak boleh di-commit.
Mengapa Menghapus Berkas Tidak Cukup?
Banyak developer mengira bahwa melakukan git rm secret.txt kemudian melakukan commit adalah cara yang benar untuk menghapus rahasia. Namun, ini adalah kesalahpahaman fatal.
Git menyimpan seluruh riwayat perubahan. Jika Anda melihat riwayat commit sebelumnya, berkas secret.txt masih ada di sana dengan seluruh isinya. Siapa pun yang meng-clone repository Anda dapat dengan mudah berpindah ke commit lama dan mengambil rahasia tersebut.
Melacak Kebocoran dengan Git Log -S (Pickaxe)
Git menyediakan fitur pencarian konten yang disebut “pickaxe”. Dengan git log -S, Anda bisa mencari commit mana yang memperkenalkan string tertentu ke dalam codebase.
# Mencari commit yang menambahkan string "API_KEY=secret123"
git log -S "API_KEY=secret123" --onelineJika perintah ini menghasilkan output, berarti rahasia Anda masih ada di dalam riwayat Git, meskipun berkasnya sudah tidak terlihat di commit terbaru.
Strategi Pencegahan: .gitignore dan .git/info/exclude
Pencegahan adalah pertahanan terbaik. Ada dua cara utama untuk memberitahu Git agar mengabaikan berkas tertentu.
1. .gitignore (Shared Ignore)
Berkas .gitignore berada di root repository dan di-commit bersama kode. Ini adalah daftar global yang berlaku bagi semua pengembang yang mengkloning repo tersebut. Gunakan ini untuk mengabaikan:
- Folder dependensi (misal:
node_modules/,venv/). - Berkas build/binary (misal:
*.exe,dist/). - Konfigurasi lokal yang umum (misal:
.env).
2. .git/info/exclude (Local Ignore)
Kadang Anda memiliki berkas konfigurasi lokal yang hanya Anda gunakan, dan Anda tidak ingin mengotori .gitignore tim dengan aturan pribadi Anda. Untuk itu, gunakan .git/info/exclude.
Berkas ini bekerja persis seperti .gitignore, tetapi tidak pernah di-commit ke repository. Ini adalah tempat terbaik untuk mengabaikan catatan pribadi (notes.txt) atau tool lokal yang Anda gunakan.
| Fitur | .gitignore | .git/info/exclude |
|---|---|---|
| Lokasi | Root Repository | .git/info/exclude |
| Ter-commit | Ya (Shared) | Tidak (Local Only) |
| Penggunaan | Standar proyek | Preferensi developer lokal |
| Cakupan | Semua anggota tim | Hanya mesin Anda |
Mengelola Rahasia dengan Environment Variable
Menghindari penyimpanan rahasia di dalam kode (hardcoded) adalah prinsip dasar keamanan. Solusi standar adalah menggunakan Environment Variable.
Pola File .env
Developer biasanya membuat file .env untuk menyimpan konfigurasi lokal:
DB_PASSWORD=supersecret123
API_KEY=abc-123-xyzSangat Penting: File .env harus selalu masuk ke .gitignore. Sebagai gantinya, sediakan file .env.example yang berisi kunci tanpa nilai asli, sehingga developer lain tahu variabel apa saja yang perlu mereka siapkan.
Mengakses Variabel di Aplikasi
Alih-alih menulis password di kode, aplikasi membaca variabel dari lingkungan sistem. Contoh di Bash:
# Menggunakan variabel lingkungan
db_pass=$DB_PASSWORD
connect_db --password "$db_pass"Dengan pola ini, rahasia tetap berada di memori proses atau dikelola oleh secret manager (seperti HashiCorp Vault, AWS Secrets Manager, atau GitHub Secrets), bukan di dalam repository.
Protokol Pemulihan: Apa yang Harus Dilakukan Jika Bocor?
Jika Anda menyadari bahwa sebuah rahasia telah di-commit dan di-push ke server, jangan panik, tetapi bertindaklah dengan cepat. Mengacu pada panduan keamanan GitHub on Secrets, langkah pertama adalah memitigasi akses.
Langkah 1: Rotasi Key (Wajib)
Ini adalah langkah paling krusial. Anggap rahasia tersebut sudah dikompromikan. Menghapus riwayat Git tidak menjamin tidak ada orang yang sudah mengunduh atau meng-index rahasia tersebut.
- Generate key baru.
- Update semua layanan yang menggunakan key tersebut.
- Cabut (revoke) key yang lama.
Langkah 2: Pembersihan Riwayat (Deep Clean)
Setelah key dirotasi, Anda mungkin ingin menghapus jejak rahasia dari riwayat untuk menjaga kebersihan repo. Karena Git adalah database konten (content-addressable storage), Anda tidak bisa sekadar menghapus file; Anda harus menulis ulang seluruh pohon commit.
Menggunakan git filter-repo
Tool modern yang direkomendasikan oleh dokumentasi resmi Git adalah git filter-repo. Tool ini jauh lebih cepat dan lebih aman daripada git filter-branch yang sudah usang.
Berikut adalah contoh cara menghapus file sensitif dari seluruh riwayat:
# Instalasi (biasanya via pip atau package manager)
# pip install git-filter-repo
# Hapus file rahasia dari semua commit
git filter-repo --path secret.txt --invert-pathsPerintah --invert-paths memberitahu Git untuk mempertahankan semua file kecuali secret.txt. Setelah menjalankan ini, Git akan menghitung ulang semua hash commit.
Mekanisme Internal: Mengapa Ini Sulit?
Dalam Git, setiap commit merujuk pada sebuah “tree” (direktori), dan tree merujuk pada “blob” (isi file). Jika Anda mengubah satu blob di commit tahun 2020, hash dari commit tersebut berubah. Karena commit tahun 2021 merujuk ke hash 2020, maka hash 2021 juga berubah. Efek domino ini berlanjut hingga commit terbaru (HEAD).
Inilah alasan mengapa pembersihan riwayat disebut sebagai “rewrite history” dan mengapa hal ini sangat berbahaya bagi tim yang bekerja secara kolaboratif.
Langkah 3: Force Push dan Koordinasi Tim
Setelah riwayat dibersihkan secara lokal, Anda harus mengunggahnya ke server:
git push origin --force --allPeringatan Keras: Setiap anggota tim yang memiliki clone repository tersebut sekarang berada dalam kondisi “diverged”. Mereka tidak boleh melakukan git pull biasa, karena Git akan mencoba menggabungkan (merge) riwayat lama yang kotor dengan riwayat baru yang bersih, yang justru akan mengembalikan rahasia tersebut ke dalam repo.
Anggota tim harus melakukan:
git fetch origin
git reset --hard origin/mainRekomendasi Praktis dan Tooling Otomatis
Menghandle kebocoran secara manual sangat melelahkan. Standar industri saat ini adalah menggunakan “Secret Scanning”.
- Pre-commit Hooks: Gunakan tool seperti
pre-commitdengan plugindetect-secretsuntuk memblokir commit yang mengandung pola API key sebelum sempat masuk ke commit lokal. - CI/CD Scanning: Integrasikan Gitleaks ke dalam pipeline GitHub Actions atau GitLab CI. Jika ditemukan secret, pipeline akan gagal dan deployment dihentikan.
- Secret Management: Berhenti menyimpan secret di file teks. Gunakan solusi seperti HashiCorp Vault, AWS Secrets Manager, atau Azure Key Vault yang menyediakan rotasi otomatis dan audit log.
- Jangan pernah mengandalkan
git rmuntuk menghapus rahasia; gunakan rotasi key. - Gunakan
.gitignoreuntuk aturan tim dan.git/info/excludeuntuk aturan pribadi. - Selalu sertakan
.env.examplesebagai panduan konfigurasi. - Pasang tool pemindaian rahasia di pipeline CI/CD untuk mencegah kebocoran sebelum terjadi.
- Gunakan double quotes
"$VAR"saat memanggil environment variable di Bash untuk menghindari word splitting jika nilai variabel mengandung spasi.