ihe-atna
The IHE audit trail in Rust: the sending half of ATNA Record Audit Event
(ITI-20), and the Basic Audit Log Patterns (BALP) AuditEvent sent over
ITI-20's ATX: FHIR Feed, with a feature per layer.
| Feature | Layer | Transaction |
|---|---|---|
atna |
Audit Trail and Node Authentication: the DICOM audit message over syslog with TLS, the spool and the forwarder | ITI-20 |
balp |
Basic Audit Log Patterns: the FHIR AuditEvent of an IHE FHIR transaction, sent over the ITI-20 FHIR Feed through the same spool and forwarder, without the syslog sender or its TLS stack |
ITI-20 |
retrieve |
The retrieval an Audit Record Repository serves: the query string read into typed criteria, and the searchset Bundle and refusal OperationOutcome of the answer |
ITI-81 |
recording compiles balp::recording alone and redact compiles
redact::RedactedUrl and fhir_base alone, for a profile crate that audits
through its own model or logs URLs it does not audit.
Under balp the FHIR Feed's TLS is the backend you build your
reqwest::Client with; the crate enables none.
The crate depends on no application. The profiles are published at https://profiles.ihe.net/ITI/.
ATNA (atna)
ihe_atna::atna is the sending half of ITI-20, Record Audit Event (ITI TF-2
§3.20), as syslog with the DICOM message:
message::AuditMessage: the DICOM PS3.15 Annex A.5 audit message, with its participant objects held as secrets and written to UTF-8 XML with no byte order mark, every value throughescape::untrusted, so no control or bidirectional character reaches the XML.syslog::Sender: the RFC 5424 message with the PRI<85>and the MSGIDIHE+RFC-3881§3.20.4.1.2 fixes, in its RFC 5425 octet-counted frame.repository::Repository: the connection to an Audit Record Repository,tls://host[:port]over the rustlsClientConfigyou hand it, which speaks TLS 1.2 or 1.3 alone and carries your trust roots and client certificate;unencrypted_for_developmentadmitstcp://for development and tests.repository::Timeouts: the connect timeout, and the send timeout that bounds the TLS handshake and each write and flush.spool::Spool: the bounded store a sender that cannot reach its repository keeps the records in (§3.20.4.1.1), one fsynced file per message in a directory private to its owner, or a queue in memory. A message that cannot be read or is no whole frame moves to itsquarantinesubdirectory, so the drain never stalls on it. Storing one message is bounded in time (Bounds::write_timeout): a write that misses the bound is refused asSpoolError::Lateand runs on, and a message it stores is delivered like any other.forwarder::Forwarder: stores every message first, then delivers it from the spool in order, retries a transport failure with a jittered backoff capped where the caller says, and reports the spool's depth, its quarantine, its deliveries and its retries.forwarder::Outboxlets it deliver from your own durable store instead, such as a table of records not yet sent.codes: the DICOM EventID, EventTypeCode, RoleID, AuditSourceTypeCode and ParticipantObjectDataLifeCycle codes and the RFC 3881 participant object id types, as triplesCodedValue::ofreads.targets: the stabletracingtargets of the spool and the forwarder.
A product builds the TLS configuration from the family's outbound TLS keys
(client_identity or client_identity_file, and trust_roots_file) with
ferrohealth-server's TlsClient, so the syslog connection trusts what the
product's HTTP clients trust:
use Arc;
use ;
use ;
// `section` is the product's `[audit.syslog]` table.
let tls = read?.platform_config?;
let repository = tls?;
BALP (balp)
ihe_atna::balp writes the FHIR R4 AuditEvent of one audited exchange:
Exchange: what the transaction's audit profile fixes (EventKind), the outcome, the other party, whom the exchange was made for and the entities it concerned;Exchange::audit_eventwrites the record with theObserverthat records it. Every coding a BALP pattern fixes is a public constant.AuditRecorder: a deployment's route to its repository, awaited once per transaction before its answer is used, withreserveto take a record's place before the exchange is made.atna::feed::FeedRepositorywithForwarder::fhir_feed: the ATX: FHIR Feed's Send Audit Resource Request, a FHIRcreateof each stored record at[base]/AuditEvent; a refused record is quarantined, every other failure retried.with_credentialsauthorizes each request from aCredentialssource and renews a refused token once (RFC 6750 §3.1);cleartextreaches anhttpbase for an operator who accepts it.atna::bearer::Bearer(featuresmart): the client credentials token offerrohealth-smartas thatCredentialssource, so a product writes no adapter of its own.recording: the bound on an audited exchange's record,Lateandwithin.Exchange::audit_event_value: the record as a JSON value, for a store that keeps JSON.
Retrieve (retrieve)
ihe_atna::retrieve serves Retrieve ATNA Audit Event (ITI-81), the FHIR R4
search on AuditEvent:
Query::parse: the query string, percent-decoded, read into thedateparameters and the other criteria. Each parameter takes its type (date, string, token, reference, uri) from the FHIR R4 search-parameter registry offhir-types, with the four token parameters the RESTful ATNA supplement adds (agent.identifier,patient.identifier,entity.identifier,source.identifier). Repeated parameters combine with AND and the values of one with OR; a parameter the crate does not support is ignored and named inQuery::ignored. A query with nodateis refused.date::DateParam::bounds: the interval ofrecordedinstants adatevalue matches, from its prefix and the range its precision implies. Every value, its escapes, tokens and dates, is read by the family's FHIR search grammar,fhir-search, so a query reads the same here as in the other FerroHEALTH FHIR servers.bundle::searchsetandbundle::refusal: the answer asfhir_types::r4resources.
The repository keeps its store, the query over it and who may read what.
Whom an exchange is made for
ihe_atna::user::OnBehalfOf is the User an OAuth 2.0 access token names
(its iss, sub, client_id, aud, jti and purposes of use, and
optionally the organisation, name, provider identifier, roles and assurance
level), a User::local authenticated otherwise, with no issuer and no
client, or System for an exchange the system makes on its own behalf. The BALP record
names the user in the agent:user slice and an Application agent with the
client_id (BALP 1.1.4 §3:5.7.5.4). User's Debug shows none of its
values. The module compiles with no feature, and so do redact, the
Debug rendering of a URL with its credential redacted, and (with either
feature) fhir_base, the URL of an interaction under a FHIR base.
Licence
Business Source License 1.1 (LICENSE in the repository): free for every
non-production use and for non-commercial production use; a commercial
licence for other production use; Apache License 2.0 four years after each
version. Source: https://github.com/FerroHEALTH/FerroAUDIT.