Dokumentasi lengkap urutan eksekusi, field yang dienkripsi, format masking, disk space requirement, dan restore procedure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.3 KiB
6.3 KiB
Runbook: Implementasi Enkripsi PII Pasien (UU PDP) — Production
Ringkasan
Enkripsi AES-256-GCM untuk data pribadi pasien dan data medis.
Key disimpan di .env. Data asli di kolom _enc, kolom lama berisi masked value.
Search pasien via trigram blind index (nama, HP, DOB, NIK).
Urutan Eksekusi di Production
0. Pre-flight
# Pastikan disk cukup (minimal 10GB free sebelum mulai)
df -h /
# Pastikan MySQL running
mysql -e "SELECT 1;"
# Catat ukuran tabel sebelum
mysql -e "SELECT table_name, ROUND((data_length+index_length)/1024/1024,1) MB
FROM information_schema.tables WHERE table_schema='one_lab'
ORDER BY (data_length+index_length) DESC LIMIT 15;"
1. Backup Database
bash scripts/backup_pdp_tables.sh
# Backup tersimpan di ~/backup_pdp_YYYY_MM_DD_HHMMSS/
2. Buat file .env
cat > /path/to/one-api-lab/.env << 'EOF'
IBL_ENCRYPT_KEY=<passphrase-enkripsi-kamu>
IBL_ENCRYPT_SEARCH_KEY=<passphrase-search-kamu>
EOF
chmod 600 .env
⚠️ WAJIB simpan passphrase di password manager sebelum lanjut. Key hilang = data tidak bisa didekripsi.
3. Jalankan SQL Migration (tambah kolom)
mysql one_lab < sql/manual_changes/2026-05-31-pdp-encrypt-columns.sql
mysql one_lab < sql/manual_changes/2026-05-31-pdp-update-triggers-enc.sql
# Verifikasi kolom terbentuk
mysql -e "SHOW COLUMNS FROM one_lab.m_patient LIKE '%_enc';"
mysql -e "SHOW COLUMNS FROM one_lab.m_patient LIKE '%_bidx';"
4. Migration Data — Patient PII
# Enkripsi m_patient dan m_patientaddress (178K + 133K rows)
# Estimasi: 30-60 menit tergantung server
php scripts/migrate_encrypt_patient.php
# Verifikasi
mysql -e "SELECT COUNT(*) total, COUNT(M_PatientName_enc) done FROM one_lab.m_patient;"
mysql -e "SELECT COUNT(*) total, COUNT(M_PatientAddressDescription_enc) done FROM one_lab.m_patientaddress;"
5. Migration Data — NIK Bidx
# Populate search index untuk NIK (dari _enc yang sudah ada)
php scripts/migrate_nik_bidx.php
6. Migration Data — Address Enc
# Enkripsi alamat (tanpa bidx — hemat disk)
php scripts/migrate_address_enc.php
7. Migration Data — Hasil Lab & Log
# Enkripsi hasil lab (t_orderdetail, t_orderheader, so_resultentry*, dll)
php scripts/migrate_encrypt_results.php
# Enkripsi t_orderdelivery (email/HP tujuan pengiriman hasil)
php scripts/migrate_encrypt_orderdelivery.php
8. Masking Kolom Plaintext
# Masking kolom lama agar controller lama tidak expose data lengkap
php scripts/mask_patient_plaintext.php
# Re-masking nama dengan format baru (kata pertama penuh + inisial)
php scripts/remask_patient_name.php
9. Verifikasi Akhir
# Cek sample data sudah termasking
mysql -e "SELECT M_PatientID, M_PatientName, M_PatientHP, M_PatientEmail
FROM one_lab.m_patient LIMIT 5;"
# Pastikan decrypt bisa berjalan
php -r "
define('BASEPATH', true);
\$_ENV['IBL_ENCRYPT_KEY'] = trim(explode('=', file('.env')[0])[1]);
\$_ENV['IBL_ENCRYPT_SEARCH_KEY'] = trim(explode('=', file('.env')[1])[1]);
require 'application/libraries/Ibl_encryptor.php';
\$enc = new Ibl_encryptor();
\$row = (new PDO('mysql:host=localhost;dbname=one_lab', 'user', 'pass'))
->query('SELECT M_PatientName_enc FROM m_patient LIMIT 1')->fetch();
echo \$enc->decrypt(\$row['M_PatientName_enc']) . PHP_EOL;
"
# Cek disk usage setelah
df -h /
Catatan Penting
Key Management
- Key disimpan di
.env(JANGAN commit ke git — sudah di.gitignore) - Backup key di: password manager + file enkripsi di lokasi terpisah
- Jika key hilang: data di
_enctidak bisa didekripsi
Disk Space
- Tambahkan minimal 8GB free sebelum mulai di production
- Kolom
_bidxuntuk nama/HP/DOB/NIK menambah ~500MB-1GB - Kolom
_encuntuk semua field menambah ~200-300MB m_patientaddresstidak punya_bidx(dihapus — hemat disk)
Jika Disk Penuh
# Cek pemakai disk terbesar
du -sh /home/* /tmp/* /var/log/* 2>/dev/null | sort -rh | head -20
# Bersihkan journal (butuh sudo)
sudo journalctl --vacuum-size=300M
sudo truncate -s 0 /var/log/btmp
Field yang Dienkripsi
one_lab.m_patient
| Field | _enc |
_bidx |
|---|---|---|
| M_PatientName | ✅ | ✅ (search) |
| M_PatientHP | ✅ | ✅ (search) |
| M_PatientDOB | ✅ | ✅ (search) |
| M_PatientNIK | ✅ | ✅ (search) |
| M_PatientEmail | ✅ | — |
| M_PatientPhone | ✅ | — |
| M_PatientPOB | ✅ | — |
| M_PatientIDNumber | ✅ | — |
| M_PatientNIP | ✅ | — |
one_lab.m_patientaddress
| Field | _enc |
_bidx |
|---|---|---|
| M_PatientAddressDescription | ✅ | — (dihapus, hemat disk) |
| M_PatientAddressEmail | ✅ | — |
| M_PatientAddressPhone | ✅ | — |
Hasil Lab
t_orderdetail:T_OrderDetailResult,T_OrderDetailNotet_orderheader:T_OrderHeaderDiagnoset_orderdelivery:T_OrderDeliveryDestinationso_resultentrydetail,so_resultentry_fisik_umum, dllmcu_resume_results:Mcu_ResumeResultsJSON
Log
one_lab_log.log_patient:Log_PatientJsonBefore/Afterone_lab_log.log_fo:Log_FoJson
Search Pasien
Search parameter via + separator:
?search=NAMA+HP+DOB+NIK
e[0]= nama (trigram bidx, min 3 karakter)e[1]= HP (trigram bidx, min 3 karakter)e[2]= DOB format dd-mm-yyyy (trigram bidx)e[3]= NIK (trigram bidx, min 3 karakter)
Masking Format
| Field | Contoh |
|---|---|
| Nama | FAJRI H******* M**** |
| HP | 0812*****890 |
fa***@gmail.com |
|
| NIK/IDNumber | 3201***01 |
| POB | JA*** |
| Alamat | Jl. S*** |
Controller yang Sudah Diupdate (Read Full Data)
mockup/fo/ibl_registration/Patient.php— FO registrationmockup/fo/ibl_registration/Order.php— Order managementmockup/fo/ibl_registration/Payment.phpmockup/fo/ibl_registration/History.phpmockup/fo/ibl_registration/Delivery.phpmockup/fo/ibl_registration/Order copy.phpmockup/masterdata/Patientv4.php— Masterdata pasien (full data)
Controller yang Belum Diupdate (Tampil Data Masked)
Semua controller lain (~300+ file) otomatis menampilkan data termasking karena kolom plaintext sudah dimasking. Tidak perlu update satu-satu.
Restore jika Ada Masalah
mysql one_lab < ~/backup_pdp_YYYY_MM_DD_HHMMSS/one_lab_tables.sql
mysql one_lab_log < ~/backup_pdp_YYYY_MM_DD_HHMMSS/one_lab_log_tables.sql