Newer Version Available
RemoteKeyCalloutEvent (Beta)
The RemoteKeyCalloutEvent captures events related to the success or failure of a callout that fetches encrypted key material from an end point. Based on the Platform Events framework, a RemoteKeyCalloutEvent is published every time a callout is made to an external key service. This event lets you monitor your cache-only key callouts in real time, and receive alerts about any errors that might occur. You can subscribe to events with after insert Apex triggers and store events in custom objects, security information event management (SIEM), or other back-end systems.
Supported Calls
describeSObjects()
Special Access Rules
Access to RemoteKeyCalloutEvent data requires purchasing Salesforce Shield or Shield Platform Encryption. The RemoteKeyCalloutEvent only applies to callouts that fetch cache-only key material.
Fields
| Field | Details |
|---|---|
| Details |
|
| ReplayID |
|
| StatusCode |
|
| TenantSecretID |
|
Usage
To view a RemoteKeyCalloutEvent and perform custom actions after your callout, create an after insert Apex trigger in Dev Console. These triggers let you assign custom actions for your event. You can set in-app alerts and send email alerts to people who maintain your key service, including users who don’t have a Salesforce login.
For longer-term monitoring, you can store RemoteKeyCalloutEvent data in custom objects and custom fields, SIEM, or other back-end systems. Then use business rules to send alerts. For example, you can set an alert that sends admins an email when something is wrong with a key service.
1trigger RemoteKeyCalloutEvent on RemoteKeyCalloutEvent (after insert){
2 List<Key_Service_Callout_Log__c> l = new List<Key_Service_Callout_Log__c>();
3 Set<ID> TenantSecretIds = new Set<ID>();
4 Map<ID, TenantSecret> TenantSecrets;
5 for(RemoteKeyCalloutEvent event : Trigger.new){
6 if(event.TenantSecretId != null && !TenantSecretIds.contains(event.TenantSecretId))
7 TenantSecretIds.add(event.TenantSecretId);
8 }
9 if(TenantSecretIds != null && !TenantSecretIds.isEmpty())
10 TenantSecrets = new Map<ID, TenantSecret>([SELECT Type, Version, Status FROM TenantSecret where Id In: TenantSecretIds]);
11
12 for(RemoteKeyCalloutEvent event : Trigger.new){
13 Key_Service_Callout_Log__c log = new Key_Service_Callout_Log__c();
14 log.Status_Code__c = event.StatusCode;
15 log.Tenant_Secret_ID__c = event.TenantSecretId;
16 log.Details__c = event.Details;
17 if(TenantSecrets != null && TenantSecrets.containsKey(event.TenantSecretId)){
18 log.Type__c = TenantSecrets.get(event.TenantSecretId).Type;
19 log.Version__c = TenantSecrets.get(event.TenantSecretId).Version;
20 log.Tenant_Secret_Status__c = TenantSecrets.get(event.TenantSecretId).Status;
21 }
22 l.add(log);
23 }
24
25 insert l;
26}| Status Code | Corresponding Details |
|---|---|
| SUCCESS | NONE |
| EMPTY_RESPONSE | NONE |
| MALFORMED_JSON_RESPONSE | "error":"com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $" |
| MALFORMED_JWE_RESPONSE | "error":"org.jose4j.lang.JoseException: Parsing error: org.jose4j.json.internal.json_simple.parser.ParseException: Unexpected character (�) at position 16." |
| MALFORMED_CONTENT_ENCRYPTION_KEY | "error":"javax.crypto.BadPaddingException: Decryption error" |
| MALFORMED_DATA_ENCRYPTION_KEY | "error":"javax.crypto.BadPaddingException: Decryption error" |
| ILLEGAL_PARAMETERS_IN_JWE_HEADER | "expect": "alg, enc, kid", "actual":"alg, enc, zip, jku" |
| INCORRECT_DATA_ENCRYPTION_KEY_SIZE | "expect":"32", "actual":"16" |
| INCORRECT_KEYID_IN_JSON | "expected":"34998291-3d55-4d8c-a93b-39f9f672b4e6", "actual":"55b0eb3d-37f8-4739-ac62-24527a4b80c1" |
| INCORRECT_KEYID_IN_JWE_HEADER | "expected":"34998291-3d55-4d8c-a93b-39f9f672b4e6", "actual":"55b0eb3d-37f8-4739-ac62-24527a4b80c1" |
| INCORRECT_ALGORITHM_IN_JWE_HEADER | "expected":"RSA-OAEP","actual":"RSA1_5" |
| INCORRECT_ENCRYPTION_ALGORITHM_IN_JWE_HEADER | "expected":"A256GCM", "actual":"A192GCM" |
| RESPONSE_TIMEOUT | NONE |
| UNKNOWN_ERROR | "error":"UNKNOWN???" |
| ERROR_HTTP_CODE | "code":"305", "message":"fail" |
| AUTHENTICATION_FAILURE_RESPONSE | "error":"DataSourceAuthMissingException: please reconfigure your authentication mechanism" |
| DESTROY_HTTP_CODE | "code":"403","message":"Access Denied" |