Mengapa Pipeline Aplikasi Mobile Anda Membutuhkan Penandatanganan (dan Cara Menjaganya Tetap Aman)

Anda baru saja selesai membangun aplikasi Android atau iOS. Build hijau, pengujian lolos, dan Anda siap untuk merilis. Namun, sebelum APK atau IPA tersebut bisa mendarat di perangkat siapa pun, ada satu langkah lagi yang sering terasa seperti beban birokrasi: menandatangani aplikasi.

Sangat menggoda untuk menganggap penandatanganan sebagai item centang belaka. Tapi jika Anda pernah kehilangan keystore, menyaksikan sertifikat kedaluwarsa pada Jumat malam, atau secara tidak sengaja melakukan commit provisioning profile ke repositori publik, Anda tahu di sinilah segalanya menjadi serius. Penandatanganan bukan sekadar formalitas teknis. Ini adalah lapisan keamanan yang membuktikan bahwa aplikasi Anda berasal dari Anda, bukan dari seseorang yang mengemas ulang atau menyamar sebagai identitas Anda.

Apa yang Sebenarnya Dilakukan oleh Penandatanganan

Saat Anda menandatangani aplikasi, Anda melampirkan tanda tangan digital yang mengikat biner dengan identitas Anda. Tanda tangan ini diperiksa oleh sistem operasi dan toko aplikasi. Jika tanda tangan tidak cocok, aplikasi tidak akan terinstal, atau toko akan menolak unggahan.

Untuk Android, penandatanganan menggunakan file keystore. File ini berisi kunci privat dan sertifikat digital. Anggap saja sebagai stempel resmi Anda. Setiap kali Anda membuat APK atau AAB untuk rilis, Anda mencapnya dengan keystore tersebut. Jika Anda menggunakan keystore yang berbeda nanti, Android akan memperlakukan aplikasi tersebut sebagai aplikasi yang sama sekali berbeda, meskipun nama paketnya identik. Itu berarti pengguna tidak dapat memperbarui aplikasi di atas instalasi yang sudah ada. Mereka harus menghapus versi lama terlebih dahulu, kehilangan semua data lokal.

Untuk iOS, prosesnya lebih berlapis. Anda memerlukan dua hal: sertifikat dan provisioning profile. Sertifikat adalah identitas digital Anda sebagai pengembang. Provisioning profile menghubungkan sertifikat, App ID, dan daftar perangkat yang diizinkan menjalankan aplikasi. Untuk distribusi App Store, Anda menggunakan distribution certificate dan App Store provisioning profile. Untuk pengujian internal atau pengembangan, Anda menggunakan development certificate dan ad-hoc provisioning profile.

Masalah Sebenarnya: Menjaga Kerahasiaan di Pipeline

Setelah Anda memahami apa yang diperlukan untuk penandatanganan, pertanyaan selanjutnya sudah jelas: bagaimana cara menyimpan kredensial ini di pipeline CI/CD Anda tanpa menuliskannya ke dalam kode atau file konfigurasi?

Jawabannya adalah manajemen rahasia. Tapi mari kita perjelas apa yang tidak boleh dilakukan terlebih dahulu.

Jangan pernah menyimpan keystore, sertifikat, atau provisioning profile di repositori Git Anda. File-file ini adalah rahasia, bukan konfigurasi. Jika mereka berakhir di repositori publik, siapa pun dapat menandatangani aplikasi dengan menyamar sebagai Anda. Jika mereka berakhir di repositori privat, Anda masih memiliki masalah: setiap pengembang dengan akses repositori sekarang memegang kunci penandatanganan produksi Anda. Itu adalah risiko keamanan dan audit.

Sebagai gantinya, gunakan penyimpanan rahasia yang disediakan oleh platform CI/CD Anda. GitHub Actions, GitLab CI, Jenkins, dan sebagian besar platform lainnya memiliki variabel rahasia bawaan. Anda dapat mengunggah keystore atau sertifikat Anda sebagai string berenkode base64, menyimpannya sebagai variabel rahasia, dan mendekodenya kembali menjadi file selama proses pipeline. Rahasia tidak pernah ditulis ke disk pada mesin build hingga runtime, dan tidak pernah muncul di log.

Berikut contoh konkret untuk Android dengan GitHub Actions:

- name: Decode keystore
  run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > app/release.keystore

Untuk iOS dengan Fastlane dan GitLab CI:

- name: Decode certificate
  run: echo $MATCH_PASSWORD | fastlane match import --git_url $MATCH_REPO

Jika tim Anda membutuhkan kontrol lebih, pertimbangkan untuk menggunakan manajer rahasia khusus seperti AWS Secrets Manager, Azure Key Vault, atau HashiCorp Vault. Pipeline Anda mengambil kredensial saat runtime dari layanan-layanan ini. Pendekatan ini memberi Anda log audit, kontrol akses, dan rotasi terpusat. Kredensial tidak pernah berada di dalam konfigurasi pipeline itu sendiri.

Berikut adalah skrip bash lengkap yang mengambil keystore dari AWS Secrets Manager, menandatangani APK dengan jarsigner, dan memverifikasi tanda tangan:

#!/bin/bash
set -euo pipefail

# Ambil keystore dari AWS Secrets Manager
KEYSTORE_SECRET=$(aws secretsmanager get-secret-value \
  --secret-id "mobile-app/keystore" \
  --query SecretString --output text)

echo "$KEYSTORE_SECRET" | base64 --decode > /tmp/release.keystore

# Tandatangani APK
jarsigner -verbose -sigalg SHA256withRSA \
  -digestalg SHA-256 \
  -keystore /tmp/release.keystore \
  -storepass "$STORE_PASSWORD" \
  app-release-unsigned.apk \
  mykeyalias

# Verifikasi tanda tangan
jarsigner -verify -verbose -certs app-release-unsigned.apk

# Bersihkan
rm -f /tmp/release.keystore

Skrip ini memastikan keystore tidak pernah disimpan di repositori, diambil dengan aman saat runtime, dan langsung dibersihkan setelah penandatanganan.

Kedaluwarsa Sertifikat: Pembunuh Pipeline Senyap

Berikut adalah skenario yang lebih sering terjadi dari yang seharusnya. Pipeline Anda berjalan lancar selama berbulan-bulan. Kemudian suatu hari, build rilis gagal. Anda menggali log dan menemukan bahwa sertifikat penandatanganan telah kedaluwarsa. Aplikasi yang sudah ada di toko masih berfungsi dengan baik di perangkat pengguna. Tapi Anda tidak dapat mengunggah versi baru. Toko menolaknya karena tanda tangan pada biner baru tidak valid.

Keystore Android dan sertifikat iOS memiliki tanggal kedaluwarsa. Mereka tidak memperbarui diri secara otomatis. Pipeline Anda harus mendeteksi kedaluwarsa yang akan datang dan memberi tahu tim sebelum kredensial menjadi tidak dapat digunakan. Skrip sederhana yang memeriksa tanggal validitas keystore atau sertifikat dan mengirim notifikasi ke saluran obrolan tim Anda dapat menyelamatkan Anda dari rilis yang terhambat.

Untuk Android, Anda dapat memeriksa kedaluwarsa keystore dengan:

keytool -list -v -keystore release.keystore -storepass $STORE_PASSWORD | grep "Valid until"

Untuk iOS, alat match milik Fastlane menyertakan mode --readonly yang menunjukkan kedaluwarsa sertifikat. Anda juga dapat menggunakan perintah security di macOS:

security find-identity -v -p codesigning | grep "iPhone Distribution"

Daftar Periksa Praktis untuk Penandatanganan di Pipeline Anda

Jika Anda menyiapkan penandatanganan untuk pertama kalinya atau meninjau pengaturan Anda saat ini, jalankan daftar periksa ini:

  • Apakah keystore, sertifikat, dan provisioning profile disimpan di luar Git?
  • Apakah kredensial penandatanganan disimpan di penyimpanan rahasia platform CI/CD atau manajer rahasia eksternal?
  • Apakah keystore atau sertifikat berenkode base64 disimpan sebagai variabel rahasia, bukan di file konfigurasi?
  • Apakah pipeline mendekode rahasia hanya saat runtime, di direktori sementara?
  • Apakah file penandatanganan sementara dibersihkan setelah build selesai?
  • Apakah pipeline memeriksa kedaluwarsa sertifikat dan memberi tahu tim sebelum kredensial kedaluwarsa?
  • Apakah ada proses terdokumentasi untuk merotasi atau memperbarui kredensial penandatanganan?
  • Apakah kredensial penandatanganan produksi dibatasi hanya untuk sekelompok kecil anggota tim tepercaya?

Penandatanganan Bukanlah Akhir

Setelah aplikasi Anda ditandatangani, artefak siap untuk diuji. Tapi biner yang ditandatangani yang duduk di mesin build tidak sama dengan rilis yang diuji. Aplikasi mobile tidak dapat diverifikasi sepenuhnya hanya dengan membaca kode atau menjalankan pengujian unit. Anda perlu menjalankan aplikasi yang ditandatangani di emulator, simulator, atau perangkat nyata untuk menangkap masalah yang hanya muncul saat runtime.

Langkah penandatanganan adalah sebuah gerbang. Ini memastikan bahwa apa yang akan Anda uji dan kirim benar-benar milik Anda. Perlakukan dengan hati-hati seperti yang Anda lakukan pada kredensial database produksi Anda. Karena dalam banyak hal, ini lebih berharga: kehilangan kata sandi database berarti memulihkan dari cadangan. Kehilangan keystore Anda berarti kehilangan kemampuan untuk memperbarui aplikasi Anda sama sekali.