From 4656adcda2d1be7c78be6a7abf20b7325111afb2 Mon Sep 17 00:00:00 2001 From: Chase Engelbrecht Date: Tue, 12 Mar 2024 22:31:02 -0700 Subject: [PATCH] Implement rest of OCSF model Signed-off-by: Chase Engelbrecht --- data-prepper-plugins/rule-engine/build.gradle | 3 + .../processor/converters/OCSFConverter.java | 56 ++++++- .../processor/model/datatypes/OCSF.java | 154 +++++++++++++++++- .../processor/model/datatypes/ocsf.json | 92 +++++++++++ .../plugins/processor/rules/Rule.java | 2 +- 5 files changed, 295 insertions(+), 12 deletions(-) create mode 100644 data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/ocsf.json diff --git a/data-prepper-plugins/rule-engine/build.gradle b/data-prepper-plugins/rule-engine/build.gradle index 4ec4f91f27..184515f6ae 100644 --- a/data-prepper-plugins/rule-engine/build.gradle +++ b/data-prepper-plugins/rule-engine/build.gradle @@ -38,6 +38,9 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-core' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation libs.commons.lang3 + implementation 'org.projectlombok:lombok:1.18.26' + compileOnly 'org.projectlombok:lombok:1.18.26' + annotationProcessor 'org.projectlombok:lombok:1.18.26' } generateGrammarSource { diff --git a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/converters/OCSFConverter.java b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/converters/OCSFConverter.java index 400dec0080..805de8efa1 100644 --- a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/converters/OCSFConverter.java +++ b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/converters/OCSFConverter.java @@ -4,12 +4,60 @@ import org.opensearch.dataprepper.model.record.Record; import org.opensearch.dataprepper.plugins.processor.model.datatypes.OCSF; +import java.util.Map; + public class OCSFConverter { public OCSF convert(final Record record) { final Event event = record.getData(); - final String apiOperation = event.get("/api/operation", String.class); - final String apiServiceName = event.get("/api/service/name", String.class); - - return new OCSF(apiOperation, apiServiceName); + return OCSF.builder() + .metadataProductVersion(event.get("/metadata/product/version", String.class)) + .metadataProductName(event.get("/metadata/product/name", String.class)) + .metadataProductVendorName(event.get("/metadata/product/vendor_name", String.class)) + .metadataProductFeatureName(event.get("/metadata/product/feature/name", String.class)) + .metadataUid(event.get("/metadata/uid", String.class)) + .metadataProfiles(event.getList("/metadata/profiles", String.class)) + .metadataVersion(event.get("/metadata/version", String.class)) + .time(event.get("/time", Long.class)) + .cloudRegion(event.get("/cloud/region", String.class)) + .cloudProvider(event.get("/cloud/provider", String.class)) + .dstEndpoint(event.get("/dst_endpoint", String.class)) + .httpRequestUserAgent(event.get("/http_request/user_agent", String.class)) + .srcEndpointUid(event.get("/src_endpoint/uid", String.class)) + .srcEndpointIp(event.get("/src_endpoint/ip", String.class)) + .srcEndpointDomain(event.get("/src_endpoint/domain", String.class)) + .className(event.get("/class_name", String.class)) + .classUid(event.get("/class_uid", Integer.class)) + .categoryName(event.get("/category_name", String.class)) + .categoryUid(event.get("/category_uid", Integer.class)) + .severityId(event.get("/severity_id", Integer.class)) + .severity(event.get("/severity", String.class)) + .user(event.get("/user", String.class)) + .activityName(event.get("/activity_name", String.class)) + .activityId(event.get("/activity_id", Integer.class)) + .typeUid(event.get("/type_uid", Integer.class)) + .typeName(event.get("/type_name", String.class)) + .status(event.get("/status", String.class)) + .statusId(event.get("/status_id", Integer.class)) + .mfa(event.get("/mfa", Boolean.class)) + .apiResponseError(event.get("/api/response/error", String.class)) + .apiResponseMessage(event.get("/api/response/message", String.class)) + .apiOperation(event.get("/api/operation", String.class)) + .apiVersion(event.get("/api/version", String.class)) + .apiServiceName(event.get("/api/service/name", String.class)) + .apiRequestUid(event.get("/api/request/uid", String.class)) + .resources(event.getList("/resources", OCSF.Resource.class)) + .actorUserType(event.get("/actor/user/type", String.class)) + .actorUserName(event.get("/actor/user/name", String.class)) + .actorUserUid(event.get("/actor/user/uid", String.class)) + .actorUserUuid(event.get("/actor/user/uuid", String.class)) + .actorUserAccountUid(event.get("/actor/user/account_uid", String.class)) + .actorUserCredentialUid(event.get("/actor/user/credential_uid", String.class)) + .actorSessionCreatedTime(event.get("/actor/session/created_time", Long.class)) + .actorSessionMfa(event.get("/actor/session/mfa", Boolean.class)) + .actorSessionIssuer(event.get("/actor/session/issuer", String.class)) + .actorInvokedBy(event.get("/actor/invoked_by", String.class)) + .actorIdpName(event.get("/actor/idp/name", String.class)) + .unmapped((Map) event.get("/unmapped", Map.class)) + .build(); } } diff --git a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/OCSF.java b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/OCSF.java index b7c2b1638f..b796eb4d51 100644 --- a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/OCSF.java +++ b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/OCSF.java @@ -1,21 +1,161 @@ package org.opensearch.dataprepper.plugins.processor.model.datatypes; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; + +import java.util.List; +import java.util.Map; + +@Builder public class OCSF extends DataType { + private final String metadataProductVersion; + private final String metadataProductName; + private final String metadataProductVendorName; + private final String metadataProductFeatureName; + private final String metadataUid; + private final List metadataProfiles; + private final String metadataVersion; + private final Long time; + private final String cloudRegion; + private final String cloudProvider; + private final String dstEndpoint; + private final String httpRequestUserAgent; + private final String srcEndpointUid; + private final String srcEndpointIp; + private final String srcEndpointDomain; + private final String className; + private final Integer classUid; + private final String categoryName; + private final Integer categoryUid; + private final Integer severityId; + private final String severity; + private final String user; + private final String activityName; + private final Integer activityId; + private final Integer typeUid; + private final String typeName; + private final String status; + private final Integer statusId; + private final Boolean mfa; + private final String apiResponseError; + private final String apiResponseMessage; private final String apiOperation; + private final String apiVersion; private final String apiServiceName; - - public OCSF(final String apiOperation, final String apiServiceName) { - super(); - this.apiOperation = apiOperation; - this.apiServiceName = apiServiceName; - } + private final String apiRequestUid; + private final List resources; + private final String actorUserType; + private final String actorUserName; + private final String actorUserUid; + private final String actorUserUuid; + private final String actorUserAccountUid; + private final String actorUserCredentialUid; + private final Long actorSessionCreatedTime; + private final Boolean actorSessionMfa; + private final String actorSessionIssuer; + private final String actorInvokedBy; + private final String actorIdpName; + private final Map unmapped; @Override public Object getValue(final String fieldName) { switch (fieldName) { + case "metadata.product.version": return metadataProductVersion; + case "metadata.product.name": return metadataProductName; + case "metadata.product.vendor_name": return metadataProductVendorName; + case "metadata.product.feature.name": return metadataProductFeatureName; + case "metadata.uid": return metadataUid; + case "metadata.profiles": return metadataProfiles; + case "metadata.version": return metadataVersion; + case "time": return time; + case "cloud.region": return cloudRegion; + case "cloud.provider": return cloudProvider; + case "dst_endpoint": return dstEndpoint; + case "http_request.user_agent": return httpRequestUserAgent; + case "src_endpoint.uid": return srcEndpointUid; + case "src_endpoint.ip": return srcEndpointIp; + case "src_endpoint.domain": return srcEndpointDomain; + case "class_name": return className; + case "class_uid": return classUid; + case "category_name": return categoryName; + case "category_uid": return categoryUid; + case "severity_id": return severityId; + case "severity": return severity; + case "user": return user; + case "activity_name": return activityName; + case "activity_id": return activityId; + case "type_uid": return typeUid; + case "type_name": return typeName; + case "status": return status; + case "status_id": return statusId; + case "mfa": return mfa; + case "api.response.error": return apiResponseError; + case "api.response.message": return apiResponseMessage; case "api.operation": return apiOperation; + case "api.version": return apiVersion; case "api.service.name": return apiServiceName; - default: throw new IllegalArgumentException("Field " + fieldName + " does not exist in class " + getClass().getName()); + case "api.request.uid": return apiRequestUid; + case "resources": return resources; + case "actor.user.type": return actorUserType; + case "actor.user.name": return actorUserName; + case "actor.user.uid": return actorUserUid; + case "actor.user.uuid": return actorUserUuid; + case "actor.user.account_uid": return actorUserAccountUid; + case "actor.user.credential_uid": return actorUserCredentialUid; + case "actor.session.created_time": return actorSessionCreatedTime; + case "actor.session.mfa": return actorSessionMfa; + case "actor.session.issuer": return actorSessionIssuer; + case "actor.invoked_by": return actorInvokedBy; + case "actor.idp.name": return actorIdpName; + case "unmapped": return unmapped; + default: return handleOtherFields(fieldName); + } + } + + private Object handleOtherFields(final String fieldName) { + final String[] parts = fieldName.split("\\."); + if (parts.length == 0 || !"unmapped".equals(parts[0])) { + throw new IllegalArgumentException("Field " + fieldName + " does not exist in class " + getClass().getName()); + } + + if (parts.length == 1) { + return unmapped; + } + + return unmapped.get(parts[1]); + } + + public static class Resource { + private String uid; + @JsonProperty("account_uid") + private String accountUid; + private String type; + + public Resource() { + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getAccountUid() { + return accountUid; + } + + public void setAccountUid(String accountUid) { + this.accountUid = accountUid; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; } } } diff --git a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/ocsf.json b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/ocsf.json new file mode 100644 index 0000000000..07b52ba272 --- /dev/null +++ b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/model/datatypes/ocsf.json @@ -0,0 +1,92 @@ +{ + "metadata": { + "product": { + "version": "1.08", + "name": "cloudtrail", + "vendor_name": "AWS", + "feature": { + "name": "Management" + } + }, + "uid": "44c4dfed-03e1-4307-bf66-12ce2f917fca", + "profiles": ["cloud"], + "version": "1.0.0-rc.2" + }, + "time": 1706588794000, + "cloud": { + "region": "us-east-1", + "provider": "AWS" + }, + "dst_endpoint": null, + "http_request": { + "user_agent": "AWS Internal" + }, + "src_endpoint": { + "uid": null, + "ip": null, + "domain": "AWS Internal" + }, + "class_name": "api_activity", + "class_uid": 3005, + "category_name": "Identity & Access Management", + "category_uid": 3, + "severity_id": 1, + "severity": "Informational", + "user": null, + "activity_name": "Other", + "activity_id": 99, + "type_uid": 300599, + "type_name": "User Access Management: Other", + "status": "Success", + "status_id": 1, + "mfa": null, + "api": { + "response": { + "error": null, + "message": null + }, + "operation": "CreateIPSet", + "version": null, + "service": { + "name": "guardduty.amazonaws.com" + }, + "request": { + "uid": "d37919f9-5ade-491c-992a-806cb8bb4a4b" + } + }, + "resources": [ + { + "uid": "70c28d56-3c27-4d48-9f62-15fc507c1ff5", + "account_uid": "888888888888", + "type": "AWS::GuardDuty::IpSet" + } + ], + "actor": { + "user": { + "type": "IAMUser", + "name": null, + "uid": "3615781c-4c24-4660-951f-736f4ee445af", + "uuid": "01fac3b9-b1be-4884-beef-1b8abf53676d", + "account_uid": "888888888888", + "credential_uid": "0b4a8d4f-4103-4623-9883-cdab4d754b07" + }, + "session": { + "created_time": 1706588794000, + "mfa": false, + "issuer": "9e25818e-3d90-42dd-9f4b-96b116f117a1" + }, + "invoked_by": "AWS Internal", + "idp": { + "name": null + } + }, + "unmapped": { + "userIdentity.sessionContext.sessionIssuer.type": "Role", + "eventType": "AwsApiCall", + "userIdentity.sessionContext.sessionIssuer.userName": "744632ad-2e3a-4380-8794-77a83d32dbf3", + "userIdentity.sessionContext.sessionIssuer.principalId": "2d69306c-8e3a-4b95-a615-598c948c420e", + "c55c046e-3941-406e-b15e-012cc50c027e": "b9276fbf-ba3f-4266-89c1-35070984bd67", + "4fd308de-048b-47ec-b1ba-e558f063568d": "144ac1aa-b273-4342-8a56-e47628b407a5", + "834c24ae-3e9a-4067-ba1b-a1a46033da69": "48127b36-6d65-44a2-a554-e9860717e048" + } +} \ No newline at end of file diff --git a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/rules/Rule.java b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/rules/Rule.java index c387bc575d..37bd18187b 100644 --- a/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/rules/Rule.java +++ b/data-prepper-plugins/rule-engine/src/main/java/org/opensearch/dataprepper/plugins/processor/rules/Rule.java @@ -6,7 +6,7 @@ public abstract class Rule { private final Predicate ruleCondition; - private final Predicate evaluationCondition; + private final Predicate evaluationCondition; public Rule(final Predicate ruleCondition, final Predicate evaluationCondition) { this.ruleCondition = ruleCondition;