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 <noreply@anthropic.com>
This commit is contained in:
sas.fajri
2026-05-31 15:24:24 +07:00
parent f667050200
commit f744a25be8

View File

@@ -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=<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)
```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
```