HL7 FHIR Implementation Guide: Data Access Policies, published by HL7 International / Security. This guide is not an authorized publication; it is the continuous build for version 1.0.0-current built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/data-access-policies/ and changes regularly. See the Directory of published versions
Page standards status: Informative |
This use-case analysis shows how a Permission can express an organization's overriding policy.
An Overriding policy is an important part of an organization’s overall risk management strategy. They help to protect the organization from potential legal liability, as well as from reputational damage. Overriding policies should be aligned with other policies within the organization, such as data security policies, employee training policies, and incident response plans. Overriding policies should be reviewed and updated regularly to ensure that they reflect the latest legal and regulatory requirements. They should also be communicated to employees and customers in a clear and concise way.
The use-case analysis is still a work in progress. Only the very basis has been described here. Many open-issues need further development, including:
The following is some other parts of an overriding policy that likely should be worked on here:
An Overriding policy expresses the default rules at an organization. An overriding policy must include all the rules necessary for the organization to function. This includes clinical workflows but also non-clinical workflows. Workflows such as billing, public-health reporting, response to legal requests, etc.
The Overriding policy fits within larger policies that cover operational aspects, such as how users are created, activated, and deactivated. How Patients are given access to their data as a User.
The Overriding policy includes the rules around clinical accessibility to a Patient's data when that Patient has not expressed a Consent. Where the Consent restricts access, what kind of circumstances may a break-glass be used.
An Overriding policy must express how it relates to the regulations that the organization must be conformant. This may include expressing the specific rules that are derived from a given regulation. Further background on the writing of Overriding (Privacy) policies can be found in IHE Appendix P: Privacy Access Policies (Informative).
The following does not try to express a complete Overriding policy, but rather picks some parts of an Overriding policy that might be difficult.
The analysis here includes what is commonly called "Role Based Access Control" (RBAC) and "Attribute Based Access Control" (ABAC). Below are some various perspectives on how an Overriding policy might be structured around RBAC and ABAC. These are not recommendation, but are rather given so as to fully exercise the FHIR Permission structure.
In Simple RBAC the access control rules are simply a given role authorizes some Create/Read/Update/Delete to a given FHIR Resource type. This is shown first as it is the most easy to write rule set. However this simple mapping is often problematic for a specific set of common usecases.
This is the kind of access control rule that SMART-App-Launch is founded up; although SMART-App-Launch allows the server to further refine the access control rules in undefined ways which is how Consents are managed and how Patient access is managed.
In Security Tagged ABAC the rules are for a given role (clearance) authorizes some Create/Read/Update/Delete to data with a given security tag (compartment). This is shown second as it is easy to write the rule set, but relies on a security labeling service to tag all data. The Security labeling service tends to be where the complexity is. In this most simple form of ABAC there would still be some common usecases that are not addressed.
The Deep ABAC use-case leverages Security Tag ABAC, and adds to this further refinements that use different data attributes, user attributes, and contextual details. Thus this set of use-cases can include Access Control rules such as:
The following is for illustration purposes. It is neither complete, nor represents the real-world.
Note that the Patient is not included as Patient access to their own data requires deep ABAC support.
Note that role first and resource-type first can both be used, but the choice is important for traversing the Permission instance.
Role first sets down the rules starting from the roles, then expressing what they can do.
role | access | resource type |
---|---|---|
doctor | CRU | Observation, AllergyIntolerance, Condition, … |
doctor | R | Practitioner, PractionerRole, Person, RelatedPerson, Organization, Location, … |
dietician | R | AllergyIntolerance, Condition, … |
registration | CRU | Patient, RelatedPerson, Person |
registration | R | Organization, Location, Practitioner, PractitionerRole… |
janitor | ||
admin | UD | * |
Traversing the Permission holding role first rules one simply looks for the rules that apply to the given role(s) that the user/actor has. Thus like the table above, see example below, one would find in the Permission the second and third rule entries apply to the doctor role, and thus they are the only rules needing to be looked at. The other rules do not apply. Within these two rules, the combining element indicated permit-overrides and thus either of the two that allows the requested action would permit the action. The first rule in this Permission is a deny
with a permit-overrides
combining rule, thus if no permit
is found then no access is granted. Note that the Access Control rules engine need only find a reason to permit.
Note that PurposeOfUse is also represented in this Permission instance as part of the activity. Thus one must, in addition to looking for role first, must look for role and purposeOfUse. Thus you can see that the Doctor is not authorized to request any data except under PurposeOfUse of treatment.
...
* combining = #permit-overrides
* rule[+].type = #deny // default is that NO ONE gets access
// Doctor CRU
* rule[+].type = #permit
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Observation
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#AllergyIntolerance
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Condition
* rule[=].activity.actor = Reference(DrRole)
* rule[=].activity.action[+] = http://hl7.org/fhir/audit-event-action#C
* rule[=].activity.action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity.action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity.purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#TREAT
* rule[=].limit = http://terminology.hl7.org/CodeSystem/v3-ActCode#AUDIT
// Doctor R
* rule[+].type = #permit
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Practitioner
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#PractitionerRole
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Person
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Patient
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#RelatedPerson
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Organization
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Location
* rule[=].activity.actor = Reference(DrRole)
* rule[=].activity.action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity.purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#TREAT
* rule[=].limit = http://terminology.hl7.org/CodeSystem/v3-ActCode#AUDIT
...
Resource-type first sets down the rules starting from the resource-type, then expressing who can do what
resource type | doctor | dietician | registration | janitor | admin |
---|---|---|---|---|---|
Observation | CRU | UD | |||
… other clinical | CRU | UD | |||
AllergyIntolerance | CRU | R | UD | ||
Condition | CRU | R | UD | ||
Practitioner | R | R | R | UD | |
PractionerRole | R | R | R | UD | |
Person | R | R | RU | UD | |
RelatedPerson | R | R | RU | UD | |
Organization | R | R | R | UD | |
Location | R | R | R | UD | |
Patient | R | R | CRU | UD | |
… |
Traversing the Permission holding resource first rules one needs to understand the kind of resource being requested, find that in the rules, and can then understand the roles / purposeOfUse that have a given action right. So where an access request is to the Observation resource, the second entry in the Permission would be all that is needed.
...
* combining = #permit-overrides
* rule[+].type = #deny // default is that NO ONE gets access
// Observation
* rule[+].type = #permit
* rule[=].data[+].extension[resourceType].valueCode = https://hl7.org/fhir/codesystem-fhir-types#Observation
* rule[=].activity[+].actor = Reference(DrRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#C
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#TREAT
* rule[=].activity[+].actor = Reference(AdminRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#D
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#HOPERAT
* rule[=].limit = http://terminology.hl7.org/CodeSystem/v3-ActCode#AUDIT
...
The following is for illustration purposes. It is neither complete, nor represents the real-world.
role | access | Confidentiality Tag |
---|---|---|
doctor | CRU | Normal, Restricted |
doctor | R | Low, Moderate |
dietician | R | Normal, Low, Moderate |
registration | CRU | Moderate |
registration | R | Low |
janitor | ||
admin | UD | * |
Note that we are using the same "role" concept as above, but in an ABAC system these grouping mechanisms for users would be called "clearance". In both cases the PractitionerRole
resource is used.
Presumes that Confidentiality Tag is added to all data by a Security Labeling Service (SLS). This example is only using the following ConfidentalityCodes for simplicity purposes. This model can be extended to other codes as well such as sensitivity classifications. The advantage of using ConfidentialityCodes in this example is because the vocabulary is a non-overlapping set of codes. Thus any piece of data will fall into ONE of the given codes. This simplification for this model is not realistic overall, but ABAC is not limited in this way. ABAC can operate on any vocabulary and against any 'attribute' (in FHIR these are called 'elements'), and any relationshps between attributes and their values.
For our example purposes: SLS would be configured to tag using ConfidentialityCode:
Note that the Patient is not included as Patient access to their own data requires deep ABAC support.
Note that the concept of Break-Glass is introduced here as a PurposeOfUse of ETREAT
, to indicate that Restricted data can only be accessed by doctors under emergency treatment context.
ABAC can be role first or security tag first. The Permission example for ABAC is showing security tag first. So there is a rule for each ConfidentialityCode, and the activities indicate who can do what with that kind of data.
...
* combining = #permit-overrides
* rule[+].type = #deny // default is that NO ONE gets access
* rule[+].type = #permit
* rule[=].data[+].security = http://terminology.hl7.org/CodeSystem/v3-Confidentiality#N
* rule[=].activity[+].actor = Reference(DrRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#C
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#TREAT
* rule[=].activity[+].actor = Reference(DieticianRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#TREAT
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#HOPERAT
* rule[=].activity[+].actor = Reference(AdminRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#D
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#HOPERAT
* rule[=].limit = http://terminology.hl7.org/CodeSystem/v3-ActCode#AUDIT
* rule[+].type = #permit
* rule[=].data[+].security = http://terminology.hl7.org/CodeSystem/v3-Confidentiality#R
* rule[=].activity[+].actor = Reference(DrRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#C
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#R
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#ETREAT
* rule[=].activity[+].actor = Reference(AdminRole)
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#D
* rule[=].activity[=].action[+] = http://hl7.org/fhir/audit-event-action#U
* rule[=].activity[=].purpose[+] = http://terminology.hl7.org/CodeSystem/v3-ActReason#HOPERAT
* rule[=].limit = http://terminology.hl7.org/CodeSystem/v3-ActCode#AUDIT
...
Given that an Overriding Policy could be written using Permission. Then a Consent.policyBasis could point at that Permission.
...
Instance: ex-consent-permission
InstanceOf: Consent
Title: "Consent that uses Permission for rules"
Description: """
Some would prefer to use the Permission rule encoding, and not the Consent.provision; thus the Consent is used to capture the ceremony, and points at a Permission for the rules.
"""
Usage: #example
* meta.security = http://terminology.hl7.org/CodeSystem/v3-ActReason#HTEST
* status = #active
* date = "2022-06-13"
* category = http://loinc.org#59284-0 "Consent Document"
* subject = Reference(ex-patient)
* grantor = Reference(ex-patient)
* policyBasis.reference = Reference(ex-overriding-rbac-by-role)
* decision = #permit
...