Auditing FHIR events
Overview
Kodjin FHIR Server adheres to the AuditEvent definition and the IHE Basic Audit Log Patterns (BALP) Implementation Guide.
Kodjin utilizes the AuditEvent resource from the FHIR specification to manage audit logs. There are two approaches to handling audit logs:
External Client Responsibility: In this approach, an external client is responsible for filling and pushing AuditEvent resources to the Kodjin FHIR API. Kodjin will validate these resources against the uploaded and filled profiles. For this option, internal auditing is switched off.
Kodjin Responsibility: In this approach, Kodjin is responsible for creating, filling and storing AuditEvent resources automatically. For this option, internal auditing should be switched on.
When internal auditing is enabled, Kodjin audits both read and write accesses to the FHIR endpoints, including search, export, and import operations. In this mode, users or clients making requests cannot create, modify or delete AuditEvents through any type of request. Access to read or search AuditEvent can be limited by SMART on FHIR scopes.
Audit Events in Bundles
(Applyes only if the internal auditing is switched on)
For Bundles with the type batch
or transaction
, each record within the Bundle is processed as an independent RESTful operation. Additionally, one AuditEvent with the action E
(Execute) will be recorded for the entire Bundle, reflecting the status of its processing.
If a Bundle with type transaction fails and all actions within the Bundle are reverted, the AuditEvents will still be recorded. However, references to new resources from the Bundle will be inaccessible.
Supported IHE profiles
Following the IHE Basic Audit Log Patterns (BALP) Implementation Guide, Kodjin FHIR Server serves in an Audit Creator role and uses Minimal AuditEvent approach. This pattern avoids replicating information that can be looked up by any audit analysis application that has access.
Note that querying AuditEvent will respectively create new AuditEvents.
Kodjin FHIR Server supports the following profiles:
- Basic AuditEvent for a successful Create with known Patient subject
- Basic AuditEvent for a successful Create not related to a Patient
- Basic AuditEvent for a successful Read with a Patient
- Basic AuditEvent for a successful Read
- Basic AuditEvent for a successful Update with a Patient subject
- Basic AuditEvent for a successful Update
- Basic AuditEvent for a successful Delete with Patient
- Basic AuditEvent for a successful Delete
- Basic AuditEvent for a successful Query with Patient
- Basic AuditEvent for a successful Query
Kodjin FHIR Server doesn't automatically substitute meta.profile
for generated AuditEvent resources. To validate AuditEvent resources against these profiles, the relevant profiles and all dependencies (including terminologies) should be uploaded to Kodjin FHIR Server.
For more information on configuring the internal audit event option, please refer to the Kodjin FHIR Server configuration page.
Audit Events and Multi-tenancy
When both the Multi-tenancy and Audit Event features are enabled, the AuditEvent will align with the tenant corresponding to the interacted resources. For requests where the system cannot evaluate the particular resources (e.g., empty or incorrect search results), the AuditEvent will be recorded for every tenant present in the request (as indicated in token claims or headers). For this reason, it is not possible to use the * (asterisk symbol for wildcard) tenant.
Examples
Example AuditEvents
This example demonstrates recorded AudiEvent at audit creator for FHIR patient resource
{
"resourceType": "AuditEvent",
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-event-type",
"code": "rest",
"display": "RESTful Operation"
},
"subtype": [
{
"system": "http://hl7.org/fhir/restful-interaction",
"code": "create",
"display": "create"
}
],
"action": "C",
"recorded": "2024-08-13T19:22:51.275829971Z",
"outcome": "0",
"outcomeDesc": "201 Created",
"agent": [
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110153",
"display": "Source Role ID"
}
]
},
"who": {
"display": "192.168.0.131:2266"
},
"requestor": false,
"network": {
"address": "192.168.0.131:2266",
"type": "2"
}
},
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110152",
"display": "Destination Role ID"
}
]
},
"who": {
"display": "demo.kodjin.com"
},
"requestor": false,
"network": {
"address": "https://demo.kodjin.com/",
"type": "5"
}
}
],
"source": {
"site": "demo.kodjin.com",
"observer": {
"display": "demo.kodjin.com"
},
"type": [
{
"system": "http://terminology.hl7.org/CodeSystem/security-source-type",
"code": "4",
"display": "Application Server"
}
]
},
"entity": [
{
"what": {
"reference": "Patient/fc81b525-89c5-4c3e-a804-70994b8e2e83"
},
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-entity-type",
"code": "1",
"display": "Person"
},
"role": {
"system": "http://terminology.hl7.org/CodeSystem/object-role",
"code": "1",
"display": "Patient"
}
}
],
"id": "c752a73b-1dc3-4e8c-84c0-a242d02038aa"
}
This example demonstrates recorded AudiEvent at audit creator for non-patient FHIR resource
{
"resourceType": "AuditEvent",
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-event-type",
"code": "rest",
"display": "RESTful Operation"
},
"subtype": [
{
"system": "http://hl7.org/fhir/restful-interaction",
"code": "create",
"display": "create"
}
],
"action": "C",
"recorded": "2024-08-13T19:23:10.384678072Z",
"outcome": "0",
"outcomeDesc": "201 Created",
"agent": [
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110153",
"display": "Source Role ID"
}
]
},
"who": {
"display": "192.168.0.1:2266"
},
"requestor": false,
"network": {
"address": "192.168.0.1:2266",
"type": "2"
}
},
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110152",
"display": "Destination Role ID"
}
]
},
"who": {
"display": "demo.kodjin.com"
},
"requestor": false,
"network": {
"address": "https://demo.kodjin.com/",
"type": "5"
}
}
],
"source": {
"site": "demo.kodjin.com",
"observer": {
"display": "demo.kodjin.com"
},
"type": [
{
"system": "http://terminology.hl7.org/CodeSystem/security-source-type",
"code": "4",
"display": "Application Server"
}
]
},
"entity": [
{
"what": {
"reference": "Organization/8de7ba02-763e-4b2b-9caf-d369c28db751"
},
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-entity-type",
"code": "2",
"display": "System Object"
},
"role": {
"system": "http://terminology.hl7.org/CodeSystem/object-role",
"code": "4",
"display": "Domain Resource"
}
}
],
"id": "7efcf4ac-dddf-4a3b-a89d-ccc4a8acb3a0"
}
This example demonstrates recorded AudiEvent at audit creator role when a RESTful Query action happens successfully, and where there is an identifiable Patient subject associated with the read Resource(s).
{
"resourceType": "AuditEvent",
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-event-type",
"code": "rest",
"display": "RESTful Operation"
},
"subtype": [
{
"system": "http://hl7.org/fhir/restful-interaction",
"code": "search",
"display": "search"
}
],
"action": "E",
"recorded": "2024-08-13T19:23:17.409086430Z",
"outcome": "0",
"outcomeDesc": "200 OK",
"agent": [
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110153",
"display": "Source Role ID"
}
]
},
"who": {
"display": "192.168.0.1:2266"
},
"requestor": false,
"network": {
"address": "192.168.0.1:2266",
"type": "2"
}
},
{
"type": {
"coding": [
{
"system": "http://dicom.nema.org/resources/ontology/DCM",
"code": "110152",
"display": "Destination Role ID"
}
]
},
"who": {
"display": "demo.kodjin.com"
},
"requestor": false,
"network": {
"address": "https://demo.kodjin.com/",
"type": "5"
}
}
],
"source": {
"site": "demo.kodjin.com",
"observer": {
"display": "demo.kodjin.com"
},
"type": [
{
"system": "http://terminology.hl7.org/CodeSystem/security-source-type",
"code": "4",
"display": "Application Server"
}
]
},
"entity": [
{
"what": {
"reference": "Patient/fc81b525-89c5-4c3e-a804-70994b8e2e83"
},
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-entity-type",
"code": "1",
"display": "Person"
},
"role": {
"system": "http://terminology.hl7.org/CodeSystem/object-role",
"code": "1",
"display": "Patient"
}
},
{
"type": {
"system": "http://terminology.hl7.org/CodeSystem/audit-entity-type",
"code": "2",
"display": "System Object"
},
"role": {
"system": "http://terminology.hl7.org/CodeSystem/object-role",
"code": "24",
"display": "Query"
},
"description": "GET /Patient?name=Wineshaw",
"query": "R0VUIC9QYXRpZW50P25hbWU9V2luZXNoYXcKSG9zdDogZmhpci1zZXJ2ZXItc2VhcmNoLmZoaXItc2VydmVyOjQwMDAKWC1Gb3J3YXJkZWQtU2VydmVyOiB0cmFlZmlrLTZiN2JmZDg1YzYtejU3Z2wKWC1Gb3J3YXJkZWQtRm9yOiA4NS4xOTMuMzUuMTU0OjIyNjYsIDEwLjEuMzAuMTI5LCAxMC4xLjEwLjYwClgtRm9yd2FyZGVkLVByb3RvOiBodHRwClgtRm9yd2FyZGVkLUhvc3Q6IGtvZGppbi1mZnMtMTUyNC5lZGVubGFiLmRldgpYLUZvcndhcmRlZC1Qb3J0OiA4MApYLUZvcndhcmRlZC1QYXRoOiAvZmhpci9QYXRpZW50ClgtUmVhbC1JcDogMTAuMS4xMC42MApVc2VyLUFnZW50OiBQb3N0bWFuUnVudGltZS83LjQwLjAKQWNjZXB0OiBhcHBsaWNhdGlvbi9maGlyK2pzb247Y2hhcnNldD11dGYtOApBY2NlcHQtRW5jb2Rpbmc6IGd6aXAsIGRlZmxhdGUsIGJyCkw1ZC1Ec3QtT3ZlcnJpZGU6IGtvbmcta29uZy1wcm94eS5rb25nOjgwClBvc3RtYW4tVG9rZW46IDdhOWY1OTJkLWYyZGUtNGZkNy1iOGU5LTFiMmM1ZTViM2JiNQpYLUFtem4tVHJhY2UtSWQ6IFJvb3Q9MS02NmJiYjJhNS0xMDdjNjcyNDUwZWM2M2YxMTA1MTgzYmYKTDVkLUNsaWVudC1JZDoga29uZy1rb25nLmtvbmcuc2VydmljZWFjY291bnQuaWRlbnRpdHkubGlua2VyZC5jbHVzdGVyLmxvY2Fs"
}
],
"id": "6857043c-e832-4166-af73-9d089dae1aef"
}