Secret adalah objek Kubernetes untuk menyimpan data sensitif seperti token, kata sandi, dan kunci privat, dengan pola konsumsi yang sama seperti ConfigMap. Topik ini membahas bentuk penyimpanan nilainya, perbedaan antara encoding dan enkripsi yang sering tertukar, tipe Secret yang umum, mounting ke dalam Pod, serta keterbatasan keamanan yang perlu diakui. Semua nilai pada contoh adalah nilai latihan yang jelas bukan kredensial nyata.
Secret sebagai objek data sensitif#
Struktur Secret menyerupai ConfigMap, yaitu pasangan kunci dan nilai pada bidang data, tetapi tujuannya berbeda. Kubernetes memberikan Secret perlakuan khusus pada beberapa titik, misalnya distribusi ke Node secara terbatas hanya pada Pod yang menggunakannya dan opsi enkripsi pada penyimpanannya. Berikut manifest Secret untuk aplikasi jadwal piket dengan nilai latihan:
apiVersion: v1
kind: Secret
metadata:
name: piket-token
type: Opaque
data:
username: cGlrZXQ=
token: bmlsYWktbGF0aWhhbg==Nilai pada data wajib berupa teks dengan encoding base64, dan penulisannya dilakukan sendiri oleh pembuat manifest. Bidang stringData menyediakan kemudahan sebaliknya, yaitu nilai ditulis apa adanya dan API server menyandikannya saat objek diterima, sehingga tidak tersimpan dalam bentuk aslinya pada API server. Namun, keduanya bermuara pada nilai yang sama di API server, dan manifest yang sudah berisi data umumnya lebih disukai dalam repositori konfigurasi. Batas ukuran total Secret juga sama dengan ConfigMap, yaitu sekitar 1 MiB, sehingga kredensial besar perlu dipisahkan ke beberapa objek.
Base64 adalah encoding, bukan enkripsi#
Penyandian base64 hanyalah cara mewakili data biner sebagai teks yang aman untuk dikirim, dan hasilnya dapat dibalik oleh siapa pun tanpa kunci. Tujuannya menjadikan data biner dapat ditulis pada manifest YAML yang hanya menampung teks, bukan menyembunyikan isinya. Perintah berikut menyandikan nilai latihan lalu memulihkannya:
# menyandikan nilai latihan menjadi base64
printf 'nilai-latihan' | base64
# memulihkan teks asli dari hasil encoding
printf 'bmlsYWktbGF0aWhhbg==' | base64 -dbmlsYWktbGF0aWhhbg==
nilai-latihanSkrip berikut membaca secret.yaml dari bundle, mendekode setiap nilai pada data, dan menampilkan hubungan kunci ke nilainya. Decode berhasil tanpa kunci apa pun, karena memang tidak ada kunci yang terlibat dalam proses ini:
import base64
import yaml
# baca manifest Secret dari bundle topik
with open("secret.yaml") as f:
secret = yaml.safe_load(f)
print(f"Secret {secret['metadata']['name']} bertipe {secret['type']}")
for kunci, sandi in secret["data"].items():
teks = base64.b64decode(sandi).decode()
print(f" {kunci} -> {teks}")Secret piket-token bertipe Opaque
username -> piket
token -> nilai-latihanNilai yang tertulis pada keluaran kubectl get secret juga masih berbentuk base64, sehingga pemula yang baru pertama kali melihatnya sering mengira isinya sudah terlindungi. Nilai asli hanya muncul setelah hasil itu didekode, dan decode dilakukan satu baris perintah saja. Perbedaan ini memperjelas bahwa Secret menyimpan bentuk teks yang dapat dibalik dan bukan bentuk terenkripsi.
Tipe Secret yang umum#
Bidang type menandai peruntukan sebuah Secret, dan beberapa tipe menuntut kunci tertentu yang divalidasi API server saat objek dibuat. Tipe yang paling sering ditemui dirangkum pada tabel berikut:
| Tipe | Kunci yang dituntut | Peruntukan |
|---|---|---|
Opaque | tidak ada | data sensitif umum, ditentukan sendiri |
kubernetes.io/tls | tls.crt dan tls.key | pasangan sertifikat dan kunci privat TLS |
kubernetes.io/dockerconfigjson | .dockerconfigjson | kredensial registry image |
kubernetes.io/basic-auth | username dan password | autentikasi dasar |
Tipe Opaque adalah default dan menerima kunci bebas, sehingga contoh sebelumnya menggunakannya. Tipe kubernetes.io/tls menolak objek apabila salah satu kunci wajibnya tidak ada, sehingga kesalahan terdeteksi lebih cepat. Validasi kunci wajib terjadi pada saat pembuatan objek, sehingga pemilihan tipe yang tepat memindahkan deteksi kesalahan lebih awal daripada menunggu Pod gagal membaca nilainya. Tipe lainnya, misalnya kubernetes.io/service-account-token, digunakan secara internal oleh kluster dan jarang dibuat manual.
Menggunakan Secret dari Pod#
Pod mengonsumsi Secret melalui dua pintu yang sama dengan ConfigMap, yaitu variabel lingkungan dan volume. Manifest berikut menyuntikkan kunci token sebagai variabel lingkungan dan sekaligus me-mount seluruh Secret sebagai berkas:
apiVersion: v1
kind: Pod
metadata:
name: piket
spec:
containers:
- name: piket
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
env:
- name: TOKEN
valueFrom:
secretKeyRef:
name: piket-token
key: token
volumeMounts:
- name: kredensial
mountPath: /var/run/secrets/piket
readOnly: true
volumes:
- name: kredensial
secret:
secretName: piket-tokenContainer di atas membaca variabel TOKEN serta berkas /var/run/secrets/piket/username dan /var/run/secrets/piket/token, dengan setiap kunci menjadi satu berkas. Bidang items dapat membatasi kunci yang muncul dan mengganti nama berkasnya:
secret:
secretName: piket-token
items:
- key: token
path: token
mode: 0400Bidang mode pada setiap entri mengatur izin berkasnya, dan kubelet menggunakan izin 0644 apabila bidang itu tidak diisi. Nilai seperti 0400 ditafsirkan sebagai bilangan oktal pada YAML, sehingga berkasnya hanya dapat dibaca dan tidak dapat ditulis.
Sifat pembaruannya juga sama, yaitu variabel lingkungan dibaca sekali saat container dimulai, sedangkan berkas yang di-mount diperbarui kubelet secara berkala. Volume Secret di belakang layar ditempatkan pada tmpfs, yaitu filesystem berbasis memori pada Node, sehingga isinya tidak menempel pada disk Node.
Keterbatasan yang perlu diakui#
Secret memberikan perlindungan hanya sejauh lapisan di sekitarnya aktif. Data pada etcd, penyimpanan di belakang API server, secara default tidak dienkripsi saat tersimpan di disk, sehingga akses baca ke etcd berarti akses ke seluruh Secret. Enkripsi saat tersimpan (encryption at rest) hanya aktif apabila kluster menetapkan konfigurasi EncryptionConfiguration secara eksplisit.
Lapisan perlindungan yang lazim disusun bertingkat, dimulai dari RBAC yang membatasi siapa yang boleh membaca Secret, dilanjutkan dengan enkripsi saat tersimpan pada etcd, dan pilihan mounting berkas daripada variabel lingkungan karena nilai di lingkungan ikut terekspos pada inspeksi proses. Sistem pengelolaan rahasia eksternal dapat mengambil peran tersendiri apabila kebutuhannya melebihi kemampuan Secret. Perintah berikut memperlihatkan cara membuat Secret tanpa menyandikan nilai secara manual:
# tidak-dijalankan
# buat Secret dari nilai literal, encoding dilakukan kubectl
kubectl create secret generic piket-token --from-literal=token=nilai-latihan
# ringkas keadaan Secret yang sudah dibuat
kubectl get secret piket-tokensecret/piket-token created
NAME TYPE DATA AGE
piket-token Opaque 1 9sKesalahan umum#
- Menulis nilai mentah langsung pada bidang
data. API server menolak objeknya dengan error decoding base64, karena nilai tersebut tidak sah sebagai base64. Perbaikannya adalah menyandikan nilai lebih dahulu atau memindahkan penulisannya ke bidangstringData. - Mengisi Secret bertipe
kubernetes.io/tlstanpa kuncitls.key. API server menolak pembuatannya karena tipe tersebut menuntut pasangan kunci yang lengkap. Perbaikannya adalah melengkapitls.crtdantls.keysesuai tuntutan tipenya. - Berbagi satu Secret untuk banyak aplikasi dengan izin baca yang luas. Kebocoran pada satu aplikasi berarti kebocoran nilai yang sama pada seluruh penggunanya. Perbaikannya adalah memecah Secret per aplikasi beserta ServiceAccount-nya, sehingga izin baca hanya diberikan kepada pihak yang membutuhkan.
Ringkasan#
- Secret menyimpan data sensitif sebagai pasangan kunci dan nilai dengan encoding base64 pada bidang
data, danstringDatamenerima nilai mentah yang disandikan API server. - Encoding base64 dapat dibalik oleh siapa pun, sehingga Secret tanpa lapisan lain bukan perlindungan yang memadai.
- Pod mengonsumsi Secret melalui
secretKeyRefuntuk variabel lingkungan dan volume bertipesecretuntuk berkas, dengan pembaruan berkas oleh kubelet secara berkala. - Keamanan Secret bergantung pada RBAC, enkripsi etcd saat tersimpan, dan pengurangan permukaan akses, bukan pada base64-nya.
Referensi#
- Secrets — Kubernetes — Dokumentasi konsep Secret, mencakup tipe, pola konsumsi Pod, dan risiko keamanannya.