Langsung ke konten
KamusNgoding
Menengah Github-actions 6 menit baca

Secrets vs Variables di GitHub Actions: Perbedaan dan Kapan Menggunakannya

#github-actions #secrets #variables #security

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

DataAlasan
Database passwordSensitif, tidak boleh bocor
API key (Stripe, Midtrans, dll)Kredensial berbayar/berbahaya jika bocor
SSH private keyAkses langsung ke server
Token autentikasi (JWT secret)Bisa dieksploitasi untuk forge token
Docker registry passwordAkses 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

DataAlasan
URL API endpointNon-sensitif, perlu fleksibilitas
Nama environment (staging, production)Konfigurasi, bukan kredensial
Versi Node.js / Python yang dipakaiParameter build
Feature flag (true/false)Toggle fitur antar environment
Slack channel ID untuk notifikasiReferensi publik

Perbandingan Utama: Kapan Menggunakan Secrets vs. Variables?

Berikut tabel perbandingan lengkap untuk membantu keputusan:

AspekSecretsVariables
EnkripsiYa, end-to-endTidak
Tampil di logTidak (disensor)Ya
Bisa dibaca via APITidakYa
Bisa diupdate via APITidakYa
Cocok untukKredensial, token, passwordURL, flag, versi, environment name
Syntax di YAML${{ secrets.NAMA }}${{ vars.NAMA }}
Default valueTidak adaTidak 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!

Artikel Terkait