Security & OAuth2 with Keycloak

Trong lĩnh vực y tế, việc bảo mật dữ liệu bệnh nhân là một yêu cầu thiết yếu. Khi triển khai hệ thống dựa trên tiêu chuẩn HL7 FHIR phiên bản 5, việc thiết lập một hệ thống xác thực và phân quyền mạnh mẽ trở nên cực kỳ quan trọng. Bài viết này sẽ phân tích cách triển khai bảo mật cho hệ thống FHIR v5 bằng cách sử dụng OAuth2 kết hợp với Keycloak.

HL7 FHIR v5 và yêu cầu bảo mật

FHIR v5 đã cải tiến đáng kể về khía cạnh bảo mật so với các phiên bản trước, với việc tích hợp chặt chẽ hơn cùng OAuth2, hỗ trợ SMART on FHIR và cung cấp các cơ chế bảo mật tiên tiến. Tiêu chuẩn này yêu cầu:

  1. Xác thực người dùng mạnh mẽ

  2. Phân quyền chi tiết đến từng resource

  3. Bảo vệ dữ liệu trong quá trình truyền tải

  4. Kiểm soát đồng ý của bệnh nhân

  5. Theo dõi và ghi nhật ký truy cập

OAuth2 trong môi trường FHIR

OAuth2 là giao thức ủy quyền tiêu chuẩn được FHIR khuyến nghị sử dụng. Trong môi trường y tế, OAuth2 giúp giải quyết một số thách thức quan trọng:

  • Ủy quyền giữa các hệ thống: Cho phép các ứng dụng bên thứ ba truy cập vào dữ liệu FHIR mà không cần biết thông tin đăng nhập của người dùng

  • Phân quyền chi tiết: Sử dụng scopes để giới hạn quyền truy cập vào các resource cụ thể

  • Tích hợp với SMART on FHIR: Cung cấp khung làm việc chuẩn cho các ứng dụng y tế

Flow OAuth2 cơ bản trong FHIR:

  1. Ứng dụng yêu cầu người dùng cấp quyền truy cập

  2. Người dùng xác thực với máy chủ ủy quyền (Keycloak)

  3. Máy chủ ủy quyền cấp mã ủy quyền

  4. Ứng dụng đổi mã ủy quyền lấy token truy cập

  5. Ứng dụng sử dụng token để truy cập API FHIR

Keycloak làm máy chủ OAuth2 cho FHIR

Keycloak là một giải pháp Identity và Access Management mã nguồn mở, cung cấp nhiều tính năng phù hợp với yêu cầu bảo mật của FHIR:

1. Thiết lập Keycloak cho FHIR

// Định nghĩa Client trong Keycloak cho FHIR Server
{
  "clientId": "fhir-server",
  "enabled": true,
  "protocol": "openid-connect",
  "redirectUris": ["https://fhir-server/callback"],
  "webOrigins": ["https://fhir-server"],
  "publicClient": false,
  "authorizationServicesEnabled": true,
  "serviceAccountsEnabled": true
}

2. Định nghĩa Scopes cho FHIR

Trong Keycloak, bạn cần định nghĩa các scopes phù hợp với các resource và quyền truy cập FHIR:

  • patient/*.read: Đọc tất cả resource của bệnh nhân

  • patient/Observation.write: Ghi dữ liệu Observation cho bệnh nhân

  • user/Patient.search: Tìm kiếm bệnh nhân

  • system/MedicationRequest.create: Tạo đơn thuốc

  • launch/patient: Khởi chạy với ngữ cảnh bệnh nhân

3. Cấu hình Roles và Permissions

Triển khai mô hình RBAC (Role-Based Access Control) trong Keycloak:

  • Roles: Doctor, Nurse, Patient, Admin, System

  • Permissions: Ánh xạ roles với các scopes FHIR

4. Tích hợp với FHIR Server

// Cấu hình FHIR Server để sử dụng Keycloak OAuth2
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors().and().csrf().disable()
            .authorizeRequests(authorize -> authorize
                .antMatchers("/fhir/metadata").permitAll()
                .antMatchers("/fhir/Patient/**").hasAuthority("SCOPE_patient/*.read")
                .antMatchers("/fhir/Observation/**").hasAuthority("SCOPE_patient/Observation.read")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwtAuthenticationConverter(jwtAuthenticationConverter())
                )
            );
        return http.build();
    }
    
    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwt -> {
            List<String> scopes = jwt.getClaimAsStringList("scope");
            return scopes.stream()
                .map(scope -> new SimpleGrantedAuthority("SCOPE_" + scope))
                .collect(Collectors.toList());
        });
        return converter;
    }
}

Cài đặt SMART on FHIR với Keycloak

SMART on FHIR (Substitutable Medical Applications and Reusable Technologies) là một tập hợp các đặc tả mở dựa trên OAuth2 để ứng dụng tích hợp với hệ thống FHIR. Để hỗ trợ SMART on FHIR với Keycloak:

  1. Tùy chỉnh Mappers trong Keycloak:

    • Tạo protocol mapper để bổ sung thông tin ngữ cảnh FHIR vào token

  2. Hỗ trợ SMART App Launch Framework:

    • Cấu hình endpoint /.well-known/smart-configuration

    • Triển khai các endpoint launch/callback

Quản lý đồng ý của bệnh nhân

Một khía cạnh quan trọng trong FHIR v5 là việc quản lý đồng ý của bệnh nhân (Consent Management). Kết hợp Keycloak và FHIR Consent resource:

// Triển khai kiểm tra đồng ý trong FHIR Interceptor
@Component
public class ConsentInterceptor implements IServerInterceptor {
    
    @Autowired
    private IFhirResourceDao<Consent> consentDao;
    
    @Override
    public boolean incomingRequestPostProcessed(RequestDetails requestDetails) {
        // Lấy thông tin bệnh nhân từ token
        String patientId = extractPatientIdFromToken(requestDetails);
        
        // Kiểm tra resource Consent
        SearchParameterMap searchMap = new SearchParameterMap();
        searchMap.add("patient", new ReferenceParam(patientId));
        searchMap.add("status", new TokenParam("active"));
        
        IBundleProvider results = consentDao.search(searchMap);
        List<IBaseResource> consents = results.getResources(0, results.size());
        
        // Kiểm tra quyền theo chính sách đồng ý
        return evaluateConsents(consents, requestDetails);
    }
    
    // Các phương thức hỗ trợ
}

Bảo mật mạng và truyền tải

Ngoài OAuth2 và Keycloak, bảo mật mạng và truyền tải cũng rất quan trọng:

  1. TLS/SSL: Yêu cầu HTTPS cho tất cả kết nối

  2. API Gateway: Sử dụng để thêm lớp bảo mật

  3. Mutual TLS: Xác thực hai chiều giữa các hệ thống

  4. IP Filtering: Giới hạn truy cập theo địa chỉ IP

Kiểm toán và ghi nhật ký

FHIR v5 có yêu cầu ghi nhật ký hành động đối với dữ liệu nhạy cảm. Kết hợp AuditEvent resource với Keycloak:

// Ghi nhật ký hành động truy cập
@Component
public class AuditLogger {
    
    @Autowired
    private IFhirResourceDao<AuditEvent> auditEventDao;
    
    public void logAccess(String userId, String action, String resourceType, String resourceId) {
        AuditEvent auditEvent = new AuditEvent();
        auditEvent.setAction(AuditEvent.AuditEventAction.fromCode(action));
        
        AuditEvent.AuditEventAgentComponent agent = new AuditEvent.AuditEventAgentComponent();
        agent.setWho(new Reference("Practitioner/" + userId));
        auditEvent.addAgent(agent);
        
        AuditEvent.AuditEventEntityComponent entity = new AuditEvent.AuditEventEntityComponent();
        entity.setWhat(new Reference(resourceType + "/" + resourceId));
        auditEvent.addEntity(entity);
        
        auditEventDao.create(auditEvent);
    }
}

Các thách thức và giải pháp

1. Hiệu suất

Việc xác thực và phân quyền có thể ảnh hưởng đến hiệu suất hệ thống. Giải pháp:

  • Sử dụng token caching

  • Tối ưu hóa kiểm tra quyền truy cập

  • Cân nhắc JWT với các claims cần thiết

2. Quản lý phiên

Trong môi trường y tế, việc quản lý phiên rất quan trọng. Giải pháp:

  • Thiết lập thời gian sống hợp lý cho token

  • Cơ chế refresh token thông minh

  • Cơ chế đăng xuất tự động khi không hoạt động

3. Đa dạng đối tượng người dùng

Hệ thống y tế phục vụ nhiều đối tượng khác nhau. Giải pháp:

  • Thiết kế hệ thống Keycloak phân cấp với nhiều Realms

  • Sử dụng Identity Brokering cho SSO

  • Federation user với các hệ thống hiện tại (LDAP, Active Directory)

Kết luận

Việc kết hợp OAuth2 và Keycloak cho bảo mật FHIR v5 mang lại nhiều lợi ích:

  • Hệ thống xác thực và phân quyền mạnh mẽ

  • Tuân thủ các tiêu chuẩn bảo mật hiện đại

  • Khả năng mở rộng và tích hợp với các hệ thống khác

  • Quản lý trung tâm các chính sách bảo mật

Tuy nhiên, việc triển khai cần được thực hiện cẩn thận, với sự cân nhắc đầy đủ về hiệu suất, trải nghiệm người dùng và yêu cầu tuân thủ pháp lý trong lĩnh vực y tế.

Last updated