Secrets vs Variables di GitHub Actions: Perbedaan dan Kapan Menggunakannya
Pendahuluan
Bayangkan kamu sedang membangun pipeline CI/CD untuk aplikasi seperti yang dipakai startup fintech Indonesia — kamu perlu menyimpan API key, token database, dan juga URL server staging. Pertanyaannya: di mana sebaiknya data-data ini disimpan?
GitHub Actions menyediakan dua mekanisme berbeda untuk menyimpan data konfigurasi: Secrets dan Variables. Meski terlihat mirip, keduanya memiliki tujuan, perilaku, dan tingkat keamanan yang sangat berbeda. Salah memilih bisa berakibat pada kebocoran kredensial atau konfigurasi yang sulit dikelola.
Di artikel ini, kita akan membahas perbedaan mendasar keduanya, kapan menggunakannya, dan contoh implementasi nyata di workflow GitHub Actions.
Memahami GitHub Secrets: Menyimpan Data Sensitif dengan Aman
GitHub Secrets adalah mekanisme penyimpanan data terenkripsi untuk informasi sensitif. Data yang disimpan sebagai secret tidak pernah ditampilkan dalam log workflow, bahkan jika kamu secara tidak sengaja mencoba meng-echo-nya.
Karakteristik Utama Secrets
- Terenkripsi end-to-end: Dienkripsi sebelum disimpan, hanya didekripsi saat digunakan di runner
- Tidak terbaca di log: GitHub secara otomatis menyensor nilai secret dalam output log
- Tidak bisa dibaca via API: Nilai secret tidak bisa diambil kembali setelah disimpan
- Cakupan: Repository level, Environment level, atau Organization level
Cara Menambahkan Secret
Masuk ke Settings → Secrets and variables → Actions → New repository secret.
# .github/workflows/deploy.yml
name: Deploy Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy ke server
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
API_KEY: ${{ secrets.STRIPE_API_KEY }}
run: |
echo "Connecting to database..."
# $DB_PASSWORD dipakai di sini tapi TIDAK muncul di log
./deploy.sh
Jenis Data yang Tepat Disimpan sebagai Secret
| Data | Alasan |
|---|---|
| Database password | Sensitif, tidak boleh bocor |
| API key (Stripe, Midtrans, dll) | Kredensial berbayar/berbahaya jika bocor |
| SSH private key | Akses langsung ke server |
| Token autentikasi (JWT secret) | Bisa dieksploitasi untuk forge token |
| Docker registry password | Akses ke image repository pribadi |
Memahami GitHub Variables: Mengelola Data Konfigurasi
GitHub Variables (diperkenalkan pertengahan 2023) adalah mekanisme penyimpanan nilai konfigurasi yang tidak sensitif dan dapat dibaca. Berbeda dengan secrets, variabel bisa ditampilkan di log, dilihat di UI, dan diakses via API.
Karakteristik Utama Variables
- Terbaca di log: Nilai variabel muncul normal di output workflow
- Bisa diupdate via API: Mendukung otomatisasi konfigurasi
- Tidak terenkripsi secara khusus: Disimpan sebagai plain text
- Cakupan: Repository level, Environment level, atau Organization level
Cara Menambahkan Variable
Masuk ke Settings → Secrets and variables → Actions → Variables tab → New repository variable.
# .github/workflows/build.yml
name: Build Application
on:
push:
branches: [main, develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build dengan konfigurasi environment
env:
APP_ENV: ${{ vars.APP_ENV }}
API_BASE_URL: ${{ vars.API_BASE_URL }}
MAX_RETRY_COUNT: ${{ vars.MAX_RETRY_COUNT }}
run: |
echo "Building for environment: $APP_ENV"
echo "API URL: $API_BASE_URL"
npm run build
Jenis Data yang Tepat Disimpan sebagai Variable
| Data | Alasan |
|---|---|
| URL API endpoint | Non-sensitif, perlu fleksibilitas |
Nama environment (staging, production) | Konfigurasi, bukan kredensial |
| Versi Node.js / Python yang dipakai | Parameter build |
Feature flag (true/false) | Toggle fitur antar environment |
| Slack channel ID untuk notifikasi | Referensi publik |
Perbandingan Utama: Kapan Menggunakan Secrets vs. Variables?
Berikut tabel perbandingan lengkap untuk membantu keputusan:
| Aspek | Secrets | Variables |
|---|---|---|
| Enkripsi | Ya, end-to-end | Tidak |
| Tampil di log | Tidak (disensor) | Ya |
| Bisa dibaca via API | Tidak | Ya |
| Bisa diupdate via API | Tidak | Ya |
| Cocok untuk | Kredensial, token, password | URL, flag, versi, environment name |
| Syntax di YAML | ${{ secrets.NAMA }} | ${{ vars.NAMA }} |
| Default value | Tidak ada | Tidak ada |
Aturan Sederhana
Gunakan Secret jika data tersebut bisa menyebabkan kerusakan atau kerugian jika bocor ke publik.
Gunakan Variable jika data tersebut aman ditampilkan di log dan tidak masalah jika seseorang membacanya.
Contoh Kasus Nyata: Deploy Aplikasi ke Server Staging
Mari kita lihat workflow lengkap yang mengkombinasikan secrets dan variables. Contoh ini mensimulasikan deployment aplikasi web — misalnya seperti dashboard internal yang sering dipakai startup Indonesia untuk monitoring.
Jika kamu sedang membangun aplikasi React dengan TypeScript, kamu bisa pelajari lebih lanjut di React dengan TypeScript: Komponen yang Type-Safe untuk memastikan codebase-mu type-safe sebelum di-deploy.
# .github/workflows/deploy-staging.yml
name: Deploy to Staging
on:
push:
branches: [develop]
env:
# Variables: data non-sensitif, aman di log
APP_NAME: ${{ vars.APP_NAME }}
STAGING_URL: ${{ vars.STAGING_URL }}
NODE_VERSION: ${{ vars.NODE_VERSION }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
environment: staging # Mengaktifkan environment-level secrets & variables
steps:
- uses: actions/checkout@v4
- name: Setup SSH
uses: webfactory/[email protected]
with:
# Secret: SSH private key — JANGAN pernah dijadikan variable!
ssh-private-key: ${{ secrets.STAGING_SSH_KEY }}
- name: Build aplikasi
env:
# Variable: URL API publik, aman ditampilkan
VITE_API_URL: ${{ vars.STAGING_API_URL }}
# Secret: API key untuk layanan third-party
VITE_PAYMENT_KEY: ${{ secrets.MIDTRANS_CLIENT_KEY }}
run: npm run build
- name: Deploy ke staging server
env:
# Secret: kredensial server
DEPLOY_HOST: ${{ secrets.STAGING_HOST }}
DEPLOY_USER: ${{ secrets.STAGING_USER }}
run: |
echo "Deploying $APP_NAME to $STAGING_URL"
rsync -avz --delete dist/ $DEPLOY_USER@$DEPLOY_HOST:/var/www/staging/
- name: Notifikasi Slack
uses: slackapi/[email protected]
with:
channel-id: ${{ vars.SLACK_CHANNEL_STAGING }}
slack-message: "✅ Deploy ${{ env.APP_NAME }} ke staging berhasil!"
env:
# Secret: Slack bot token
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
Jika workflow-mu melibatkan pengolahan data seperti membaca file CSV konfigurasi, kamu bisa merujuk ke panduan Panduan Praktis Python: Membaca dan Menulis File CSV untuk Pengolahan Data untuk skrip pendukungnya.
Environment-Level Secrets dan Variables
Untuk kontrol lebih granular antara environment staging dan production:
# Settings > Environments > staging > Add secret/variable
# Secrets environment level menimpa repository level
jobs:
deploy-staging:
environment: staging # Menggunakan secrets/vars dari environment 'staging'
steps:
- name: Deploy
env:
DB_URL: ${{ secrets.DB_URL }} # Pakai versi staging
APP_URL: ${{ vars.APP_URL }} # Pakai versi staging
run: ./deploy.sh
deploy-production:
environment: production # Menggunakan secrets/vars dari environment 'production'
steps:
- name: Deploy
env:
DB_URL: ${{ secrets.DB_URL }} # Pakai versi production (berbeda!)
APP_URL: ${{ vars.APP_URL }} # Pakai versi production (berbeda!)
run: ./deploy.sh
Troubleshooting: Error yang Sering Muncul
Secret Tidak Terbaca, Nilai Menjadi Empty String
Penyebab: Nama secret di workflow tidak cocok dengan nama yang didaftarkan di GitHub Settings (case-sensitive), atau secret belum ditambahkan di repository/environment yang tepat.
Solusi:
# ❌ Salah: nama tidak cocok
env:
API_KEY: ${{ secrets.api_key }} # huruf kecil, tidak cocok
# ✅ Benar: nama harus EXACT MATCH (biasanya UPPERCASE)
env:
API_KEY: ${{ secrets.API_KEY }}
# Debug: cek apakah secret ter-set (output 'true' atau 'false', bukan nilainya)
- name: Check secret exists
run: |
if [ -z "${{ secrets.API_KEY }}" ]; then
echo "Secret API_KEY is NOT set!"
exit 1
else
echo "Secret API_KEY is set."
fi
Variable Tidak Tersedia Meski Sudah Ditambahkan
Penyebab: Variable ditambahkan di level Environment, tapi workflow tidak mendeklarasikan environment: di job, sehingga environment-level variables tidak diaktifkan.
Solusi:
# ❌ Salah: environment tidak dideklarasikan
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo ${{ vars.STAGING_URL }} # Kosong jika var ada di environment level
# ✅ Benar: tambahkan deklarasi environment
jobs:
deploy:
runs-on: ubuntu-latest
environment: staging # Aktifkan environment 'staging'
steps:
- run: echo ${{ vars.STAGING_URL }} # Sekarang terbaca
Secret Muncul Sebagai *** di Log Padahal Tidak Seharusnya
Penyebab: Nilai yang tidak sengaja sama persis dengan nilai secret akan ikut disensor. Ini terjadi jika kamu menggunakan variabel biasa yang kebetulan bernilai sama dengan secret.
Solusi:
# Jika output debug-mu tiba-tiba tersensor, cek apakah value-nya
# kebetulan sama dengan salah satu secret yang terdaftar.
# Ganti nilai variable agar tidak bertabrakan dengan secret.
- name: Debug config
run: |
# Gunakan prefix/suffix agar mudah dibedakan
echo "APP_ENV value is: [env=${{ vars.APP_ENV }}]"
echo "BASE_URL is: [url=${{ vars.API_BASE_URL }}]"
Error Context access might be invalid pada Syntax Variable
Penyebab: Menggunakan syntax lama ${{ env.VAR_NAME }} untuk mengakses GitHub Variables, padahal syntax yang benar adalah ${{ vars.VAR_NAME }}.
Solusi:
# ❌ Salah: vars bukan env
steps:
- run: echo ${{ env.APP_ENV }} # Ini baca environment variable runner, bukan GitHub Variable
# ✅ Benar: gunakan vars. untuk GitHub Variables
steps:
- run: echo ${{ vars.APP_ENV }} # Ini baca GitHub Variable yang kamu set di Settings
# Keduanya berbeda:
# vars.APP_ENV → GitHub Variable (di-set di Settings UI)
# env.APP_ENV → Environment variable runner (di-set di blok env: dalam workflow)
Pertanyaan yang Sering Diajukan (FAQ)
Apa perbedaan mendasar antara Secrets dan Variables di GitHub Actions?
Secrets dirancang untuk data sensitif dan selalu terenkripsi — nilainya tidak pernah ditampilkan di log dan tidak bisa diambil kembali via API. Variables adalah untuk data konfigurasi non-sensitif yang boleh terbaca, bisa ditampilkan di log, dan bisa dikelola via API GitHub. Gunakan sintaks ${{ secrets.NAMA }} untuk secrets dan ${{ vars.NAMA }} untuk variables.
Apakah aman menyimpan URL database sebagai Variable?
Tergantung isinya. URL database yang hanya berisi host dan nama database (tanpa password) relatif aman sebagai Variable. Namun jika URL-nya berbentuk postgresql://user:password@host/db, itu harus disimpan sebagai Secret karena mengandung kredensial. Pisahkan URL host (vars.DB_HOST) dari password (secrets.DB_PASSWORD) jika perlu transparansi pada konfigurasi.
Bagaimana cara menggunakan Secrets dan Variables yang berbeda untuk staging vs. production?
Gunakan fitur Environments di GitHub. Buat dua environment (staging dan production), lalu tambahkan secrets/variables di masing-masing environment. Di workflow, deklarasikan environment: staging atau environment: production di level job — GitHub akan otomatis menggunakan secrets/variables dari environment yang sesuai.
Apakah Secret bisa diakses oleh Pull Request dari fork repository?
Tidak, secara default. GitHub Actions tidak mengizinkan workflow dari forked repository mengakses secrets repository untuk alasan keamanan. Kamu bisa mengaktifkan ini secara manual di Settings, tapi sangat tidak disarankan karena berpotensi bocor ke kontributor eksternal yang tidak dipercaya.
Berapa batas jumlah Secrets dan Variables yang bisa disimpan?
GitHub membatasi maksimum 100 secrets per repository/environment/organization, dengan ukuran nilai maksimum 64 KB. Untuk Variables, batasnya 500 variables per repository/environment/organization, dengan nilai maksimum 48 KB. Untuk kebutuhan konfigurasi yang sangat besar, pertimbangkan menyimpan file konfigurasi terenkripsi di repository dan dekripsi saat runtime.
Kesimpulan
Memahami perbedaan antara Secrets dan Variables di GitHub Actions adalah fondasi penting untuk membangun pipeline CI/CD yang aman dan mudah dikelola. Singkatnya:
- Secrets → untuk data sensitif (password, token, private key) yang tidak boleh bocor
- Variables → untuk data konfigurasi (URL, nama environment, versi tool) yang bisa dibaca
Dengan memisahkan keduanya secara tepat, kamu mendapatkan dua manfaat sekaligus: keamanan dari proteksi secrets, dan fleksibilitas dari variables yang mudah diubah tanpa menyentuh kode. Tambahkan lapisan kontrol dengan Environment-level secrets/variables untuk workflow yang melayani beberapa environment sekaligus.
Selamat membangun pipeline yang aman dan rapi! Jika ada pertanyaan atau kamu ingin eksplorasi lebih jauh tentang GitHub Actions dan DevOps, jangan ragu untuk menjelajahi artikel-artikel lainnya di KamusNgoding — masih banyak topik seru yang menunggumu!