GitLab CI Security
Pendahuluan
GitLab CI/CD adalah platform CI/CD terintegrasi yang merupakan bagian dari GitLab - baik GitLab.com (SaaS) maupun self-managed GitLab. GitLab CI menawarkan pipeline yang fleksibel dengan fitur keamanan bawaan seperti SAST, DAST, secret detection, container scanning, dan dependency scanning melalui template ready-to-use.
Keamanan pipeline GitLab CI sangat krusial karena pipeline sering
memiliki akses ke production credentials, artifact build, dan
infrastruktur cloud. Artikel ini membahas struktur
.gitlab-ci.yml, manajemen CI/CD variables, secret
detection, template keamanan, runner security, dan contoh pipeline
aman yang lengkap.
Struktur .gitlab-ci.yml
File .gitlab-ci.yml adalah jantung dari GitLab CI. File
ini mendefinisikan pipeline yang terdiri dari stages, jobs, dan
konfigurasi runner.
Contoh Struktur Dasar
stages:
- build
- test
- deploy
variables:
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
build-job:
stage: build
script:
- docker build -t app:$IMAGE_TAG .
artifacts:
paths:
- dist/
test-job:
stage: test
script:
- npm install
- npm test
dependencies:
- build-job
deploy-job:
stage: deploy
script:
- ./deploy.sh
environment: production
only:
- main
Beberapa elemen penting dari struktur di atas:
- stages: Menentukan urutan eksekusi pipeline.
- variables: Variabel yang tersedia di seluruh job.
- artifacts: File yang diteruskan antar job.
- environment: Menautkan job ke environment tertentu (production, staging).
- only/except: Aturan kapan job dijalankan.
CI/CD Variables: Masked, Protected, dan File
GitLab CI menyediakan beberapa jenis variabel untuk menyimpan informasi sensitif:
1. Masked Variables
Variabel yang dimasked akan disembunyikan di job log. GitLab
mengganti nilai variabel dengan [MASKED] di output log.
# Setting di UI: Settings > CI/CD > Variables
# Key: DEPLOY_TOKEN
# Value: glpat-xxxxxxxx
# Type: Variable
# Masked: Yes
Keterbatasan masking:
- Hanya variabel dengan panjang minimal 8 karakter yang bisa dimasked.
- Variabel tidak boleh berisi spasi atau karakter yang mudah dikenali regex.
- Masking tidak sempurna - variabel yang di-encode (base64, URL encoding) bisa lolos.
2. Protected Variables
Protected variables hanya tersedia di pipeline yang berjalan di protected branch atau protected tag. Ini mencegah developer tidak berwenang mengakses production credentials.
# Setting di UI: Settings > CI/CD > Variables
# Key: PROD_DB_PASSWORD
# Value: s3cr3t!
# Protected: Yes
# Masked: Yes
# Environment: production
3. File Variables
Untuk nilai yang sangat panjang (seperti SSH key atau sertifikat),
gunakan tipe File - variabel akan disimpan sebagai file
sementara di runner.
# Setting di UI
# Key: DEPLOY_SSH_KEY
# Value: (private key content)
# Type: File
Akses di pipeline:
deploy-job:
script:
- chmod 600 $DEPLOY_SSH_KEY
- ssh -i $DEPLOY_SSH_KEY user@server "deploy.sh"
Best Practices Variabel
- Jangan pernah mencampur variabel development dan production dalam satu project.
- Gunakan group-level variables untuk variabel yang dibagikan ke beberapa project.
- Rotasi variabel secara berkala - gunakan GitLab API untuk otomatisasi.
- Audit akses variabel secara rutin.
Secret Detection
GitLab memiliki Secret Detection bawaan yang dapat mendeteksi credentials yang tidak sengaja di-commit ke repository. Fitur ini menggunakan pola regex untuk mendeteksi berbagai jenis secret.
Mengaktifkan Secret Detection
include:
- template: Jobs/Secret-Detection.gitlab-ci.yml
secret_detection:
stage: test
variables:
SECRET_DETECTION_HISTORIC_SCAN: "true"
Dengan SECRET_DETECTION_HISTORIC_SCAN: "true",
GitLab juga memindai commit lama - bukan hanya commit terbaru.
Secret Detection Rules Kustom
GitLab memungkinkan Anda menambahkan custom rules untuk secret detection:
# .gitlab/secret_detection_rules.toml
[[rules]]
id = "custom-api-key"
description = "Custom API Key detection"
path = ".*\\.key$"
regex = "(?i)myapp-api-key-[a-zA-Z0-9]{32}"
Template SAST dan DAST
GitLab menyediakan template siap pakai untuk berbagai jenis
security scanning melalui include: template.
SAST (Static Application Security Testing)
include:
- template: Jobs/SAST.gitlab-ci.yml
stages:
- test
- security
sast:
stage: security
variables:
SAST_EXCLUDED_ANALYZERS: "eslint, nodejs-scan"
SAST_EXCLUDED_PATHS: "vendor, node_modules, tests"
SEARCH_MAX_DEPTH: 8
Template SAST GitLab secara otomatis mendeteksi bahasa pemrograman yang digunakan dan menjalankan analyzer yang sesuai (Semgrep, SpotBugs untuk Java, brakeman untuk Ruby, bandit untuk Python).
DAST (Dynamic Application Security Testing)
include:
- template: DAST.gitlab-ci.yml
stages:
- build
- test
- dast
dast:
stage: dast
variables:
DAST_WEBSITE: https://staging.example.com
DAST_BROWSER_SCAN: "true"
DAST_FULL_SCAN: "true"
environment:
name: staging
DAST GitLab menggunakan tool analisis dinamis untuk memindai aplikasi yang sedang berjalan. Mode browser scan menggunakan headless browser untuk aplikasi JavaScript-heavy, sementara full scan mengaktifkan pengujian yang lebih agresif.
Container Scanning
include:
- template: Jobs/Container-Scanning.gitlab-ci.yml
container_scanning:
stage: security
variables:
CI_APPLICATION_REPOSITORY: $CI_REGISTRY_IMAGE
CI_APPLICATION_TAG: $CI_COMMIT_SHORT_SHA
DOCKER_IMAGE: alpine:latest
Container scanning menggunakan Trivy di backend untuk memindai kerentanan di image Docker.
Dependency Scanning
include:
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
dependency_scanning:
stage: security
variables:
DS_DEFAULT_ANALYZERS: "gemnasium"
DS_EXCLUDED_PATHS: "test, spec, vendor"
Dependency scanning memeriksa library dan package yang digunakan untuk kerentanan yang diketahui. Gemnasium analyzer mendeteksi kerentanan di berbagai ekosistem seperti npm, pip, Maven, dan Composer.
License Compliance
include:
- template: Jobs/License-Scanning.gitlab-ci.yml
license_scanning:
stage: security
variables:
LICENSE_MANAGEMENT_LICENSE_FILE: "license-report.json"
License compliance memeriksa lisensi dari setiap dependency yang digunakan, memastikan kepatuhan terhadap kebijakan organisasi.
Auto DevOps GitLab
Auto DevOps adalah pendekatan batteries-included yang mengonfigurasi pipeline lengkap secara otomatis - dari build hingga deploy ke Kubernetes, termasuk semua security scanning.
Mengaktifkan Auto DevOps
- Buka project di GitLab.
- Pergi ke Settings > CI/CD > Auto DevOps.
- Centang Default to Auto DevOps pipeline.
Atau aktifkan melalui file .gitlab-auto-devops.yml:
# .gitlab-auto-devops.yml
auto_devops:
script:
- echo "Auto DevOps enabled"
Contoh Pipeline Auto DevOps Lengkap
# .gitlab-ci.yml dengan Auto DevOps terintegrasi
variables:
SECURE_LOG_LEVEL: info
include:
- template: Auto-DevOps.gitlab-ci.yml
# Override konfigurasi template Auto DevOps
stages:
- build
- test
- security
- review
- dast
- staging
- canary
- production
- performance
- cleanup
build:
stage: build
image: docker:24.0.5
services:
- docker:24.0.5-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
sast:
stage: security
variables:
SAST_EXCLUDED_ANALYZERS: "eslint"
dast:
stage: dast
variables:
DAST_WEBSITE: https://review-$CI_ENVIRONMENT_SLUG.example.com
DAST_FULL_SCAN: "true"
secret_detection:
stage: security
container_scanning:
stage: security
variables:
CI_APPLICATION_REPOSITORY: $CI_REGISTRY_IMAGE
CI_APPLICATION_TAG: $CI_COMMIT_SHORT_SHA
dependency_scanning:
stage: security
license_scanning:
stage: security
deploy:
stage: production
environment:
name: production
only:
- main
script:
- kubectl set image deployment/my-app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Pipeline ini secara otomatis menjalankan: SAST, DAST, Secret Detection, Container Scanning, Dependency Scanning, dan License Compliance - tanpa perlu konfigurasi manual.
Runner Security
GitLab CI menggunakan runner untuk mengeksekusi job. Ada dua jenis runner: shared dan specific.
Shared vs Specific Runner
| Aspek | Shared Runner | Specific Runner |
|---|---|---|
| Available to | Semua project di instance/group | Project tertentu saja |
| Cost | Gratis hingga batas tertentu (GitLab.com) | Dikelola sendiri |
| Security | Isolasi via VM/container | Kontrol penuh |
| Tag | shared |
docker, macos, dll |
Security Best Practices untuk Runner
# .gitlab-ci.yml - gunakan tag untuk memilih runner yang tepat
test-job:
tags:
- docker
script:
- npm test
deploy-job:
tags:
- production
script:
- ./deploy.sh
Untuk self-managed runner:
- Gunakan Docker executor - setiap job berjalan di container baru tanpa akses ke host.
# config.toml untuk Docker executor
[[runners]]
name = "docker-runner-01"
url = "https://gitlab.com/"
token = "xxxxxxxx"
executor = "docker"
[runners.docker]
image = "ubuntu:22.04"
privileged = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
-
Nonaktifkan
privilegedmode - jangan pernah memberikan akses root penuh ke container runner. -
Batasi concurrent jobs - cegah satu runner mengeksekusi terlalu banyak job bersamaan.
[[runners]]
limit = 2 # maksimal 2 job concurrent
concurrent = 2
-
Gunakan runner ephemeral - hancurkan runner setelah setiap job untuk mencegah data bocor.
-
Firewall ketat - runner hanya boleh mengakses GitLab server dan resource yang diperlukan.
-
Update rutin - pastikan GitLab Runner selalu diperbarui ke versi terbaru.
Contoh Pipeline Secure Lengkap
Berikut adalah contoh pipeline production-grade yang mengintegrasikan semua fitur keamanan:
# .gitlab-ci.yml - Secure Pipeline
image: node:18-alpine
stages:
- lint
- security
- test
- build
- deploy
variables:
NPM_CONFIG_CACHE: $CI_PROJECT_DIR/.npm
NODE_ENV: test
# Cache untuk mempercepat instalasi
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .npm/
- node_modules/
lint-job:
stage: lint
script:
- npm ci
- npm run lint
- npm run format:check
# Template keamanan dari GitLab
include:
- template: Jobs/SAST.gitlab-ci.yml
- template: Jobs/Secret-Detection.gitlab-ci.yml
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
sast:
stage: security
variables:
SAST_EXCLUDED_ANALYZERS: "eslint, nodejs-scan"
SAST_EXCLUDED_PATHS: "node_modules, test"
secret_detection:
stage: security
dependency_scanning:
stage: security
unit-test:
stage: test
script:
- npm ci
- npm test -- --coverage
artifacts:
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
build:
stage: build
image: docker:24.0.5
services:
- docker:24.0.5-dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
only:
- main
container-scan:
stage: security
image: docker:24.0.5
services:
- docker:24.0.5-dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
script:
- apk add --no-cache curl
- curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- trivy image --severity CRITICAL,HIGH --exit-code 0 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- trivy image --severity CRITICAL --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
dependencies:
- build
only:
- main
deploy-staging:
stage: deploy
variables:
NODE_ENV: staging
script:
- echo "Deploying to staging server..."
- chmod 400 $STAGING_SSH_KEY
- ssh -o StrictHostKeyChecking=no -i $STAGING_SSH_KEY [email protected] "docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA && docker-compose up -d"
environment:
name: staging
url: https://staging.example.com
only:
- main
needs: ["unit-test", "sast", "secret_detection", "dependency_scanning", "container-scan"]
deploy-production:
stage: deploy
variables:
NODE_ENV: production
script:
- echo "Deploying to production server..."
- chmod 400 $PRODUCTION_SSH_KEY
- ssh -o StrictHostKeyChecking=no -i $PRODUCTION_SSH_KEY [email protected] "docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA && docker-compose up -d"
environment:
name: production
url: https://app.example.com
only:
- main
needs: ["deploy-staging"]
when: manual
Pipeline di atas menerapkan:
- SAST, Secret Detection, Dependency Scanning melalui template GitLab.
- Container scanning dengan Trivy - pipeline gagal jika ada kerentanan CRITICAL.
- Stage terpisah untuk keamanan - security gate sebelum deploy.
- Deployment manual ke production - membutuhkan persetujuan manusia.
- SSH key sebagai File variable - aman dan terproteksi.
- Hanya branch main yang bisa deploy ke production.
Kesimpulan
Keamanan GitLab CI/CD membutuhkan pendekatan berlapis. Mulai dari manajemen variabel yang aman (masked, protected, file variables), pemanfaatan template SAST/DAST/secret scanning, hingga konfigurasi runner yang aman. GitLab Auto DevOps menyediakan fondasi keamanan yang solid, tetapi tetap membutuhkan penyesuaian sesuai kebutuhan organisasi. Dengan mengintegrasikan security scanning di setiap stage pipeline, Anda dapat mendeteksi dan memperbaiki kerentanan sebelum mencapai production.