Tutorial Amankan CI/CD Pipeline: Sign Image Docker Pakai Cosign & Trivy
Poin Kunci Artikel Ini:
- Ancaman Supply Chain Attack pada Container RegistrySupply chain attack targetkan proses build dan distribusi container.
- Penyerang sisipkan malware ke image sebelum masuk produksi.
- Trivy jalankan audit kerentanan dan buat SBOM.
Ancaman Supply Chain Attack pada Container Registry
Supply chain attack targetkan proses build dan distribusi container. Penyerang sisipkan malware ke image sebelum masuk produksi. Kode sumber di repositori tetap bersih, eksploitasi terjadi di artifact registry.
Vektor serangan utama:
- Image Tag Mutation: Penyerang timpa isi image di registry pakai tag mutabel (
latest,v1.0.0). Kode jahat masuk tanpa ubah manifes deployment. - Compromised Dependency & Base Image: Base image tidak terverifikasi bawa kerentanan High/Critical atau backdoor.
- CI/CD Pipeline Tampering: Kredensial runner bocor. Penyerang unggah artifact buatan langsung ke registry tanpa lewat tahap uji.
Pencegahan butuh dua langkah: validasi komponen lewat Software Bill of Materials (SBOM) dan pembuktian integritas artifact pakai tanda tangan digital. Trivy jalankan audit kerentanan dan buat SBOM. Cosign jamin integritas image lewat tanda tangan cryptographic hash sha256.
Praktek Audit SBOM Trivy dan Signing Cosign di GitHub Actions
Pengamanan pipeline butuh alur terintegrasi: pemindaian dependensi, pembuatan manifest SBOM, push image ke registry, dan penandatanganan artifact.
1. Audit Kerentanan dan Generasi SBOM dengan Trivy
Trivy memindai layer Dockerfile dan package manager (npm, pip, gomod, apk, apt). Jalankan pemindaian lokal atau CI:
# Pemindaian kerentanan image dengan threshold CRITICAL
trivy image --severity HIGH,CRITICAL --exit-code 1 my-registry.com/app:v1.0.0
# Generasi SBOM format CycloneDX JSON
trivy image --format cyclonedx --output sbom.json my-registry.com/app:v1.0.0Opsi --exit-code 1 paksa CI/CD berhenti jika Trivy temukan kerentanan sesuai threshold.
2. Generasi Kunci dan Signing Image dengan Cosign
Cosign dukung dua metode: pasang kunci (private/public key) atau keyless (Sigstore Fulcio/Rekor OIDC). Pembuatan pasang kunci mandiri:
# Generate keypair (menghasilkan cosign.key dan cosign.pub)
cosign generate-key-pair
# Sign image container menggunakan private key
cosign sign --key cosign.key my-registry.com/app:v1.0.0@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Penandatanganan wajib pakai immutable digest SHA256, bukan tag mutabel. Mencegah race condition mutasi image.
3. Otomatisasi Pipeline Lengkap di GitHub Actions
Simpan workflow pada .github/workflows/build-secure.yml. Tambah COSIGN_PRIVATE_KEY dan COSIGN_PASSWORD di GitHub Repository Secrets.
name: Secure Build and Sign
on:
push:
tags:
- 'v*'
jobs:
build-scan-sign:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Local Image for Scanning
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
- name: Run Trivy Vulnerability Scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL'
- name: Generate SBOM with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
format: 'cyclonedx'
output: 'sbom.json'
- name: Build and Push Docker Image
id: build-publish
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
- name: Install Cosign
uses: sigstore/cosign-installer@v3.3.0
- name: Sign Container Image
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
cosign sign --yes --key env://COSIGN_PRIVATE_KEY \
ghcr.io/${{ github.repository }}@${{ steps.build-publish.outputs.digest }}
- name: Attest SBOM to Image
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
cosign attest --yes --key env://COSIGN_PRIVATE_KEY \
--type cyclonedx --predicate sbom.json \
ghcr.io/${{ github.repository }}@${{ steps.build-publish.outputs.digest }}Verifikasi Signature Runtime dan Troubleshooting Verification Fail
Penandatanganan tidak berguna jika runtime Kubernetes terima image tanpa validasi signature.
1. Verifikasi Manual dan Policy Enforcement
Verifikasi signature manual sebelum deploy:
cosign verify --key cosign.pub ghcr.io/user/app@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855Otomatisasi di Kubernetes gunakan Kyverno Admission Controller. Kebijakan ini menolak Pod jika image tidak memiliki tanda tangan valid dari kunci publik resmi:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/user/*"
key: |
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----2. Troubleshooting Kegagalan Verifikasi
Penanganan error umum verifikasi Cosign:
- Error:
NO_MATCHING_SIGNATUREatauentity not found in registry
Penyebab: Image di-push ulang tanpa signing baru, atau verifikasi pakai nama tag (:latest) yang beda digest.
Solusi: Gunakan digest SHA256 (@sha256:...). Pastikan step signing jalan setelah step push selesai di CI/CD. - Error:
verifying artifact: claim validation failed
Penyebab: Kunci publik untuk verifikasi tidak cocok dengan kunci privat penanda tangan.
Solusi: Cek pasangan kunci. Pastikan `COSIGN_PUBLIC_KEY` di target deployment cocok dengan `COSIGN_PRIVATE_KEY` di CI/CD. - Error:
trivy exit code 1pada Pipeline
Penyebab: Ditemukan kerentanan CRITICAL pada base image atau package OS.
Solusi: Update base image ke versi distroless/minimal terbaru (alpine:3.19ataugcr.io/distroless/static-debian12). Gunakan.trivyignorehanya untuk kerentanan false-positive terverifikasi.
Ringkasan Best Practice Keamanan Pipeline Production
Terapkan 8 poin panduan praktis berikut untuk mengamankan rantai pasokan perangkat lunak container:
- Gunakan Immutable Digest: Selalu deploy image menggunakan
image@sha256:...alih-alih tag mutabel seperti:latest. - Prinsip Least Privilege CI/CD: Batasi scope
GITHUB_TOKENhanya kepackages: writedancontents: read. - Keyless Signing jika Memungkinkan: Manfaatkan OIDC Cosign (Fulcio & Rekor) untuk mengeliminasi manajemen kunci privat jangka panjang.
- Scan Multi-Layer: Pemindaian Trivy dilakukan pada dua tahap: kode sumber/dependensi saat komit dan image akhir hasil build.
- Attestation SBOM Terintegrasi: Lampirkan (attest) berkas SBOM langsung ke image registry menggunakan Cosign agar audit compliance mudah dilakukan.
- Gunakan Base Image Minimal: Ganti base image besar (Ubuntu/Debian full) dengan Distroless atau Alpine untuk memperkecil attack surface dan jumlah CVE.
- Enforce Runtime Protection: Pasang admission controller (Kyverno/OPA Gatekeeper) di kluster Kubernetes untuk memblokir deployment image tanpa signature valid.
- Pin Action Dependencies: Kunci versi GitHub Actions menggunakan SHA commit hash, bukan versi tag (misal:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11).
Integrasi Trivy dan Cosign dalam CI/CD pipeline jadikan keamanan standar otomatis yang wajib lolos. Amankan supply chain sejak dini cegah insiden produksi. Terapkan validasi SBOM dan digital signature pada tiap proses build.


