Episode ini membahas privacy dan data handling di ChromaDB: risiko embedding inversion yang bisa merekonstruksi dokumen dari vektor, enkripsi data at rest, penanganan PII, retention policy, dan audit log akses data untuk kepatuhan regulasi.

Keamanan teknis sudah kuat di episode 14 dan 15. Tapi ada dimensi yang sering terlupakan: privacy dan data handling. Server yang aman dari peretas belum tentu aman dari masalah hukum. Dokumen yang kalian simpan di ChromaDB — termasuk yang berisi data pribadi — tetap harus diperlakukan sesuai regulasi.
Episode 16 membahas empat hal: risiko embedding inversion, enkripsi data at rest, penanganan PII (personally identifiable information), dan retention policy beserta audit log. Ini materi yang menentukan apakah aplikasi kalian bisa lulus audit.
Kebanyakan orang menganggap embedding sebagai "teks yang sudah diubah total". Fakta yang kurang dikenal: embedding bisa dibalik secara parsial. Riset di bidang embedding inversion menunjukkan bahwa dari vektor embedding, dokumen asli bisa direkonstruksi — kadang cukup akurat untuk membocorkan isi sensitif.
Ini bukan teori murni: penyerang dengan akses ke collection (atau backup yang bocor) bisa mencoba merekonstruksi dokumen dari embeddings yang tersimpan. Implikasi penting: embedding bukan pengganti enkripsi. Jika data aslinya sensitif, anggap embedding-nya juga sensitif.
data = collection.get(include=["documents", "embeddings"])
print("jumlah item:", len(data["ids"]))
print("dimensi embedding:", len(data["embeddings"][0]))collection.get(include=["documents", "embeddings"]) menampilkan bahwa dokumen asli dan embedding sama-sama tersimpan. Menghapus dokumen asli pun masih menyisakan embedding yang berpotensi dibalik.
Danger
Jangan menyimpan embedding data pribadi di tempat yang tidak terenkripsi. Embedding inversion memungkinkan rekonstruksi parsial dokumen — anggap embedding sama sensitifnya dengan teks asli.
Beberapa strategi mengurangi paparan:
Lapisan pertama: enkripsi disk tempat data ChromaDB disimpan. Ini menangani skenario paling umum — media fisik atau volume cloud yang dicuri:
cloud: aktifkan volume encryption (EBS/PD/PV terenkripsi)
lokal: gunakan LUKS atau native disk encryption
backup: enkripsi snapshot di episode 11Di cloud, aktifkan enkripsi volume bawaan penyedia. Di Kubernetes, pastikan StorageClass memakai encrypted: true. Backup yang dipindahkan antar environment juga harus dienkripsi — snapshot plaintext adalah titik bocor yang sering dilupakan.
Untuk kontrol lebih ketat, enkripsi dokumen sensitif sebelum masuk ChromaDB:
from cryptography.fernet import Fernet
kunci = Fernet.generate_key()
fernet = Fernet(kunci)
dokumen_terenkripsi = fernet.encrypt(b"isi rahasia").decode()
collection.add(ids=["doc-1"], documents=[dokumen_terenkripsi])fernet.encrypt(b"isi rahasia") menyimpan dokumen dalam bentuk terenkripsi — hanya bisa dibaca oleh pemegang kunci. Trade-off-nya: full-text search dan where_document dari episode 7 tidak lagi bekerja pada data terenkripsi. Untuk kasus PII, ini trade-off yang wajar.
Aturan pertama penanganan PII: jangan menyimpan yang tidak perlu. Sebelum meng-embed dokumen, bersihkan data pribadi:
import re
def redaksi(teks):
teks = re.sub(r"\b\d{16}\b", "[KARTU]", teks)
teks = re.sub(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", "[EMAIL]", teks)
return teks
dokumen_aman = redaksi(dokumen_asli)redaksi(teks) mengganti nomor kartu 16 digit dan email dengan placeholder sebelum dokumen masuk ChromaDB. Kebiasaan ini jauh lebih murah daripada harus membersihkan data setelah terjadi kebocoran.
Jika aplikasi kalian memproses data pribadi, siapkan dokumentasi minimal: apa yang disimpan, untuk apa, berapa lama, dan siapa yang bisa mengakses. Dokumen ini bukan sekadar formalitas — ia menjadi dasar menjawab pertanyaan regulasi dan audit.
Retention policy menentukan berapa lama data disimpan sebelum dihapus. Pola yang bisa diterapkan langsung:
import datetime
batas = (datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=90)).isoformat()
collection.delete(where={"timestamp": {"$lt": batas}})collection.delete(where={"timestamp": {"$lt": batas}}) menghapus semua dokumen dengan timestamp lebih lama dari 90 hari. Retention policy — yang memakai filter $lt dari episode 7 — dijalankan terjadwal, misalnya setiap malam lewat cron atau job Kubernetes.
Untuk kepatuhan, catat siapa mengakses apa dan kapan. Di level aplikasi, bungkus operasi query dengan logging:
import logging
log = logging.getLogger("chroma-audit")
def query_dengan_audit(client, collection_name, query):
log.info("QUERY collection=%s user=%s", collection_name, get_user())
hasil = client.get_collection(collection_name).query(query_texts=query)
log.info("QUERY_DONE collection=%s n=%s", collection_name, len(hasil["ids"][0]))
return hasilFungsi query_dengan_audit(...) mencatat permintaan dan hasilnya. Pada deployment besar, audit log diarahkan ke agregasi log terpusat (episode 20) agar tidak mudah hilang.
Episode 16 menutup sisi privacy: memahami risiko embedding inversion yang bisa merekonstruksi dokumen, mengenkripsi data at rest di level disk dan aplikasi, membersihkan PII sebelum masuk ChromaDB, menerapkan retention policy terjadwal, serta mencatat audit log akses data untuk kepatuhan.
Inti yang harus dibawa pulang:
where={"timestamp": {"$lt": ...}}.Di episode 17 selanjutnya kita akan membahas scaling dan performance — melayani jutaan vektor dengan server Rust, batch operations, tuning index, optimasi ef search, pra-filter metadata, dan sizing resource CPU serta RAM. Aplikasi kalian tumbuh; saatnya menyiapkan mesinnya.