Policy definition
The tdx Volt policy engine is based on the XACML standard, with some extenstions to integrate Verifiable Credential support.
Much of the tdx Volt policy definition and configuration is based on a default set of rules that are generated automatically when the Volt starts, such as permitting the owner of a resource to perform any action on that resource, and permitting the owner of the Volt to perform any action on any resource.
More configuration is possible by adding ‘shares’ via the fusebox or using the SaveAccess API. These shares enable adding the most common policy rules, such as granting a specific account permission to perform a specific action on a specific resource.
Sometimes it may be necessary to configure more advanced policy rules. This is possible by either creating a custom policy document, or via a special kind of ‘verifiable credential claim’ share.
Verifiable Credential claims
When a client authenticates with the tdx Volt they may present one or more verifiable credentials. The Volt may also have some verifiable credentials stored locally that relate to the authenticating client. This is known as the ‘credential cache’ and it is used to store VCs that have been issued by the Volt, as well as related VCs issued by other entitities.
Each Volt can be configured to connect to any number of other Volts and pull down copies of their credential cache. This means that the Volt will be able to verify VCs issued by other Volts, even when the Volt is not connected to the issuing entity, or when the Volt itself is offline.
Each of these verifiable credentials will be signed by the issuer and refer to the client as the ‘subject’ and have some associated ‘claims’ about the subject.
A ‘VC claim share’ provides a way to extract values out of a verifiable credential and use those values to define policy.
For example, we can configure a policy rule that allows anybody who presents a VC that is issued by Acme Inc
with a type of EmployeeCredential
and a claim of isManager
to access a sensitive document.
We can define this rule using a set of predicates defined as JSON tuples consisting of a JSON pointer and a comparison value.
The JSON pointer describes the location within the Verifiable Credential to extract the value from, and this is then compared with the second item in the tuple.
[ ["/issuer/id", "Acme Inc"], ["/type", {"includes": "EmployeeCredential"}], ["/credentialSubject/isManager", true]]
includes function
Note that the /type
JSON pointer above uses a JSON object for the comparison, which consists of the includes
function and a value. This is because the ‘type’ field in a VC is an array, so we apply the includes
function to determine if the value EmployeeCredential
exists in the array.
string-regexp-match function
The string-regexp-match
function can be used to apply wildcards to the comparison.
In the example below, the rule will evaluate true if any of the VCs presented by the client have a subject id that matches an acme.com
email address:
[ [ "/credentialSubject/id", { "string-regexp-match": ".+@acme\\.com" } ], [ "/issuer/id", "did:volt:bed919ab-6081-40e7-9677-88d1cd37a0c0" ]]
Chaining predicates
It is possible to define predicates that are evaluated against VCs related to the issuer of a credential.
When evaluating a policy, the policy engine will load all the VCs that have a subject matching the client identity. It also loads all the VCs that have a subject matching the issuers of those VCs, and so on up the chain.
This enables rules to be defined in terms of claims made against the issuer of a client credential, as well as claims against the issuer of the issuer of the credential, and so on.
The syntax for extracting data from an issuer VC involves using the @@issuer
prefix in the JSON pointers:
[ ["/credentialSubject/degree", "Mathematics"], ["/credentialSubject/award", "first"], ["@@issuer/credentialSubject/isRussellGroup", true], ["@@issuer/issuer/id", "did:uk-government-DoE"], ["@@issuer@@issuer/issuer/id", "did:uk-government-root"]]
In the example above, the predicate set will evaluate to true if there is a client VC that has a subject with a degree of Mathematics
and an award of first
.
It then determines if there is a VC that has the issuer of the client degree VC as the subject, and a subject claim of isRussellGroup
set to true.
The next predicate states that the issuer of the Russell Group credential must be the UK Department of Education.
This is essentially saying “there must be a Verifiable Credential in the VC cache that states that entity that issued the First class Mathematics degree is a Russell Group university and that credential was issued by the DoE”
And the final predicate uses a double issuer prefix (@@issuer/@@issuer
), stating that the Department of Education must have a credential issued by the UK government root identity.
Defining VC claim shares
You can configure VC claim shares using the credential_lookup member and the SaveAccess API, or via the fusebox ‘share’ dialog:
Custom policy documents
So far we have described how to extract data from VCs and compare it to literal values, such as EmployeeCredential
. This technique can be used to compare any subject or resource attribute, as well data extracted from VCs, although this is normally possible through the ‘share’ user interface in fusebox rather than manually entering predicates.
For example, the following policy document excerpt demonstrates how to permit access to a resource if the client email is alice@example.com
and the resource name is Alice's secret document
.
{ ... "target": { "allOf": [ { "anyOf": [ { "allOf": [ { "attributeId": "volt:subject-email-id", "category": "subject", "dataType": "string", "functionId": "string-equal", "value": "alice@example.com" }, { "attributeId": "volt:resource-name", "category": "resource", "dataType": "string", "functionId": "string-equal", "issuer": "", "value": "Alice's secret document" } ] } ] } ] }}
In this example, we are comparing the subject email with a literal value and the resource name with a literal value.
In some instances, it may be desirable to compare attributes or VC properties with other attributes rather than literal values. The policy engine supports doing this via a custom policy document. The custom policy document can contain one or more policies, where each policy has a ‘rule’ that determines the decision for a request.
By adding a custom policy document, you can define your own rules and conditions.
Below is an excerpt of a custom policy document that demonstrates using a rule condition that allows a user to access a resource if they are the owner of the resource. It does this by comparing the subject identity with the identity of the resource owner.
{ ... "condition": { "description": "compare subject DID and resource owner", "functionId": "string-equal", "typeName": "Apply", "args": [ { "attributeId": "volt:subject-identity-did", "category": "subject", "dataType": "string", "typeName": "AttributeDesignator" }, { "attributeId": "volt:resource-owner", "category": "resource", "dataType": "string", "typeName": "AttributeDesignator" } ] }}
Rule conditions can also make use of attributes extracted from Verifiable Credentials, allowing them to be compared to other attributes.
The format for defining the VC rule condition is similar to the that described above, but the last item in the predicate set is a JSON pointer indicating the data to extract from the VC.
The example below, defines an attribute lookup that will match a VC issued by did:example:nottingham-university
that has a degree subject of Maths
, a degree type of BSc
, and a degree award of first
.
[ ["/credentialSubject/degreeSubject", "Maths"], ["/credentialSubject/degreeType", "BSc"], ["/credentialSubject/degreeAward", "first"], ["/issuer/id", "did:example:nottingham-university"] "/credentialSubject/year"]
The last item in the predicate is /credentialSubject/year
, which defines the value that will be extracted from the VC if all the previous predicates are true.
When defining the rule condition to include a VC attribute, set the attributeId
to volt:subject-vc-claim
and the attributeExtra
field to the JSON array of predicates.
We can then use this attribute lookup in a rule condition to permit access to a resource if the client has a degree that was awarded this year:
{ "id": "7e7cfd41-6f0e-4550-9f5f-ee93f9bd5b00", "description": "degree check", "ruleCombiningAlgorithm": "first-applicable", "policyCombiningAlgorithm": "first-applicable", "rules": [ { "description": "permit first class maths degree awarded this year", "effect": "permit", "condition": { "functionId": "string-equal", "args": [ { "attributeId": "volt:subject-vc-claim", "category": "subject", "dataType": "mixed", "typeName": "AttributeDesignator", "attributeExtra": "[ ["/credentialSubject/degreeSubject", "Maths"], ["/credentialSubject/degreeType", "BSc"], ["/credentialSubject/degreeAward", "first"], ["/issuer/id", "did:example:nottingham-university"] "/credentialSubject/year" ]" }, { "attributeId": "volt:environment-year", "category": "environment", "dataType": "mixed", "typeName": "AttributeDesignator" } ], "typeName": "Apply" } } ]}
Defining custom policy documents
Custom policy documents can be defined in the fusebox ‘policy’ dialog.
The policy document can be defined using the editor GUI or in JSON format.
The policy document will then be saved to the Volt’s policy store, and will be loaded by the Volt when it starts.