Skip to main content

ATNA Logs

EHRbase provides capabilities to log all accesses to its services based on the ATNA (Audit Trail and Node Authentication) specification.

The following services are covered by ATNA Logging:

  • Definition
    • Stored query
      • List stored queries
      • Store a query
      • Get stored query and info/metadata
  • EHR
    • EHR
      • Create EHR
      • Create EHR with ID
      • Get EHR summary by ID
      • Get EHR summary by Subject ID
    • EHR Status
      • Get EHR Status version by time
      • Get EHR Status by version ID
      • Update EHR Status
    • Versioned EHR Status
      • Get Versioned EHR Status
      • Get Versioned EHR Status revision history
      • Get Versioned EHR Status version by time
      • Get Versioned EHR Status version by ID
    • Composition
      • Create Composition
      • Update Composition
      • Delete Composition
      • Get Composition by version ID
      • Get Composition at time
      • Delete Composition
    • Versioned Composition
      • Get Versioned Composition
      • Get Versioned Composition revision history
      • Get Versioned Composition version by ID
      • Get Versioned Composition version at time
    • Directory
      • Create Directory
      • Update Directory
      • Delete Directory
      • Get Folder in Directory version
      • Get Folder in Directory version at time
    • Contribution
      • Create Contribution
      • Get Contribution by ID
  • Query
    • Execute ad-hoc (non-stored) AQL Query
    • Execute Store Query
  • Admin
    • EHR
      • Update EHR
      • Delete EHR
    • Composition
      • Delete Composition
    • Directory
      • Delete Directory
    • Query
      • Delete query

Configuration

PropertyENVUseExample
ipf.atna.audit-enabledIPF_ATNA_AUDITENABLEDWhether to enable ATNA audit feature"true"
ipf.atna.audit-enterprise-site-idIPF_ATNA_AUDITENTERPRISESITEIDEnterprise Site ID (CDR Base Tenant ID is used)1f332a66-0e57-11ed-861d-0242ac120002
ipf.atna.audit-repository-hostIPF_ATNA_AUDITREPOSITORYHOSTAudit repository hostlocalhost
ipf.atna.audit-repository-portIPF_ATNA_AUDITREPOSITORYPORTAudit repository port514
ipf.atna.audit-source-idIPF_ATNA_AUDITSOURCEIDAudit source ID
ipf.atna.audit-value-if-missingIPF_ATNA_AUDITVALUEIFMISSINGValue used for mandatory elements that are empty.UNKNOWN
ehrbase.atna.supressLoginEventsEHRBASE_ATNA_SUPRESSLOGINEVENTSDisables auditing of the login events by ATNA logs. Events are only present for BASIC authtrue

ATNA Message Example and Mapping

The code listing shows an example ATNA message that is created whenever a user creates an electronic health record object (EHR) in EHRbase. The user information is either extracted from the Basic Auth credentials or from the OAuth2 JWT Token.

EHR creation successful
<?xml version="1.0" encoding="UTF-8"?>
<AuditMessage>
<EventIdentification EventActionCode="C" EventDateTime="2023-09-21T10:13:50.289269153Z" EventOutcomeIndicator="0">
<EventID csd-code="110110" codeSystemName="DCM" originalText="Patient Record" />
<EventOutcomeDescription>Operation performed successfully</EventOutcomeDescription>
</EventIdentification>
<ActiveParticipant UserID="john doe " UserIsRequestor="true" NetworkAccessPointID="10.216.24.150"
NetworkAccessPointTypeCode="2">
<RoleIDCode csd-code="110153" codeSystemName="DCM" originalText="Source Role ID" />
</ActiveParticipant>
<ActiveParticipant UserID="ehrbase" UserIsRequestor="false" NetworkAccessPointID="10.42.23.77"
NetworkAccessPointTypeCode="2">
<RoleIDCode csd-code="110152" codeSystemName="DCM" originalText="Destination Role ID" />
</ActiveParticipant>
<AuditSourceIdentification AuditEnterpriseSiteID="1f332a66-0e57-11ed-861d-0242ac

120002" AuditSourceID="ehrbase">
<AuditSourceTypeCode csd-code="4" codeSystemName="DCM" originalText="Application Server Process or Thread" />
</AuditSourceIdentification>
<ParticipantObjectIdentification ParticipantObjectID="ae1d91f9-43c4-4ed9-bea0-51e2f1494e0b"
ParticipantObjectTypeCode="1" ParticipantObjectTypeCodeRole="1" ParticipantObjectDataLifeCycle="1">
<ParticipantObjectIDTypeCode csd-code="2" codeSystemName="RFC-3881" originalText="Patient Number" />
</ParticipantObjectIdentification>
</AuditMessage>
FieldExplanationMapping
EventActionCodeRepresents the action performed"Create("C"), Read("R"), Update("U"), Delete("D"), Execute("E")"
EventDateTimeThe Date of the MessageUse current datetime
EventOutcomeIndicatorstatus of the operation"Success(0), MinorFailure(4), SeriousFailure(8), MajorFailure(12)"
EventID.csd-code and EventID.originalTexttype of the entity"a) In case of an EHR: csd-code="110110" and originalText="Patient Record"
b) for data operations: always the originalText="composition" / "contribution" / "query" / "directory"
c) for application activity: : csd-code="110100" and originalText="Application Activity"
AuditEnterpriseSiteIDID of the audit producing systemTenant-ID of EHRbase
ActiveParticipant.UserIDThe user identifier"a) Basic Auth: username; b) OAuth2: sub claim from the token"
ParticipantObjectID [EHR]The EHR was affected by the transactionEHR and EHR Status: 1 x ParticipantObjectIdentification with ParticipantObjectTypeCode=1, ParticipantObjectIDTypeCode.originalText=URI, and ParticipantObjectID as the Patient Subject ID of the HER
ParticipantObjectID [Composition, Contribution, Directory]Compositions, Contributions, or the Directory was affected by the transaction"a) ParticipantObjectTypeCode=1, ParticipantObjectIDTypeCode.originalText=Patient Number, and ParticipantObjectID is the Patient Subject ID of the parent EHR; b) ParticipantObjectTypeCode=2, ParticipantObjectIDTypeCode.originalText=URI, and ParticipantObjectID in the form "
ParticipantObjectID [Ad-hoc query execution]Ad-hoc queries are part of the transactionAd-hoc query execution: 1 x ParticipantObjectIdentification with ParticipantObjectTypeCode=2, ParticipantObjectIDTypeCode.originalText=Search Criteria, and ParticipantObjectID set to UNKNOWN
ParticipantObjectID [Stored queries]Creation and execution of stored queries are part of the transaction"a) ParticipantObjectTypeCode=2, ParticipantObjectIDTypeCode.originalText=URI, and ParticipantObjectID in the form b) ParticipantObjectTypeCode=2, ParticipantObjectIDTypeCode.originalText=Search Criteria, and ParticipantObjectID as the qualified name of the query"
ParticipantObjectID [Application Activity]Application events like start upActiveParticipant.UserId=The identity of the process started or stopped or the person or process starting or stopping the Application
NetworkAccessPointIDIdentification of the user device that creates the audit recordThe IP address of the requesting client

Set up an Audit Repository

The easiest way to install and configure your own Audit Record Repository instance is to use the Elastic Stack together with Docker.

Step 1: Create the Docker Compose file

The following Docker Compose file installs and configures Elasticsearch, Kibana, and Logstash according to the default configuration used in CDR Base.

services:
elasticsearch:
image: elasticsearch:7.7.0
hostname: elasticsearch
environment:
- "discovery.type=single-node"
ports:
- 9200:9200
- 9300:9300
networks:
- elastic-network
kibana:
image: kibana:7.7.0
hostname: kibana
ports:
- 5601:5601
links:
- elasticsearch:elasticsearch
depends_on:
- elasticsearch
networks:
- elastic-network
logstash:
image: logstash:7.7.0
hostname: logstash
ports:
- 9600:9600
- 8089:8089
- 514:514/udp
volumes:
- ./logstash:/usr/share/logstash/pipeline/
links:
- elasticsearch:elasticsearch
depends_on:
- elasticsearch
networks:
- elastic-network
networks:
elastic-network: {}

Step 2: Create the Docker Compose file

The second step is the configuration of Logstash to enable the support of the Syslog Protocol and DICOM Audit Trail Message

Format Profile. The following configuration file has to be stored in the directory referenced in the volume mounted in the logstash service declared in the Docker Compose file above (i.e. ./logstash/logstash.conf).

input {
udp {
port => 514
}
}
filter {
grok {
match => {
"message" => "<%{NONNEGINT:syslog_header_pri}>%{NONNEGINT:syslog_header_version}%{SPACE}(?:-|%{TIMESTAMP_ISO8601})%{SPACE}(?:-|%{IPORHOST:syslog_header_hostname})%{SPACE}(?:%{SYSLOG5424PRINTASCII:syslog_header_app-name}|-)%{SPACE}(?:-|%{SYSLOG5424PRINTASCII:syslog_header_procid})%{SPACE}(?:-|%{SYSLOG5424PRINTASCII:syslog_header_msgid})%{SPACE}(?:-|(?<syslog_structured_data>(\[.*?[^\\]\])+))(?:%{SPACE}%{GREEDYDATA:syslog_message}|)"
}
}
xml {
store_xml => true
target => "AuditMessage"
force_array => false
source => "syslog_message"
}
mutate {
remove_field => [ "@timestamp", "@version", "message", "host" ]
}
}
output {
elasticsearch { hosts => ["elasticsearch:9200"] }
}

Step 3: Start your Audit Repository instance

docker-compose -f docker-compose-audit.yml up