Insiden penghapusan massal repositori atau modifikasi kode berbahaya oleh akun pengelola—seperti insiden pada proyek OpenMandriva—menunjukkan kelemahan tata kelola hak akses Git tradisional. Risiko sabotase internal, pengambilalihan akun (account takeover), atau mantan kontributor yang hak aksesnya belum dicabut dapat melumpuhkan sistem pengiriman kode secara instan jika kontrol branch dan kredensial deployment tidak dibatasi dengan ketat.
Mitigasi serangan semacam ini menuntut penguatan (hardening) pada dua pilar utama: kontrol integritas cabang utama melalui GitHub Rulesets atau GitLab Protected Branches, serta eliminasi token statis jangka panjang dari pipeline CI/CD menggunakan OpenID Connect (OIDC).
1. Hardening Integritas Branch dengan GitHub Rulesets
Pengaturan branch protection tradisional sering kali diterapkan per branch dan rentan terlewat pada repositori baru. Menggunakan GitHub Repository Rulesets memungkinkan penegakan aturan secara deklaratif, terpusat, dan tidak dapat dilewati bahkan oleh pengguna dengan peran Maintainer atau Admin (kecuali diberikan izin bypass khusus).
{
"name": "Enforce Branch Integrity",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["refs/heads/main", "refs/heads/production"],
"exclude": []
}
},
"rules": [
{
"type": "deletion"
},
{
"type": "non_fast_forward"
},
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 2,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": true,
"require_last_push_approval": true
}
},
{
"type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": true,
"required_status_checks": [
{"context": "security/sast"},
{"context": "test/integration"}
]
}
}
],
"bypass_actors": []
}Aturan di atas memblokir dua vektor serangan destruktif utama:
- Block Deletion & Non-Fast-Forward: Mencegah
git push --forcedan penghapusan ref cabang secara langsung, memastikan riwayat commit tidak dapat dimanipulasi atau dihilangkan. - Strict Pull Request Review: Parameter
dismiss_stale_reviews_on_pushmembatalkan persetujuan jika ada commit baru yang disisipkan setelah review disetujui, menangkal injeksi payload di detik terakhir. Kosongkanbypass_actorsagar admin tunduk pada aturan yang sama saat berinteraksi normal.
2. Eliminasi Long-Lived Secrets Menggunakan OIDC
Menyimpan kredensial cloud permanen (seperti AWS IAM Access Keys) di dalam CI/CD secrets mengandung risiko eksfiltrasi oleh aktor jahat via modifikasi pipeline script. Solusi standar industri saat ini adalah menggunakan OpenID Connect (OIDC) untuk menukar token JWT jangka pendek (berlaku < 1 jam) dengan peran IAM cloud.
Contoh implementasi GitHub Actions workflow untuk deployment ke AWS tanpa token statis:
name: Secure Deployment Pipeline
on:
push:
branches: [ main ]
permissions:
id-token: write # Diperlukan untuk meminta OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeploymentRole
aws-region: ap-southeast-1
role-session-name: GitHubActionsDeploymentSession
- name: Deploy Application
run: |
aws s3 sync ./dist s3://prod-app-assets --deletePada sisi penyedia cloud (AWS IAM), kunci keamanan terletak pada Trust Relationship Policy yang mengikat peran hanya ke branch dan repositori tertentu:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:perusahaan/aplikasi-core:ref:refs/heads/main"
}
}
}
]
}Jika penyerang membuat branch baru atau melakukan fork, klaim sub pada token tidak akan cocok, sehingga STS (Security Token Service) menolak penerbitan kredensial sementara.
3. Isolasi CI/CD Runners dan Environment Protection
Runner CI/CD yang dieksekusi di infrastruktur bersama (self-hosted runners) rentan terhadap pembajakan proses atau akses lateral ke jaringan internal. Terapkan prinsip isolasi berikut:
- Ephemeral Runner: Gunakan arsitektur ephemeral runner (misalnya via Kubernetes Actions Runner Controller / ARC). Setiap job dieksekusi dalam pod/container baru yang langsung dihancurkan setelah selesai untuk mencegah persistensi malware atau file sisa antar pipeline.
- Environment Protection Rules: Tetapkan konfigurasi Environment pada pipeline yang menuntut persetujuan manual (manual approval gate) dari tim rilis sebelum job deployment diizinkan membaca environment secrets atau menjalankan aksi ke infrastruktur kritis.
- Disable Fork Workflows: Batasi eksekusi workflow otomatis dari branch pull request hasil fork repositori luar untuk mencegah script berbahaya mengekstrak kredensial runner.
4. Audit Privilege dan Akses Repositori Secara Berkala
Sabotase kerap terjadi saat akun nonaktif atau mantan kontributor masih mempertahankan akses write atau admin. Jalankan audit privilege otomatis secara periodik menggunakan GitHub API via Python script untuk mendeteksi anomali akses kolaborator.
import os
import requests
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
ORG_NAME = "perusahaan"
HEADERS = {
"Authorization": f"Bearer {GITHUB_TOKEN}",
"Accept": "application/vnd.github+json"
}
def audit_repo_collaborators():
url = f"https://api.github.com/orgs/{ORG_NAME}/repos?type=all&per_page=100"
repos = requests.get(url, headers=HEADERS).json()
for repo in repos:
repo_name = repo["name"]
collab_url = f"https://api.github.com/repos/{ORG_NAME}/{repo_name}/collaborators?affiliation=direct"
collaborators = requests.get(collab_url, headers=HEADERS).json()
for collab in collaborators:
permissions = collab["permissions"]
# Flag akun non-admin yang memiliki hak modifikasi kritis
if permissions.get("admin") or permissions.get("push"):
user = collab["login"]
role = "Admin" if permissions.get("admin") else "Write"
print(f"AUDIT ALERT: Repo=[{repo_name}] | User=[{user}] | Role=[{role}]")
if __name__ == "__main__":
audit_repo_collaborators()Rekomendasi Praktis: Integrasikan skrip audit ini ke dalam jadwal mingguan. Segera hapus akses langsung (direct access) dan alihkan manajemen pengguna melalui Identity Provider (IdP) terpusat (SCIM/SAML) agar pemblokiran akun karyawan otomatis mencabut hak akses Git secara instan.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!