ITSkillsCenter
الأمن السيبراني

Audit trail وامتثال للبيانات الصحية: درس 2026

4 min de lecture

📍 المقالة الرئيسية للمجموعة: الصحة الرقمية CEDEAO 2026.

القانون الصحي يفرض تتبعاً شاملاً للوصول إلى ملفات المرضى. ARTCI الإيفواري، CDP السنغالي، CDP المغربي قانون 09-08، NESA الإماراتي يطلبون: من اطلع، متى، ماذا، من أين. التخزين 5-10 سنوات حسب البلد. هذا الدرس يفصل تكوين audit trail شامل لـ OpenMRS مع Loki + Grafana للتصور، وتقارير تلقائية للمدققين.

المتطلبات

OpenMRS في الإنتاج. VPS Hetzner CCX13 minimum. Docker + Loki + Grafana. المستوى المتوقع: متقدم. الوقت المقدر: 3-4 ساعات للتكوين الكامل.

الخطوة 1 — تفعيل OpenMRS Audit Module

OpenMRS لديه Audit module مدمج. تفعيله إجباري للإنتاج الصحي:

Admin → Manage Modules → ابحث «auditlog»
# تثبيت إذا غير مثبت
# Status: Started

# تكوين كائنات للتتبع
Admin → Audit Log → Configuration
# تفعيل: Patient, Encounter, Observation, MedicationRequest, User
# Action types: ALL (CREATED, UPDATED, DELETED, VIEWED)

الخطوة 2 — تثبيت Loki

Loki يجمع ويحفظ السجلات. أخف من Elasticsearch، مثالي لـ audit logs. تثبيت عبر Docker:

docker run -d --name loki \
  -p 3100:3100 \
  -v /var/lib/loki:/loki \
  grafana/loki:latest \
  -config.file=/etc/loki/local-config.yaml

تكوين retention 1 سنة hot، 5 سنوات cold storage على Backblaze B2:

# /etc/loki/local-config.yaml
limits_config:
  retention_period: 8760h  # 1 سنة hot
chunk_store_config:
  max_look_back_period: 8760h
table_manager:
  retention_deletes_enabled: true
  retention_period: 43800h  # 5 سنوات

storage_config:
  aws:
    s3: s3://eu-central-003.backblazeb2.com/audit-cold-storage
    bucketnames: audit-cold-storage

الخطوة 3 — تثبيت Promtail (collecteur)

Promtail يقرأ سجلات OpenMRS Audit ويرسلها إلى Loki:

# /etc/promtail/config.yml
server:
  http_listen_port: 9080

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: openmrs-audit
    static_configs:
      - targets: [localhost]
        labels:
          job: openmrs-audit
          __path__: /var/log/openmrs/audit.log
    pipeline_stages:
      - json:
          expressions:
            user: user
            patient: patient
            action: action
            timestamp: timestamp

الخطوة 4 — تثبيت Grafana للتصور

docker run -d --name grafana \
  -p 3000:3000 \
  -v grafana-data:/var/lib/grafana \
  grafana/grafana:latest

تكوين datasource Loki: Settings → Data Sources → Add → Loki → URL http://loki:3100.

الخطوة 5 — لوحات Grafana للـ Audit

إنشاء dashboards مفيدة للـ DPO (Data Protection Officer):

  1. Dashboard «Patient Access»: من فتح ملف المريض X في 30 يوماً.
  2. Dashboard «After Hours Access»: الوصول خارج ساعات العمل (موقع شك).
  3. Dashboard «Failed Logins»: محاولات اقتحام.
  4. Dashboard «Bulk Exports»: تصدير > 100 ملف (تسرب محتمل).
  5. Dashboard «Modifications par utilisateur»: الأطباء النشطون.

كل لوحة بـ LogQL queries:

# مثال: الوصول إلى ملف مريض محدد
{job="openmrs-audit"} | json | patient="UUID-DIALLO"

# الوصول خارج ساعات العمل (22h-6h)
{job="openmrs-audit"} | json | __error__="" | hour(timestamp) >= 22 or hour(timestamp) <= 6

# تصديرات ضخمة
{job="openmrs-audit"} | json | action="EXPORT" | count > 100

الخطوة 6 — تنبيهات في الوقت الفعلي

Grafana Alerting يولد تنبيهات على أحداث حساسة. webhook إلى Mattermost قناة #security:

# Alert rule: Bulk export
expr: count_over_time({job="openmrs-audit"} | json | action="EXPORT" [5m]) > 50
for: 1m
labels:
  severity: critical
annotations:
  summary: "Suspicious bulk export by {{ $labels.user }}"
  
# Webhook إلى Mattermost
url: https://chat.votre-hopital.com/hooks/abc123
body: |
  {
    "text": "🚨 ALERT: {{ .Annotations.summary }}",
    "channel": "security"
  }

الخطوة 7 — تقرير سنوي للمدقق

سكربت Python يولد تقرير PDF للتدقيق السنوي ARTCI/CDP:

import requests
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas

def generate_audit_report(year):
    # استفسار Loki للسنة
    queries = {
        'total_accesses': f'count_over_time({{job="openmrs-audit"}}[1y])',
        'unique_users': f'count(count by (user) ({{job="openmrs-audit"}}))',
        'bulk_exports': f'count_over_time({{job="openmrs-audit"}} | json | action="EXPORT"[1y])',
        'after_hours': f'count_over_time({{job="openmrs-audit"}} | json | hour > 22 or hour < 6 [1y])',
    }
    
    results = {}
    for key, query in queries.items():
        r = requests.get('http://loki:3100/loki/api/v1/query', 
                         params={'query': query, 'time': f'{year}-12-31T23:59:59Z'})
        results[key] = r.json()['data']['result'][0]['value'][1]
    
    # توليد PDF
    pdf = canvas.Canvas(f"audit-report-{year}.pdf", pagesize=A4)
    pdf.drawString(100, 800, f"تقرير التدقيق السنوي {year}")
    pdf.drawString(100, 750, f"إجمالي الوصول: {results['total_accesses']}")
    pdf.drawString(100, 700, f"المستخدمون الفريدون: {results['unique_users']}")
    pdf.drawString(100, 650, f"تصديرات ضخمة: {results['bulk_exports']}")
    pdf.save()

الخطوة 8 — حماية ضد التلاعب

Audit logs يجب ألا تكون قابلة للتعديل (write-once). استراتيجيات:

  • Object Lock على Backblaze B2: ملفات غير قابلة للحذف لـ 5 سنوات.
  • HMAC-SHA256 signature على كل log entry.
  • Replication إلى MinIO ثانوي offsite.
# Backblaze B2 Object Lock
b2 update-bucket --fileLockEnabled audit-cold-storage allPrivate
b2 update-bucket --defaultRetention compliance --period "5 years" audit-cold-storage

الخطوة 9 — Anonymization للأبحاث

للدراسات الإحصائية، تصدير anonymized يحترم RGPD/CEDEAO:

def anonymize_patient(patient):
    # احذف معرفات مباشرة
    del patient['name'], patient['phone'], patient['email']
    # هاش NIN
    patient['nin_hash'] = hashlib.sha256(patient['nin'].encode()).hexdigest()
    del patient['nin']
    # تعميم تاريخ الميلاد إلى عام
    patient['birth_year'] = patient['birth_date'][:4]
    del patient['birth_date']
    return patient

الخطوة 10 — DPO Dashboard

Dashboard موحد للـ DPO يعرض:

  • نظرة عامة 30 يوم: عدد الوصول، المستخدمون النشطون، الإيقافات.
  • تنبيهات حالية (الأحداث المشبوهة).
  • تقرير شهري قابل للتصدير.
  • إجراء «حذف بيانات مريض» (Right to Erasure GDPR/CDP).
  • إجراء «تصدير بيانات مريض» (Data Portability).

الأخطاء الشائعة

الخطأ السبب الحل
Loki disk full retention مفقود config retention_period
Promtail لا يقرأ logs permissions chmod 644 audit.log + adduser promtail adm
Audit logs مفقودة module غير مفعَّل Admin Modules → Start auditlog
تنبيهات مغرقة thresholds منخفضة tuner alert rules
تقرير PDF فارغ queries خاطئة اختبر LogQL في Grafana Explore
Cold storage بطيء B2 Eu-Central-003 موصى به اختر datacenter قريب

التكيف مع السياق

أربع توضيحات. القوانين المحلية. ARTCI كوت ديفوار (قانون 2013-450)، CDP السنغال (قانون 2008-12)، CDP المغرب (09-08)، NESA الإمارات. كلها تطلب audit trail لكن متطلبات الاحتفاظ تختلف (5-10 سنوات). التدقيقات السنوية. ARTCI تطلب تقريراً سنوياً في الـ DPA report. صدِّر مباشرة من Grafana. Right to Erasure. GDPR/CDP يفرضون حذف البيانات عند الطلب. لكن للبيانات الصحية، استثناءات قانونية (الأرشفة الطبية الإلزامية 20 سنة في فرنسا/المغرب). DPO يقرر. Cross-border data flow. CEDEAO Cross Border Act 2025 يتطلب موافقة قبل نقل البيانات خارج CEDEAO. Hetzner ألمانيا = adequacy decision EU، مقبول لكن وثِّق.

دروس الإخوة

الأسئلة المتكررة

كم تكلفة Loki + Grafana؟ Hetzner CX22 (4.51 يورو/شهر) يستضيف الاثنان لـ < 50 GB logs/شهر.

retention 5 سنوات تكلفة؟ 5 GB/سنة × 5 سنوات × 6 USD/TB Backblaze = 0.15 USD/سنة. ضئيل.

HIPAA-compliant؟ AWS لديه «HIPAA-compliant» eligible services. Hetzner ألمانيا يخضع لـ GDPR، يكفي للقواعد الإفريقية.

التدقيقات في الوقت الفعلي؟ Grafana Alerting + webhook Mattermost = response في 30 ثانية على event مشبوه.

للاستزادة

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité