Question: How to setup the IBM FHIR Server with fhir-audit?

The IBM FHIR Server supports audit events for FHIR operations (CREATE-READ-UPDATE-DELETE-OPERATION) in Cloud Auditing Data Federation (CADF) and HL7 FHIR AuditEvent and pushing the events to an Apache Kafka backend. You can read more about it on the IBM FHIR Server site.

Let’s spin up an IBM FHIR Server with fhir-audit and see what we get with a running container.

  1. Create an Event Streams instance on IBM Cloud Console

  2. Create a topic FHIR_AUDIT

Create
  1. Click Service Credentials, click Create New Credential, Click Add
Add a Credential
  1. Expand your new Service Credential, and copy the JSON and store locally, we’ll use it in a subsequent step.
curl -L https://raw.githubusercontent.com/IBM/FHIR/main/fhir-server/liberty-config/config/default/fhir-server-config-audit-environment.json -o fhir-server-config-audit-environment.json

The file contains a setting for loading the properties from the Environment, and some basic settings:

        "audit": {
            "serviceClassName" : "com.ibm.fhir.audit.impl.KafkaService",
            "serviceProperties" : {
                "auditTopic": "FHIR_AUDIT",
                "geoCity": "Dallas",
                "geoState": "TX",
                "geoCounty": "US"
            }
        }
  1. Download the docker image
docker pull ibmcom/ibm-fhir-server:latest
$ docker pull ibmcom/ibm-fhir-server:latest
latest: Pulling from ibmcom/ibm-fhir-server
13897c84ca57: Pull complete 
64607cc74f9c: Pull complete 
16ac69f16a48: Pull complete 
54eaf4e89615: Pull complete 
215ce34bfb04: Pull complete 
23fc81994ef3: Pull complete 
358f256d50db: Pull complete 
2c5ee9f8d67e: Pull complete 
df1b462e3122: Pull complete 
64782415f212: Pull complete 
5871c358d552: Pull complete 
931b2daafdbb: Pull complete 
a77b0c08b2ad: Pull complete 
8405f4cee973: Pull complete 
a0d476c441e5: Pull complete 
d504580ab646: Pull complete 
b68755501c7d: Pull complete 
4071f846ff8d: Pull complete 
Digest: sha256:1829c8ab601355efecc190ef667fba93d92cbbd2e9305c109f736851c3ba97f4
Status: Downloaded newer image for ibmcom/ibm-fhir-server:latest
docker.io/ibmcom/ibm-fhir-server:latest
  1. Make the JSON a single line
cat << EOF | tr -d '\n'
{
  "api_key": "credentialapikey",
  "apikey": "credentialapikey",
  "iam_apikey_description": "Auto-generated for key 01ba3165-85d9-410b-ad1a-1111",
  "iam_apikey_name": "Service credentials-1",
  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/11111::serviceid:ServiceId-864b549f-ff90-4b24-84f2-1111",
  "instance_id": "6b00cc8c-26ec-4c42-a1e8-f4da5b9f71e7",
  "kafka_admin_url": "https://admin.eventstreams.cloud.ibm.com",
  "kafka_brokers_sasl": [
    "broker-3.eventstreams.cloud.ibm.com:9093",
    "broker-5.eventstreams.cloud.ibm.com:9093",
    "broker-1.eventstreams.cloud.ibm.com:9093",
    "broker-2.eventstreams.cloud.ibm.com:9093",
    "broker-4.eventstreams.cloud.ibm.com:9093",
    "broker-0.eventstreams.cloud.ibm.com:9093"
  ],
  "kafka_http_url": "https://admin.eventstreams.cloud.ibm.com",
  "password": "credentialapikey",
  "user": "token"
}
EOF

The output is:

{  "api_key": "credentialapikey",  "apikey": "credentialapikey",  "iam_apikey_description": "Auto-generated for key 01ba3165-85d9-410b-ad1a-1111",  "iam_apikey_name": "Service credentials-1",  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/11111::serviceid:ServiceId-864b549f-ff90-4b24-84f2-1111",  "instance_id": "6b00cc8c-26ec-4c42-a1e8-f4da5b9f71e7",  "kafka_admin_url": "https://admin.eventstreams.cloud.ibm.com",  "kafka_brokers_sasl": [    "broker-3.eventstreams.cloud.ibm.com:9093",    "broker-5.eventstreams.cloud.ibm.com:9093",    "broker-1.eventstreams.cloud.ibm.com:9093",    "broker-2.eventstreams.cloud.ibm.com:9093",    "broker-4.eventstreams.cloud.ibm.com:9093",    "broker-0.eventstreams.cloud.ibm.com:9093"  ],  "kafka_http_url": "https://admin.eventstreams.cloud.ibm.com",  "password": "credentialapikey",  "user": "token"}
  1. Export ES_CONFIG
export ES_CONFIG='{  "api_key": "credentialapikey",  "apikey": "credentialapikey",  "iam_apikey_description": "Auto-generated for key 01ba3165-85d9-410b-ad1a-1111",  "iam_apikey_name": "Service credentials-1",  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/11111::serviceid:ServiceId-864b549f-ff90-4b24-84f2-1111",  "instance_id": "6b00cc8c-26ec-4c42-a1e8-f4da5b9f71e7",  "kafka_admin_url": "https://admin.eventstreams.cloud.ibm.com",  "kafka_brokers_sasl": [    "broker-3.eventstreams.cloud.ibm.com:9093",    "broker-5.eventstreams.cloud.ibm.com:9093",    "broker-1.eventstreams.cloud.ibm.com:9093",    "broker-2.eventstreams.cloud.ibm.com:9093",    "broker-4.eventstreams.cloud.ibm.com:9093",    "broker-0.eventstreams.cloud.ibm.com:9093"  ],  "kafka_http_url": "https://admin.eventstreams.cloud.ibm.com",  "password": "credentialapikey",  "user": "token"}'

Note the single quotes surround the above.

  1. Start up the IBM FHIR Server with the EventStreams credentials and fhir-server-config.json we just downloaded.
docker run --rm -d -p 9443:9443 -e BOOTSTRAP_DB=true \
    -v $(pwd)/fhir-server-config-audit-environment.json:/config/config/default/fhir-server-config.json \
    -e EVENT_STREAMS_AUDIT_BINDING="${ES_CONFIG}" ibmcom/ibm-fhir-server

You’ll see the container id output 60a5f1cae6d677d80772f1736db1be74836a8a4845fcccc81286b7c557bc2d86.

  1. Check that the applications are started using the container id.
$ docker logs 60a | grep -i started
[4/21/21, 20:55:58:449 UTC] 00000001 FrameworkMana I   CWWKE0002I: The kernel started after 1.43 seconds
[4/21/21, 20:55:58:464 UTC] 0000002a FeatureManage I   CWWKF0007I: Feature update started.
[4/21/21, 20:56:01:328 UTC] 00000030 AppMessageHel A   CWWKZ0001I: Application fhir-openapi started in 1.588 seconds.
[4/21/21, 20:56:03:141 UTC] 00000031 AppMessageHel A   CWWKZ0001I: Application fhir-bulkdata-webapp started in 3.402 seconds.
[4/21/21, 20:56:07:824 UTC] 0000002d AppMessageHel A   CWWKZ0001I: Application fhir-server-webapp started in 7.871 seconds.
[4/21/21, 20:56:07:868 UTC] 0000002a TCPPort       I   CWWKO0219I: TCP Channel defaultHttpEndpoint-ssl has been started and is now listening for requests on host *  (IPv4) port 9443.
[4/21/21, 20:56:07:880 UTC] 0000002a FeatureManage A   CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 10.885 seconds.
  1. Download the Sample Data
curl -L https://raw.githubusercontent.com/IBM/FHIR/main/fhir-server-test/src/test/resources/testdata/everything-operation/Antonia30_Acosta403.json -o Antonia30_Acosta403.json
  1. Load the Sample Data bundle to the IBM FHIR Server
curl -k --location --request POST 'https://localhost:9443/fhir-server/api/v4' \
--header 'Content-Type: application/fhir+json' \
--header "Authorization: Basic ${DUMMY_PASSWORD}" \
--data-binary  "@Antonia30_Acosta403.json" -o response.json
  1. Scan the response.json for any status that is not "status": "201". For example, the status is in the family of User Request Error or Server Side Error.

Note: DUMMY_PASSWORD should be set to your environment.

  1. Download Kafka from Apache Kafka

  2. Create a client-ssl.properties from your service credentials.

cat << EOF > client-ssl.properties
bootstrap.servers=broker-2.mybroker.com:9093,broker-5.mybroker.com:9093,broker-0.mybroker.com:9093,broker-3.mybroker.com:9093,broker-4.mybroker.com:9093,broker-1.mybroker.com:9093
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="token" password="MYPASSWORD";
sasl.mechanism=PLAIN
security.protocol=SASL_SSL
ssl.protocol=TLSv1.2
EOF
  1. Unzip the kafka archive

  2. Check the Kafka Console Consumer

bash bin/kafka-console-consumer.sh \
    --bootstrap-server broker-4.mybroker.com:9093,broker-5.mybroker.com:9093,broker-3.mybroker.com:9093,broker-2.mybroker.com:9093,broker-1.mybroker.com:9093,broker-0.mybroker.com:9093 \
    --topic FHIR_AUDIT --max-messages 25 --property print.timestamp=true --consumer.config client-ssl.properties --from-beginning

We see up to 25 messages related to the generated data.

You see the CADF audit messages, and you can change settings in the fhir-server-config.json to use AuditEvent. You can see an example at https://github.com/IBM/FHIR/blob/main/fhir-server/liberty-config/config/default/fhir-server-config-audit-config.json

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.