Password database, kunci API payment gateway, dan token layanan cloud adalah kunci yang membuka aset berharga — namun kebiasaan pemula justru menuliskannya langsung di dalam kode. Secret yang tertanam di source code tidak pernah benar-benar terhapus: sistem version control seperti Git menyimpan riwayat penuh, dan satu repo yang bocor membocorkan seluruh kuncinya. Chapter ini membahas cara menyimpan dan membaca secrets dengan benar di Python.

Kode Sumber Itu Bocor #

Risikonya nyata: repository di-push ke layanan publik, laptop dicuri, backup tersebar, atau mantan kontraktor menyimpan salinan. Menghapus secret pada commit berikutnya tidak menolong — commit lama tetap menyimpan nilai tersebut, dan siapa pun yang pernah menarik repo ikut menyimpannya.

Environment Variables #

Lokasi penyimpanan paling sederhana adalah environment variable: nilai hidup di proses, bukan di file kode. Module os menyediakan dua cara membacanya, dan cara kita menangani kunci yang hilang menentukan keamanan aplikasi:

python
import os

api_key = os.environ.get("PAYMENT_API_KEY")
if api_key is None:
    print("PAYMENT_API_KEY belum diatur - aplikasi menolak berjalan")

os.environ["PAYMENT_API_KEY"] = "YOUR_API_TOKEN"
api_key = os.environ["PAYMENT_API_KEY"]
tersembunyi = "*" * (len(api_key) - 4) + api_key[-4:]
print("Token terbaca (disamarkan):", tersembunyi)

Output yang Dihasilkan:

text
PAYMENT_API_KEY belum diatur - aplikasi menolak berjalan
Token terbaca (disamarkan): **********OKEN

Mari kita bedah kode di atas:

  1. Baris 3 (os.environ.get("PAYMENT_API_KEY")): method get() mengembalikan None saat kunci tidak ada — tidak ada exception, sehingga kita wajib memeriksanya sendiri.
  2. Baris 4-5 (if api_key is None:): prinsip fail securely diterapkan — secret yang hilang menghentikan aplikasi, bukan membuatnya berjalan tanpa autentikasi.
  3. Baris 9-10 (penyamaran): log tidak pernah mencetak token utuh; hanya empat karakter terakhir yang tampil agar operasional tetap bisa memverifikasi kunci mana yang aktif.

Perbedaan os.environ["KEY"] dan os.environ.get("KEY") penting: indeks langsung memunculkan KeyError saat kunci hilang, sedangkan get() membiarkan kita memilih kebijakan penanganan sendiri.

File .env dengan python-dotenv #

Mengetik puluhan environment variable di setiap sesi terminal melelahkan, sehingga timbiasa memakai package python-dotenv. File .env menyimpan pasangan kunci-nilai untuk mesin pengembang, lalu diubah menjadi environment variable saat program dijalankan:

text
DATABASE_URL=postgresql://budi:YOUR_DATABASE_PASSWORD@localhost/toko
PAYMENT_API_KEY=YOUR_API_TOKEN

File tersebut dibaca oleh fungsi load_dotenv():

python
import os

from dotenv import load_dotenv

with open(".env", "w") as f:  # simulasi file .env milik Anda
    f.write(
        "DATABASE_URL=postgresql://budi:YOUR_DATABASE_PASSWORD@localhost/toko\n"
        "PAYMENT_API_KEY=YOUR_API_TOKEN\n"
    )

os.environ.pop("DATABASE_URL", None)
load_dotenv()

print("DATABASE_URL   :", os.environ.get("DATABASE_URL"))
print("PAYMENT_API_KEY:", os.environ.get("PAYMENT_API_KEY"))
os.remove(".env")

Output yang Dihasilkan:

text
DATABASE_URL   : postgresql://budi:YOUR_DATABASE_PASSWORD@localhost/toko
PAYMENT_API_KEY: YOUR_API_TOKEN

Fungsi load_dotenv() membaca file .env lalu mengisi os.environ, sehingga kode aplikasi tetap membaca dari environment — tidak ada perubahan cara akses. File .env sendiri wajib masuk daftar .gitignore:

text
# .gitignore
.env
.env.*

Dengan begitu Git tidak pernah menyimpan file tersebut. Konvensi yang lazim: komit satu file .env.example berisi nama kunci tanpa nilai, sebagai dokumentasi bagi anggota tim baru.

Token di URL Itu Bocor #

Cara pengiriman secret menentukan nasibnya juga. Token yang ditempatkan di query string ikut tercatat di access log web server, log proxy, dan riwayat browser:

python
def catat_akses(method, path):
    # simulasi satu baris access log milik web server
    print(f'192.0.2.10 - - [15/Jun/2025:10:30:00 +0700] "{method} {path}" 200')


# Token di query string ikut terekam di log server dan proxy
catat_akses("GET", "/api/orders?token=YOUR_API_TOKEN")

# Header Authorization TIDAK tercatat di access log standar
catat_akses("GET", "/api/orders  (token dikirim lewat header Authorization)")

Output yang Dihasilkan:

text
192.0.2.10 - - [15/Jun/2025:10:30:00 +0700] "GET /api/orders?token=YOUR_API_TOKEN" 200
192.0.2.10 - - [15/Jun/2025:10:30:00 +0700] "GET /api/orders  (token dikirim lewat header Authorization)" 200

Baris log pertama menyimpan token apa adanya; siapa pun yang bisa membaca log — operator, tool analitik, penyimpanan log pihak ketiga — ikut memegang kuncinya. Kirim kredensial lewat header Authorization, bukan query string.

Secret Manager dan Rotasi #

Untuk server produksi, environment variable punya kelemahan: nilainya terlihat oleh siapa pun yang bisa membaca proses, dan menggantinya berarti memulai ulang aplikasi. Secret manager mengatasi keduanya:

LayananBentukKelebihan
HashiCorp VaultServer sendiri atau SaaSAudit trail dan dynamic secrets per aplikasi
AWS Systems Manager Parameter StoreLayanan AWSIntegrasi IAM dan enkripsi bawaan
Google Cloud Secret ManagerLayanan GCPVersioning secret bawaan
Azure Key VaultLayanan AzureKebijakan akses terpadu dengan Active Directory

Dua kebiasaan menutup chapter ini. Pertama, rotasi: ganti secret secara berkala, karena umur kunci yang panjang memperpanjang masa berlaku kebocoran yang tidak kita sadari. Kedua, satu secret per kegunaan — token untuk layanan pengiriman email dan token untuk database harus berbeda, agar pencabutan satu tidak melumpuhkan yang lain. Selanjutnya kita bahas rahasia milik pengguna: password, dan mengapa menyimpannya butuh perlakuan khusus.