Chapter sebelumnya menutup dengan pertanyaan yang sengaja dibiarkan terbuka: tanda tangan membuktikan siapa penulis sebuah commit, tetapi tidak mengatakan apa yang boleh dilakukan penulis itu. Prinsip least privilege — hak akses minimal — menjawabnya: setiap kredensial, kunci, dan akun hanya diberi izin paling sempit yang masih memungkinkan pemegangnya menyelesaikan pekerjaannya, tidak satu poin lebih. Git inti sama sekali tidak punya model izin — seluruh penerapan terjadi di sisi yang menerima push. Kita buktikan dulu, lalu naik lapis demi lapis sampai demo nyata satu mesin dengan dua kunci berbeda izin.
Git Inti Tidak Menguji Izin #
Git menjalankan git push untuk siapa pun yang memegang kredensial yang diterima server — sisi klien tidak punya konsep “dilarang”. Sandbox membuktikannya dengan dua klon pada repository yang sama, latihan-hak, yang memakai identitas dan username kredensial berbeda; keduanya berhasil mendorong commit ke pusat.git. Konfigurasi klon pertama milik Budi:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[user]
name = Budi Santoso
email = [email protected]
[credential]
username = budi-laptop
[remote "origin"]
url = ../pusat.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/mainKlon kedua diperuntukkan bagi bot CI — konfigurasinya memuat identitas dan username kredensial yang berbeda untuk repository yang sama:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = /home/z/my-project/tutorial-extracted/work/sandbox/keamanan-dan-akses/part-b/latihan-hak/pusat.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
[user]
name = Bot CI
email = [email protected]
[credential]
username = bot-toko-ciKonfigurasi credential.username menentukan nama pengguna yang diajukan saat Git meminta kredensial HTTPS — dua klon pada repository yang sama mengajukan dua identitas. Jalur remote klon-bot absolut karena lahir dari git clone; remote klon-budi relatif karena ditambahkan manual. Setelah keduanya push, riwayat pusat memuat dua penulis:
git log --pretty=format:'%an <%ae>'Bot CI <[email protected]>
Budi Santoso <[email protected]>Pada sandbox lokal, siapa pun yang menjangkau direktori bisa mendorong apa pun. Pada platform sungguhan, server-lah yang memutuskan: kredensial yang autentik diperiksa terhadap izin yang melekat padanya, dan push ditolak bila izinnya kurang. Kolom author tetap teks bebas yang bisa dipalsukan (dibuktikan di Signed Commits ); izin sejatinya melekat pada kredensial — least privilege = memutuskan kredensial macam apa ditanamkan ke tangan mana.
Deploy Key: Satu Repository, Satu Kunci #
Untuk mesin — server deploy, runner CI, skrip backup — pilihan paling sempit bukan token milik akun, melainkan deploy key: pasangan kunci SSH yang publiknya didaftarkan pada satu repository tertentu, bukan pada sebuah akun. Saat menambahkannya di Settings → Deploy keys, tersedia opsi Allow write access; tanpa dicentang, kunci itu hanya bisa membaca — bawaannya memang read-only, sebagaimana didokumentasikan di panduan deploy keys GitHub .
| Bentuk deploy key | Izin pada repo itu | Kapan tepat |
|---|---|---|
| read-only | clone, pull, fetch | CI yang hanya build, skrip backup, server deploy |
| read-write | juga push | pipeline yang menerbitkan rilis/hasil build ke repo |
Deploy key read-write bukan kenaikan kecil: aksinya setara anggota dengan akses admin pada repository itu — berikan hanya bila mesin benar-benar harus push. Kuncinya dibuat dengan ssh-keygen biasa — sandbox menamainya sesuai peruntukannya:
ssh-keygen -t ed25519 -C "deploy-toko-ci" -f toko-deploy -N ""
cat toko-deploy.pubssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKk6fZ3lUwOuvydBlmP7yL4eTA60/dmMVD6soOwKp+CA deploy-toko-ciKunci acak per pembuatan, jadi nilainya berbeda di mesin pembaca. Baris itulah yang ditempelkan ke kolom Key; comment deploy-toko-ci membuat kunci mudah dikenali di daftar deploy key. Tiga sifatnya perlu dipegang: deploy key hanya membuka satu repository — pasangan kunci yang sama tidak bisa didaftarkan ke repo kedua; izinnya tidak terikat keanggotaan organisasi — pembuatnya keluar dari tim, kunci tetap hidup; dan tidak punya masa kedaluwarsa. Bila satu mesin butuh banyak repository, dua jalur lebih sehat daripada mengulurkan token pribadi: machine user — akun khusus otomatisasi, satu kunci per server cukup — atau GitHub App untuk integrasi resmi yang izinnya paling granular.
PAT Fine-Grained: Dua Sumbu Pembatasan #
Untuk jalur HTTPS, padanan tersempitnya adalah fine-grained personal access token, yang membatasi di dua sumbu: repository mana saja yang terbuka, dan permission apa per kategori. Keduanya dipilih saat pembuatan token — alurnya di dokumentasi pembuatan token :
| Pilihan | Sumbu repository | Permission Contents | Kapan tepat |
|---|---|---|---|
| fine-grained, 1 repo | Only select repositories: satu | Read-only | skrip backup, alat analisis |
| fine-grained, 1 repo | Only select repositories: satu | Read and write | pekerjaan harian pada proyek |
| fine-grained, beberapa repo | repo terpilih | per kebutuhan | alat lintas 2-3 repo |
| fine-grained, seluruh repo | All repositories | minimal | alat organisasi lintas repo |
klasik, scope repo | seluruh repo akun | penuh | hanya bila alat lama belum mendukung fine-grained |
Kategori permission dipilih satu per satu — Contents, Issues, Pull requests, dan seterusnya — tiap kategori bisa Read-only atau Read and write. Satu batas kerasnya: token tidak pernah bisa memberi izin melebihi yang dimiliki pemiliknya — token hanya mempersempit, bukan memperluas. Kebiasaan merawatnya — nama jujur, umur pendek, rotasi, pencabutan — dibahas tuntas di Mengelola Token .
Permission Level untuk Manusia #
Mesin terlayani kunci dan token; manusia terlayani level permission. GitHub membagi akses repository dalam lima level, dari paling sempit ke paling lebar:
| Level | Yang bisa dilakukan pemegangnya |
|---|---|
| read | melihat kode, membuka dan mengomentari issues/PR |
| triage | menambah label, assign, menutup issues/PR — tanpa menulis kode |
| write | mendorong commit, membuka dan merge pull request |
| maintain | mengelola repository — termasuk sebagian pengaturannya — tanpa aksi sensitif atau destruktif |
| admin | akses penuh: keamanan, pengaturan, anggota, menghapus repository |
Deskripsi resmi kelima level GitHub dirinci di dokumentasi repository roles . GitLab memakai lima role yang peta tanggung jawabnya serupa:
| Role GitLab | Yang bisa dilakukan pemegangnya |
|---|---|
| guest | melihat dan berkomentar pada issue; tanpa akses repository (proyek privat) |
| reporter | melihat kode dan membuka issue; tanpa push |
| developer | push ke branch non-protected, membuka merge request, menjalankan pipeline |
| maintainer | mengelola branch, merge, pengaturan CI, dan anggota |
| owner | penuh, termasuk menghapus proyek |
Aturan memilihnya: level terendah yang masih menyelesaikan pekerjaannya — kontributor kode cukup di write/developer, koordinator tanpa kode cukup di triage/reporter, admin hanya untuk pemilik yang benar-benar mengelola repository-nya.
Dua Kebiasaan yang Membuka Semua Pintu #
Dua kebiasaan menghapus semua lapisan di atas sekaligus. Pertama, token akun pribadi dipakai bot atau CI: token mewarisi seluruh izin manusianya, jejak audit jadi kacau — aktivitas bot tercatat atas nama manusia — dan hidupnya terikat karir pemilik: orangnya pindah, pipeline ikut mati. Gantinya sudah dibahas: deploy key, machine user, atau GitHub App. Kedua, berbagi akun: dua orang satu kredensial berarti riwayat aktivitas tidak bisa menunjuk siapa pun, 2FA kehilangan maknanya, dan pencabutan tidak bisa setengah-setengah — akunnya dimatikan untuk semua orang sekaligus.
Kebalikan kedua larangan itu dirangkum tabel berikut — skenario dan kredensial paling sempit yang menyelesaikannya:
| Skenario | Kredensial tepat | Alasannya |
|---|---|---|
| bot CI hanya build (pull) | deploy key read-only pada repo itu | bocor sekalipun, pelakunya tidak bisa menulis |
| rekan tim push kode | kolaborator write dengan akun + kunci SSH sendiri | izin manusia atas nama sendiri, bisa diaudit |
| kontributor eksternal | fork + pull request, tanpa akses langsung | pekerjaan masuk lewat review, seperti di Fork dan Pull Request |
| pelapor bug | read / Guest, atau cukup issues publik | melapor tidak butuh menulis kode |
| skrip backup malam hari | deploy key read-only / fine-grained Contents: Read-only | searah — cukup membaca, tidak pernah menulis |
Demo: Satu Mesin, Dua Kunci, Dua Izin #
Semua tabel di atas berhenti di kebijakan platform; bagian yang hidup di mesin lokal berikut ini. Laptop Budi membawa dua kunci: id_ed25519 (akun pribadi) dan toko-deploy (deploy key read-only untuk repository toko-buku). Berkas konfigurasi SSH memisahkan keduanya lewat alias:
# Kunci pribadi Budi — akses akun penuh
Host github-budi
HostName github.com
User git
IdentityFile /home/z/my-project/tutorial-extracted/work/sandbox/keamanan-dan-akses/part-b/latihan-hak/ssh/id_ed25519
# Kunci deploy toko-buku — read-only, terdaftar per repository
Host github-toko-ro
HostName github.com
User git
IdentityFile /home/z/my-project/tutorial-extracted/work/sandbox/keamanan-dan-akses/part-b/latihan-hak/ssh/toko-deployJalur IdentityFile di sandbox absolut menuju direktori latihan; di mesin kita cukup ~/.ssh/id_ed25519 dan ~/.ssh/toko-deploy. Tiap alias diperiksa tanpa koneksi — ssh -G mencetak opsi teratasi:
ssh -G github-toko-ro | grep -E '^(hostname|user|identityfile) 'user git
hostname github.com
identityfile /home/z/my-project/tutorial-extracted/work/sandbox/keamanan-dan-akses/part-b/latihan-hak/ssh/toko-deployssh -G github-budi | grep -E '^(hostname|user|identityfile) 'user git
hostname github.com
identityfile /home/z/my-project/tutorial-extracted/work/sandbox/keamanan-dan-akses/part-b/latihan-hak/ssh/id_ed25519Dua alias menuju host yang sama dengan kunci berbeda — dan di sinilah least privilege benar-benar bekerja: alamat remote memilih alias, alias memilih kunci, kunci menentukan izin. Klon untuk skrip cadangan memakai github-toko-ro; pekerjaan harian memakai github-budi:
git remote add cadangan github-toko-ro:budi/toko-buku.git
git remote -vcadangan github-toko-ro:budi/toko-buku.git (fetch)
cadangan github-toko-ro:budi/toko-buku.git (push)
origin ../pusat.git (fetch)
origin ../pusat.git (push)Audit Berkala #
Akses yang tidak pernah diperiksa membusuk diam-diam: orang pindah peran, kontrak habis, bot dilupakan — sementara kunci dan tokennya tetap hidup. Audit akses membandingkan dua daftar — siapa yang punya akses versus siapa yang masih membutuhkannya. Kedua daftar hidup di platform: GitHub menyediakan Settings → Collaborators per repository, halaman outside collaborators untuk organisasi, dan daftar token dengan waktu pemakaian terakhirnya (dokumentasi pengelolaan token ); GitLab menempatkannya di Project → Members.
Dari terminal, peta manusianya ditarik dari riwayat — git log --pretty=format:'%an <%ae>' | sort -u mencantumkan semua penulis yang pernah menyentuh repository. Nama di riwayat tanpa akses saat ini adalah kontributor lama, wajar; akses tanpa satu pun jejak kontribusi adalah kandidat pencabutan. Jadwalkan perbandingan ini tiap kuartal, dan segera setiap ada anggota keluar dari tim.
Kredensial yang ukurannya tepat hari ini bisa menjadi terlalu besar esok — karena itu keamanan repository bukan pemasangan sekali jadi, melainkan pemeriksaan berulang. Chapter penutup section ini menyusun seluruh pembahasan menjadi satu checklist audit yang bisa dijalankan langsung dari terminal.