下拉重新整理

在 Keycloak 和 HAPI FHIR 中間放一層 Rails(五):Keycloak 發證、OPA 判斷、Rails 執行、Kafka 傳事件

659 字 2 分鐘閱讀 12 次閱讀

系列最後一篇。把前面拆開講的 constraint、CQL、function tooling 收起來,補上 OPA 跟 Kafka,看整張圖怎麼合。

最重要的原則:Rails 不能是唯一防線

先講結論裡最要緊的一條。這層 Rails 再厲害,我都不讓它變成唯一的安全防線。我採雙層防護:

Rails Gateway
  第一層:業務政策、動態 constraint、CQL、tool control
                 ↓
HAPI FHIR
  第二層:禁止未授權 Patient、Resource、operation

就算有人繞過 Rails 直連 HAPI,HAPI 的 AuthorizationInterceptor 也不能讓他任意取資料。所以網路上 HAPI 不對外,放在 private network,只接受 Rails 服務帳號、mTLS、固定 audience 的 service token。

別做完全透明的 proxy

我也不建議做 /fhir/* → Rails → HAPI /fhir/* 這種完全透明代理。相容性是高,但很容易漏掉冷門功能:_history_include_revinclude_has、chained search、conditional update、$export$everything$graphql、transaction Bundle、PATCH、bulk data。漏一個就是一個洞。

我改成兩條通道。標準 SMART FHIR 通道只放明確白名單的操作:

/api/fhir/Patient
/api/fhir/Observation
/api/fhir/MedicationRequest

臨床 function 通道給 LINE Bot、AI Agent、行動 App:

/api/functions/recent-labs
/api/functions/active-medications
/api/functions/visit-summary

補上 OPA 跟 Kafka

之前我還討論過一套更完整的架構,把 OPA(Open Policy Agent)跟 Kafka 也放進來。角色是這樣分的:Keycloak 發證、OPA 判斷、Rails 執行、HAPI 提供資料、Kafka 傳事件。整張圖合起來大概是這樣:

SMART on FHIR + Keycloak + OPA + Rails Gateway + Kafka + HAPI FHIR 架構總覽

關鍵是 OPA 只回答「這次可不可以,如果可以要套哪些限制」,它不讀寫 FHIR、也不代理資料。真正執行 maximum_age_days = 7patient_id = token.patient 的還是 Rails。用 PDP/PEP 的講法就是:OPA 是 Policy Decision Point,Rails 是 Policy Enforcement Point。

Kafka 則不放在每次即時讀取的主路徑上。即時讀取還是走 App → Gateway → OPA → HAPI。Kafka 適合 HIS 跟 Oracle 的資料同步、事件驅動、跨 DMZ 傳輸,還有把一筆資料更新分送給通知服務、CDS、AI Summary、稽核 pipeline 這些消費端。

各元件責任我列成一張表收尾:

元件 主要責任
Kong TLS、routing、rate limit、WAF、API 管理
Keycloak 登入、OAuth2/OIDC、Token、role、scope
OPA 政策計算、Consent、purpose、constraint
Rails 執行政策、改寫查詢、遮罩結果、CQL orchestration、AI tools
HAPI FHIR FHIR REST、搜尋、驗證、版本、資料保存
Kafka HIS 同步、事件傳遞、跨區交換、非同步工作

所以我想到的那層 Rails API,不是另起爐灶,而是把先前的架構補完整。對現在要做的火線超人、患者端 SMART App 跟 AI 臨床工具,我會優先做 Rails 白名單 function API,其次才做有限制的 FHIR proxy,CQL 當 Rails 呼叫的獨立臨床邏輯引擎,不拿去取代 OAuth 授權。