Collect JumpCloud Directory Insights logs
This document explains how to ingest JumpCloud Directory Insights logs into Google Security Operations using Google Cloud Storage V2.
JumpCloud is a cloud directory platform that provides identity management, SSO, and device management. Directory Insights delivers audit and activity logs covering user authentication, admin actions, and system events. The parser maps log fields to the Unified Data Model (UDM), handling event types such as user logins, resource changes, and security actions.
Before you begin
Make sure you have the following prerequisites:
- A Google SecOps instance
- A GCP project with Cloud Storage API enabled
- Permissions to create and manage GCS buckets and IAM policies
- A JumpCloud account with an Admin or Manager role and a valid API key
Create Google Cloud Storage bucket
- Go to the Google Cloud Console.
- Select your project or create a new one.
- In the navigation menu, go to Cloud Storage > Buckets.
- Click Create bucket.
Provide the following configuration details:
Setting Value Name your bucket Enter a globally unique name (for example, jumpcloud-directory-insights-logs)Location type Choose based on your needs (Region, Dual-region, Multi-region) Location Select the location (for example, us-central1)Storage class Standard (recommended for frequently accessed logs) Access control Uniform (recommended) Protection tools Optional: Enable object versioning or retention policy Click Create.
Export JumpCloud Directory Insights logs to Google Cloud Storage
JumpCloud Directory Insights exposes events through the Directory Insights API. Use a scheduled script or Cloud Run function to pull events and write them to GCS.
Generate a JumpCloud API key:
- Sign in to the JumpCloud Admin Portal.
- Go to your profile icon and select My API Key.
- Copy the API key.
Create a Cloud Run function that queries the JumpCloud Directory Insights API, retrieves events, and writes them to GCS.
Trigger the function on a schedule using Cloud Scheduler and Pub/Sub.
- Ensure that the exported files retain their original JSON format.
- Each file should contain one or more event records.
Retrieve the Google SecOps service account
- Sign in to the Google SecOps console.
- Go to SIEM Settings > Feeds.
- Click Add New Feed.
- Click Configure a single feed.
- Select Google Cloud Storage V2 as the Source type.
- Select JumpCloud Directory Insights as the Log type.
Click Get Service Account. A unique service account email will be displayed, for example:
chronicle-12345678@chronicle-gcp-prod.iam.gserviceaccount.comCopy this email address. You will use it in the next step.
Grant IAM permissions to the Google SecOps service account
- Go to Cloud Storage > Buckets.
- Click your bucket name.
- Go to the Permissions tab.
- Click Grant access.
- Provide the following configuration details:
- Add principals: Paste the Google SecOps service account email.
- Assign roles: Select Storage Object Viewer.
- Click Save.
Configure a feed in Google SecOps to ingest JumpCloud Directory Insights logs
- Go to SIEM Settings > Feeds.
- Click Add New Feed.
- Click Configure a single feed.
- In the Feed name field, enter a name for the feed (for example,
JumpCloud Directory Insights Logs). - Select Google Cloud Storage V2 as the Source type.
- Select JumpCloud Directory Insights as the Log type.
- Click Next.
Specify values for the following input parameters:
Field Value Storage bucket URI gs://jumpcloud-directory-insights-logs/jumpcloud/Source Deletion Option Select the deletion option according to your preference Maximum File Age (Days) Default is 180 days Asset namespace The asset namespace Ingestion labels The label to be applied to the events from this feed - Replace
jumpcloud-directory-insights-logswith your actual GCS bucket name. - Always include the trailing slash (
/) at the end of the URI.
- Replace
Click Next.
Review your new feed configuration in the Finalize screen, and then click Submit.
UDM mapping table
| Log Field | UDM Mapping | Logic |
|---|---|---|
| data.profile_list.payload_content.payload_type, data.profile_list.payload_content.payload_identifier, data.profile_list.payload_content.payload_uuid, data.profile_list.payload_content.payload_organization, data.profile_list.payload_content.payload_display_name, data.profile_list.payload_content.payload_description | about | Merged with attribute labels from payloadContent |
| data.association.op, data.association.action_source, data.geoip.region_code, data.service, data.event_type, data.@version, data.application.version, data.application.publisher, data.application.uninstall_string, data.changes.0.field, data.changes.0.from, data.changes.0.to, data.available_os_updates.allows_install_later | additional.fields | Merged with corresponding labels |
| extensions.auth.type | Set to "MACHINE" when event_type is USER_LOGIN | |
| data.timestamp | metadata.event_timestamp | Converted using date match ISO8601, RFC3339, yyyy-MM-ddTHH:mm:ss.SSSSSSZ |
| data.message, data.client_ip, data.initiated_by.username, data.system.hostname | metadata.event_type | Set to USER_LOGIN if message matches "logged in" and target not empty, else USER_UNCATEGORIZED if ip and userid present, else STATUS_UPDATE if hostname or ip present, else USER_UNCATEGORIZED if userid present, else GENERIC_EVENT |
| data.id | metadata.product_log_id | Value copied directly |
| data.@version, data.application.version | metadata.product_version | Set to data.@version, then replaced with data.application.version |
| data.application.name | principal.application | Value copied directly |
| data.mdm_type | principal.asset.hardware | Merged with manufacturer set to data.mdm_type |
| data.command_uuid | principal.asset_id | Concatenated as "commandUuid:" + data.command_uuid |
| data.system.hostname | principal.hostname | Value copied directly |
| data.client_ip | principal.ip | Merged from data.client_ip |
| data.geoip.country_code | principal.location.country_or_region | Value copied directly |
| data.geoip.region_code | principal.location.name | Value copied directly |
| data.geoip.latitude | principal.location.region_latitude | Converted to string then to float |
| data.geoip.longitude | principal.location.region_longitude | Converted to string then to float |
| data.geoip.region_name | principal.location.state | Value copied directly |
| data.application.path, data.process_name | principal.process.file.full_path | Set to data.application.path, then replaced with data.process_name |
| data.association.connection.from.name, data.mdm_device_manager_id, data.request_type | principal.resource.attribute.labels | Merged with labels for connection_from_name, mdm_device_manager_id, request_type |
| data.system.id, data.resource.id, data.mdm_device_id | principal.resource.id | Set to data.system.id, then replaced with data.resource.id, then replaced with data.mdm_device_id |
| data.resource.username | principal.resource.name | Value copied directly |
| data.association.connection.from.object_id | principal.resource.product_object_id | Value copied directly |
| data.association.connection.from.type | principal.resource.type | Value copied directly |
| data.initiated_by.email | principal.user.email_addresses | Merged if email matches ^.+@.+$ |
| data.system.displayName | principal.user.user_display_name | Value copied directly |
| data.initiated_by.username, data.admin_info.name | principal.user.userid | Set to data.initiated_by.username, then replaced with data.admin_info.name, then replaced with data.initiated_by.username |
| data.success, data.status | sec_result.action | Set to ALLOW if success true or status Acknowledged, BLOCK if success false |
| data.status, data.success | sec_result.action_details | Set to status if not empty, else success |
| data.success, data.status, data.security_info.management_status.is_activation_lock_manageable, data.security_info.management_status.is_user_enrollment, data.security_info.management_status.enrolled_via_dep, data.organization, data.windows_meta.logon_type, data.security_info.management_status.user_approved_enrollment | sec_result.detection_fields | Merged with labels for is_activation_lock_manageable, is_user_enrollment, enrolled_via_dep, organization, logon_type, user_approved_enrollment |
| data.query_responses.device_name | target.hostname | Value copied directly |
| data.query_responses.wifi_mac | target.mac | Merged from data.query_responses.wifi_mac |
| data.query_responses.model_name | target.platform | Set to "MAC" if matches (?i)mac |
| data.query_responses.os_version | target.platform_version | Value copied directly |
| data.query_responses.available_device_capacity, data.query_responses.device_capacity | target.resource.attribute.labels | Merged with labels for available_device_capacity, device_capacity |
| data.association.connection.to.name | target.resource.name | Value copied directly |
| data.association.connection.to.object_id | target.resource.product_object_id | Value copied directly |
| data.association.connection.to.type | target.resource.type | Value copied directly |
| data.profile_list.payload_organization | target.user.department | Merged from profile_payload_organization |
| metadata.vendor_name | Set to "JUMPCLOUD_DIRECTORY_INSIGHTS" | |
| metadata.product_name | Set to "JUMPCLOUD_DIRECTORY_INSIGHTS" |
Need more help? Get answers from Community members and Google SecOps professionals.