GitHub Actions Security
Pendahuluan
GitHub Actions adalah platform CI/CD bawaan GitHub yang memungkinkan otomatisasi workflow pengembangan perangkat lunak - dari build, test, hingga deploy. Namun, fleksibilitas yang ditawarkan GitHub Actions juga membawa risiko keamanan yang signifikan. Workflow yang tidak dikonfigurasi dengan benar dapat menjadi pintu masuk bagi attacker untuk mengeksekusi kode berbahaya, mencuri credentials, atau mengompromikan rantai pasok perangkat lunak.
Artikel ini membahas struktur workflow GitHub Actions, security hardening yang wajib diterapkan, risiko dari third-party actions, keamanan self-hosted runner, dan praktik permission minimization. Setiap bagian dilengkapi dengan contoh konfigurasi konkret yang dapat langsung diterapkan.
Struktur Workflow GitHub Actions
Workflow GitHub Actions didefinisikan dalam file YAML yang disimpan
di direktori .github/workflows/. Struktur dasar sebuah
workflow terdiri dari:
- Trigger event: Menentukan kapan workflow dijalankan (push, pull_request, schedule).
- Jobs: Satu atau lebih pekerjaan yang berjalan secara paralel atau berurutan.
- Steps: Langkah-langkah individual dalam sebuah job, yang dapat berupa perintah shell atau action yang sudah di-publish.
Contoh Workflow Dasar
Berikut adalah contoh workflow sederhana untuk menjalankan unit test pada setiap pull request:
name: CI
on:
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
Meskipun terlihat sederhana, workflow di atas memiliki beberapa celah
keamanan yang perlu diperhatikan: menggunakan
pull_request_target tanpa hati-hati, tidak membatasi
permissions, dan menggunakan action tanpa pinned commit.
Security Hardening untuk GitHub Actions
1. OIDC vs PAT (Personal Access Token)
Salah satu keputusan keamanan paling kritis dalam CI/CD adalah bagaimana workflow mengotentikasi diri ke cloud provider atau layanan eksternal.
PAT (Personal Access Token) adalah metode tradisional - menyimpan token di GitHub Secrets dan menggunakannya di workflow. Masalahnya: token bersifat long-lived, sulit dirotasi, dan jika bocor dapat digunakan untuk akses yang tidak terbatas.
OIDC (OpenID Connect) adalah pendekatan modern yang
jauh lebih aman. Dengan OIDC, workflow meminta token
short-lived dari GitHub yang hanya valid untuk satu
eksekusi workflow. Cloud provider memverifikasi klaim OIDC seperti
repository, ref, dan
environment sebelum mengeluarkan token akses.
Contoh Konfigurasi OIDC dengan AWS:
name: Deploy to AWS
on:
push:
branches: [main]
permissions:
id-token: write # meminta OIDC token
contents: read # membaca repo
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: ap-southeast-1
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster production \
--service my-service \
--force-new-deployment
Di sisi AWS, konfigurasi IAM role harus membatasi subjek OIDC hanya untuk repository dan branch tertentu:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:organisasi/nama-repo:ref:refs/heads/main"
}
}
}
]
}
2. Environment Protection Rules
GitHub Environments memungkinkan Anda menambahkan protection rules sebelum deployment ke environment tertentu. Rules ini termasuk:
- Required reviewers: Deployment harus disetujui oleh reviewer tertentu.
- Wait timer: Menunda deployment selama waktu tertentu.
- Branch restrictions: Hanya branch tertentu yang boleh deploy.
Contoh Environment dengan Protection Rules:
name: Production Deployment
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./deploy.sh
Untuk mengaktifkan protection rules, buka Settings > Environments > production, lalu aktifkan Required reviewers dan pilih tim yang berwenang.
3. Secrets Management
GitHub Actions menyediakan encrypted secrets yang dapat diakses di workflow. Namun, ada beberapa best practices yang harus diikuti:
- Gunakan Repository Secrets untuk rahasia spesifik repo.
- Gunakan Organization Secrets untuk rahasia yang dibagikan ke beberapa repo.
- Gunakan Environment Secrets untuk rahasia yang hanya dibutuhkan di environment tertentu (seperti production).
Praktik aman secrets:
# BURUK - mengekspos secret ke semua step
jobs:
build:
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/deploy
# BAIK - hanya mengekspos secret di step yang membutuhkan
jobs:
build:
steps:
- name: Build
run: docker build -t app .
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: ./deploy.sh
Peringatan: Jangan pernah menggunakan
echo atau print untuk menampilkan secret.
GitHub secara otomatis meredact secret dari log, tetapi mekanisme
ini tidak sempurna - secret yang di-encode (base64, URL-encoded)
mungkin lolos dari redaction.
Risiko Third-Party Actions
Ekosistem GitHub Actions memungkinkan siapa saja untuk mempublikasikan action. Ini membawa risiko keamanan serius:
Pinned Commits vs Version Tags
Menggunakan action dengan version tag seperti
v3 atau @v3 berbahaya karena tag bersifat
mutable - pemilik action dapat mengubah apa yang dirujuk oleh tag
tersebut, memperkenalkan kode berbahaya ke workflow Anda.
Contoh berbahaya:
- uses: some-user/malicious-action@v1 # tag bisa diubah kapan saja
Praktik aman - pinned commit:
- uses: some-user/action@e21d5f8e8c5c4b3a2a1f0d9e8c7b6a5f4e3d2c1
Namun, menggunakan pinned commit menyulitkan pembaruan. Solusi kompromi yang baik adalah menggunakan Dependabot untuk memperbarui action secara otomatis:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "github-actions"
Action Verification
GitHub memverifikasi action dari verified creators dengan
tanda centang biru. Action dari GitHub Verified Creators (seperti
actions/checkout,
docker/build-push-action) telah melalui proses
verifikasi. Namun, tetap gunakan pinned commit untuk action
ini.
Untuk action dari sumber tidak dikenal, selalu audit kode sumbernya sebelum digunakan. Anda dapat melihat source code action di repository masing-masing.
Self-Hosted Runner Security
Self-hosted runner memberikan kontrol penuh atas lingkungan eksekusi workflow, tetapi juga membawa risiko besar. Workflow yang berjalan di self-hosted runner memiliki akses ke sistem host.
Risiko utama self-hosted runner:
- Arbitrary code execution: Workflow dari pull request dapat mengeksekusi kode berbahaya di runner.
- Persistent storage: Data antar workflow execution mungkin bocor.
- Network access: Runner mungkin memiliki akses ke jaringan internal.
Best practices untuk self-hosted runner:
# Konfigurasi runner di level repository
# Settings > Actions > Runners
# Batasi workflow yang boleh menggunakan self-hosted runner
jobs:
sensitive-job:
runs-on: self-hosted
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Deploy to internal server
run: ./deploy-internal.sh
Rekomendasi keamanan untuk self-hosted runner:
- Jangan gunakan self-hosted runner untuk workflow dari pull request forked.
- Isolasi runner menggunakan container atau VM.
- Gunakan ephemeral runner yang dihancurkan setelah setiap eksekusi.
- Batasi akses jaringan runner menggunakan firewall.
- Selalu perbarui sistem operasi dan software runner.
Permission Minimization
Setiap workflow harus memiliki permission yang paling minimal. Prinsip least privilege berlaku di sini.
Membatasi permissions di level workflow:
name: Lint and Test
on: [pull_request]
# Hanya memberikan permission yang dibutuhkan
permissions:
contents: read # membaca kode repo
issues: none # tidak perlu akses issues
pull-requests: none # tidak perlu akses PR
checks: write # perlu menulis status check
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linter
run: npm run lint
Membatasi permissions di level job:
jobs:
deploy:
permissions:
contents: read
deployments: write # hanya job ini yang punya akses deployments
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Dengan membatasi permissions, Anda mengurangi dampak jika workflow dikompromikan.
Contoh Pipeline CI/CD Aman Lengkap
Berikut adalah contoh pipeline CI/CD yang menerapkan semua praktik keamanan di atas:
name: Secure CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
security-scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
scan-type: fs
format: sarif
output: trivy-results.sarif
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
test:
needs: security-scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
pip install -r requirements.txt
pytest --junitxml=test-results.xml
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results.xml
build-and-scan:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:${{ github.sha }} .
- name: Scan container image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
format: sarif
output: container-scan.sarif
- name: Upload container scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: container-scan.sarif
deploy:
needs: build-and-scan
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
environment:
name: production
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
aws-region: ap-southeast-1
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster production \
--service my-service \
--force-new-deployment
Pipeline ini menerapkan:
- OIDC authentication untuk deployment, bukan PAT.
- Environment protection untuk production.
- Container scanning menggunakan Trivy.
- Secret scanning dan upload hasil ke GitHub Security tab.
- Least privilege permissions di setiap job.
- Pinned action versions dengan Dependabot untuk pembaruan otomatis.
Kesimpulan
Keamanan GitHub Actions bukan sekadar tentang menyimpan rahasia dengan benar, melainkan pendekatan holistik yang mencakup struktur workflow, mekanisme autentikasi, pemilihan action, konfigurasi runner, dan manajemen permission. Dengan menerapkan OIDC, environment protection rules, pinned commits, dan permission minimization, Anda dapat secara signifikan mengurangi risiko keamanan di pipeline CI/CD Anda.