From f744a25be8cc0c6bf8464bc36e403b6fbda85fb8 Mon Sep 17 00:00:00 2001 From: "sas.fajri" Date: Sun, 31 May 2026 15:24:24 +0700 Subject: [PATCH] FHM31052601IBL - tambah runbook implementasi enkripsi PII untuk production Dokumentasi lengkap urutan eksekusi, field yang dienkripsi, format masking, disk space requirement, dan restore procedure. Co-Authored-By: Claude Sonnet 4.6 --- docs/pdp-encryption-runbook.md | 223 +++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 docs/pdp-encryption-runbook.md diff --git a/docs/pdp-encryption-runbook.md b/docs/pdp-encryption-runbook.md new file mode 100644 index 00000000..44cb5737 --- /dev/null +++ b/docs/pdp-encryption-runbook.md @@ -0,0 +1,223 @@ +# 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 + +```bash +# 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 +bash scripts/backup_pdp_tables.sh +# Backup tersimpan di ~/backup_pdp_YYYY_MM_DD_HHMMSS/ +``` + +### 2. Buat file `.env` + +```bash +cat > /path/to/one-api-lab/.env << 'EOF' +IBL_ENCRYPT_KEY= +IBL_ENCRYPT_SEARCH_KEY= +EOF +chmod 600 .env +``` + +> ⚠️ **WAJIB** simpan passphrase di password manager sebelum lanjut. +> Key hilang = data tidak bisa didekripsi. + +### 3. Jalankan SQL Migration (tambah kolom) + +```bash +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 + +```bash +# 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 + +```bash +# Populate search index untuk NIK (dari _enc yang sudah ada) +php scripts/migrate_nik_bidx.php +``` + +### 6. Migration Data — Address Enc + +```bash +# Enkripsi alamat (tanpa bidx — hemat disk) +php scripts/migrate_address_enc.php +``` + +### 7. Migration Data — Hasil Lab & Log + +```bash +# 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 + +```bash +# 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 + +```bash +# 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 `_enc` tidak bisa didekripsi + +### Disk Space +- Tambahkan minimal **8GB free** sebelum mulai di production +- Kolom `_bidx` untuk nama/HP/DOB/NIK menambah ~500MB-1GB +- Kolom `_enc` untuk semua field menambah ~200-300MB +- `m_patientaddress` tidak punya `_bidx` (dihapus — hemat disk) + +### Jika Disk Penuh +```bash +# 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_OrderDetailNote` +- `t_orderheader`: `T_OrderHeaderDiagnose` +- `t_orderdelivery`: `T_OrderDeliveryDestination` +- `so_resultentrydetail`, `so_resultentry_fisik_umum`, dll +- `mcu_resume_results`: `Mcu_ResumeResultsJSON` + +#### Log +- `one_lab_log.log_patient`: `Log_PatientJsonBefore/After` +- `one_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` | +| Email | `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 registration +- `mockup/fo/ibl_registration/Order.php` — Order management +- `mockup/fo/ibl_registration/Payment.php` +- `mockup/fo/ibl_registration/History.php` +- `mockup/fo/ibl_registration/Delivery.php` +- `mockup/fo/ibl_registration/Order copy.php` +- `mockup/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 +```bash +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 +```