TDCTF Academy Logo TDCTF ACADEMY

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:

  1. Arbitrary code execution: Workflow dari pull request dapat mengeksekusi kode berbahaya di runner.
  2. Persistent storage: Data antar workflow execution mungkin bocor.
  3. 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:

  1. OIDC authentication untuk deployment, bukan PAT.
  2. Environment protection untuk production.
  3. Container scanning menggunakan Trivy.
  4. Secret scanning dan upload hasil ke GitHub Security tab.
  5. Least privilege permissions di setiap job.
  6. 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.

PADA HALAMAN INI