Security automation artinya cek keamanan dijalankan mesin di tiap perubahan kode, bukan menunggu ada orang yang ingat. Bayangin pemeriksaan bagasi di bandara: semua tas lewat mesin X-ray, bukan cuma tas yang kelihatan mencurigakan, dan ban berjalannya berhenti kalau ada yang ketemu. Di CI, tiap pull request lewat security stage; kalau ada temuan serius, merge-nya diblokir sampai diperbaiki.
🧪 Tebakan cepat: pipeline-mu menjalankan
npm audit --audit-level=critical, dan ada dependency dengan celah severity high. Merge-nya diblokir atau lolos? Tebak dulu, jawabannya ada di bagian "Empat cek di security stage".
DevSecOps dan shift left
DevSecOps adalah memasukkan security ke tiap tahap DevOps, bukan menempelkannya di akhir sebelum rilis. Prinsipnya shift left: geser pengecekan ke kiri di garis waktu, sedini mungkin, karena bug yang ketemu di pull request jauh lebih murah daripada yang ketemu di production.
| Tahap | Cek otomatis | Contoh tool |
|---|---|---|
| Laptop, sebelum commit | secret scanning di pre-commit hook | gitleaks |
| Pull request (CI) | dependency audit (SCA), secret scanning, SAST | npm audit, gitleaks, Semgrep, CodeQL |
| Staging | DAST, cek security headers | OWASP ZAP, curl -sI |
| Production | logging, monitoring, alert | pelajaran Security Logging & Monitoring |
Semua tool ini sudah kamu kenal namanya: SAST dan DAST dari Secure Code Review, npm audit dari Dependency Vulnerabilities, secret scanning dari Environment Variables & Secrets, dan header dari Security Headers Lengkap. Pelajaran ini menyambungkan semuanya jadi satu gerbang.
Empat cek di security stage
Ini kasus yang sama dengan Lab: PR #57 di repo TokoKita menambah pembayaran kartu. Security stage menjalankan empat job, dan tiga di antaranya merah:
| Job | Perintah | Temuan di PR #57 |
|---|---|---|
| dependency-audit | npm audit --audit-level=high |
lodash 4.17.20, severity high (Command Injection in lodash, GHSA-35jh-r3h4-6jhm) |
| secret-scan | gitleaks | stripe-access-token di src/payment.js baris 3 |
| sast | semgrep scan --config p/owasp-top-ten --error |
query SQL dirakit dari input user di src/orders.js |
| header-check | curl -sI ke staging |
lolos: HSTS, CSP, dan nosniff terkirim |
Tiap job memberi exit code: 0 artinya lolos, selain 0 artinya gagal, dan CI menandai job itu merah.
npm auditmencocokkan tiap versi dipackage-lock.jsondengan database advisory.--audit-level=highartinya "gagal kalau ada celah high atau critical".- gitleaks mencari pola secret (kunci API, token) di kode dan history git.
semgrep ... --errormembuat Semgrep keluar dengan exit code 1 kalau ada temuan. Tanpa--error, temuannya dicetak tapi job tetap hijau.
Kalau threshold-nya dilonggarkan jadi --audit-level=critical, npm audit cuma gagal untuk celah critical. Celah lodash yang high tetap tercetak di log, tapi exit code-nya 0, job hijau, dan merge-nya lolos. Itu jawaban tebakannya. Makanya high adalah titik awal yang umum.
Workflow-nya
# .github/workflows/security.yml
name: security
on: [pull_request]
jobs:
dependency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm audit --audit-level=high
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
sast:
runs-on: ubuntu-latest
container: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- run: semgrep scan --config p/owasp-top-ten --error
header-check:
runs-on: ubuntu-latest
steps:
- run: |
headers=$(curl -sI https://staging.tokokita.id)
for h in strict-transport-security content-security-policy x-content-type-options; do
echo "$headers" | grep -qi "^$h:" || { echo "missing header: $h"; exit 1; }
done
on: [pull_request]menjalankan workflow ini di tiap pull request.- Empat job jalan paralel, jadi security stage gak bikin CI jauh lebih lama.
fetch-depth: 0mengambil seluruh history, supaya gitleaks juga memeriksa commit lama di branch itu.- Untuk repo milik organisasi,
gitleaks-actionjuga butuh secretGITLEAKS_LICENSE(gratis didaftarkan). container: semgrep/semgrepmenjalankan job di image resmi Semgrep.- Di
header-check, tiap header yang gak ketemu mencetakmissing header: ...laluexit 1.
Gerbang merge: branch protection
Job merah belum memblokir apa pun sampai kamu bilang begitu. Di GitHub, nyalakan branch protection (atau ruleset) di main dengan required status checks: keempat job wajib hijau sebelum tombol merge aktif. Tanpa itu, hasil security stage cuma jadi notifikasi yang gampang diabaikan.
- Fail fast: blokir di PR, jangan di hari rilis.
- Perbaiki temuannya, jangan matikan ceknya. Upgrade dependency (
npm audit fix, atau PR otomatis dari Dependabot), pindahkan secret ke secret manager lalu rotate, pakai query berparameter. - Kurangi noise: false positive yang sudah di-review boleh dikecualikan dengan alasan tertulis, misalnya komentar
// nosemgrepdi baris itu. Tool yang terlalu berisik akhirnya dimatikan orang.
DAST di pipeline: OWASP ZAP
Untuk DAST, OWASP ZAP punya skrip siap pakai di image Docker resminya:
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py -t https://staging.tokokita.id
zap-baseline.pymenjelajahi situs sebentar dan cuma mengamati respons (passive scan), gak menyerang. Cepat dan aman untuk tiap PR atau tiap malam.zap-full-scan.pyikut menjalankan serangan aktif, jadi lebih lama. Jalankan cuma ke staging milikmu sendiri, terjadwal.zap-api-scan.pykhusus API, membaca definisi OpenAPI atau GraphQL.- Image lamanya,
owasp/zap2docker-stable, sudah gak diperbarui. Pakaighcr.io/zaproxy/zaproxy:stable.
⚠️ Jebakan yang sering ketemu
- Threshold terlalu longgar.
--audit-level=criticalmeloloskan celah high tanpa ada yang sadar. Mulai darihigh. - Cek yang gak memblokir. Tanpa required status checks di branch protection, job merah tetap bisa di-merge.
- Lupa
--errordi Semgrep. Temuannya tercetak, job-nya hijau, dan gak ada yang membaca log-nya. - Mematikan tool yang berisik. Tune rule-nya dan kecualikan false positive satu per satu dengan alasan, jangan matikan seluruh ceknya.
TL;DR: DevSecOps memasukkan cek keamanan ke tiap tahap, dengan prinsip shift left: sedini mungkin. Security stage di tiap pull request menjalankan dependency audit (npm audit --audit-level=high), secret scanning (gitleaks), SAST (semgrep ... --error), dan cek header, paralel, dan tiap job gagal lewat exit code selain 0. Branch protection dengan required status checks yang mengubah job merah jadi merge yang diblokir. Perbaiki temuannya, jangan longgarkan threshold atau matikan ceknya. Untuk DAST, pakai zap-baseline.py dari image ghcr.io/zaproxy/zaproxy:stable di tiap PR, dan zap-full-scan.py terjadwal ke staging sendiri.