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>
224 lines
6.3 KiB
Markdown
224 lines
6.3 KiB
Markdown
# 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
|
|
```
|