Collect JAMF Security Cloud logs
This document explains how to ingest JAMF Security Cloud logs into Google Security Operations using Google Cloud Storage V2.
JAMF Security Cloud is a mobile threat defense and endpoint security platform for Apple devices. It generates threat detection, compliance, and device security event logs covering DNS-layer protection, phishing prevention, content filtering, and device risk assessment.
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
- Privileged access to the JAMF Security Cloud portal (Jamf Threat Defense or Jamf Protect console)
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, jamf-security-cloud-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 JAMF Security Cloud logs to Google Cloud Storage
JAMF Security Cloud supports streaming event data to cloud storage destinations. Configure the data export in the JAMF Security Cloud portal.
- Sign in to the JAMF Security Cloud portal.
- Go to Integrations > Data Streams.
- Click Add Stream.
- Select a supported destination type. JAMF Data Streams supports AWS S3 and Generic HTTP endpoints natively. To deliver logs to Google Cloud Storage, you can use a Generic HTTP endpoint with a Cloud Run function that writes to GCS, or configure an intermediate S3-compatible destination.
- Provide the following configuration details:
- Stream name: Enter a descriptive name (for example,
Chronicle GCS Export) - GCS bucket name: Enter the bucket name (for example,
jamf-security-cloud-logs) - Path prefix: Enter a folder prefix (for example,
jamf-security-cloud/) - Output format: Select JSON (recommended for Chronicle ingestion)
- Stream name: Enter a descriptive name (for example,
- Upload or paste the GCP service account credentials JSON key that has write access to the GCS bucket.
- Select the event types to export:
- Threat events (network threats, phishing, malware)
- Device compliance events
- DNS security events
- App risk events
- Click Save (or Create).
- Verify that log files begin appearing in the GCS bucket under the specified prefix.
- Ensure that the GCP service account used for the export has the Storage Object Creator role on the target bucket.
- Log files are written in JSON format, with each file containing 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 JAMF Security Cloud 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.
- Each Google SecOps instance has a unique service account. Do not use service accounts from other documentation or examples.
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.
- If you plan to use the deletion option (delete transferred files), grant Storage Object Admin role instead of Storage Object Viewer.
Configure a feed in Google SecOps to ingest JAMF Security Cloud 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,
JAMF Security Cloud logs). - Select Google Cloud Storage V2 as the Source type.
- Select JAMF Security Cloud as the Log type.
- Click Next.
Specify values for the following input parameters:
Field Value Storage bucket URI gs://jamf-security-cloud-logs/jamf-security-cloud/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
jamf-security-cloud-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 |
|---|---|---|
| event_data.account.parentId, event_data.action, event_data.device.os, event_data.dns.recordType, event_data.riskDetails.appRiskIndexThreshold, event_data.riskDetails.deviceRiskIndex, event_data.routeName, event_data.signatureId.id, event_data.signatureId.name, event_data.threat.result, event_data.tld, customer.parentId, customer.resellerId, device.deviceId, device.deviceName, device.carrier.carrierName, device.carrier.isoCountryCode, device.carrier.mcc, device.carrier.mnc, device.hw.deviceModel, device.hw.hwPlatform, device.hw.imei, device.hw.platform, device.lastNetworkTrafficUtcMs, device.lastUpdatedUtcMs, device.location.isoCountryCode, device.mdm.lastMdmCheckInUtcMs, device.mdm.mdmId, device.network.ssid, device.os.osVersion, device.state.activated, device.state.deploymentState, device.state.vpnActive, device.state.wifiActive, device.user.id, device.user.name, device.wanderaApp.version, trigger.triggerTimeUtcMs, trigger.triggerType, app.appId.packageName, app.appId.appName, app.appId.appVersion, app.category.label, app.category.system, app.installation.installationTimeUtcMs, app.installation.installedBy, app.developer, app.threats, app.permissions, event_data.accessPoint, event_data.alertId, event_data.event_dataType, event_data.software.softwareId, event_data.software.softwareVersion, event_data.software.softwareName, event_data.cve.id, event_data.cve.baseScore, event_data.cve.exploitAvailable, event_data.cve.attribution, event_data.threat.types, event_data.app.id, event_data.app.name, event_data.app.version | additional.fields | Merged as labels with specific keys and values from sources |
| event_data.dns.ttl | dns_answers.ttl | Converted to uinteger |
| event_data.dns.category | dns_questions.name | Value copied directly |
| event_data.receiptTime | metadata.collected_timestamp | Value copied directly |
| event_data_event_dataType_description, event_data.cve.description | metadata.description | Value from event_data_event_dataType_description if not empty, else event_data.cve.description |
| has_principal, has_user | metadata.event_type | Set to STATUS_UPDATE if has_principal true, USER_UNCATEGORIZED if has_user true, else GENERIC_EVENT |
| event_data.md1.product, md1.product | metadata.product_event_type | Value from event_data.md1.product if not empty, else md1.product |
| event_data.device.externalId, event_data.externalId | metadata.product_log_id | Value from event_data.device.externalId if not empty, else event_data.externalId |
| event_data.md1.schemaVersion, schemaVersion | metadata.product_version | Value from event_data.md1.schemaVersion if not empty, else schemaVersion |
| dns_answers | network.dns.answers | Merged from dns_answers |
| dns_questions | network.dns.questions | Merged from dns_questions |
| event_data.dns.responseStatus | network.dns.response | Set to true if NOERROR, else false |
| event_data.domain | principal.administrative_domain | Value copied directly |
| event_data.application | principal.application | Value copied directly |
| event_data.hostName, event_data.device.userDeviceName | principal.asset.hostname | Value from event_data.hostName if not empty, else event_data.device.userDeviceName |
| event_data.source.ip | principal.asset.ip | Value copied directly |
| event_data.hostName, event_data.device.userDeviceName | principal.hostname | Value from event_data.hostName if not empty, else event_data.device.userDeviceName |
| event_data.source.ip | principal.ip | Value copied directly |
| event_data.source.port | principal.port | Converted to integer |
| event_data_event_dataType_id | principal.process.pid | Value copied directly |
| event_data.event_dataUrl, event_data.cve.consoleUrl | principal.url | Value from event_data.event_dataUrl if not empty, else event_data.cve.consoleUrl |
| device.user.email | principal.user.email_addresses | Merged if matches email regex |
| event_data.account.name, event_data.user.userName | principal.user.user_display_name | Value from event_data.account.name if not empty, else event_data.user.userName |
| event_data.account.customerId, customer.customerId, event_data.customerId, device.user.email | principal.user.userid | Value from event_data.account.customerId if not empty, else customer.customerId if not empty, else event_data.customerId if not empty, else device.user.email if not email |
| event_data.blocked | security_result.action | Set to BLOCK if true, ALLOW if false |
| event_data_event_dataType_name | security_result.description | Value copied directly |
| app.threats, app.permissions, event_data.cve.id, event_data.cve.baseScore, event_data.cve.exploitAvailable, event_data.cve.attribution | security_result.detection_fields | Merged as labels from sources |
| event_data.severity | security_result.severity | Set to INFORMATIONAL if 2, LOW if 4, MEDIUM if 6, HIGH if 8, CRITICAL if 10 |
| event_data.blockReason | security_result.summary | Value copied directly |
| event_data.cve.cveDetailUrl | security_result.url_back_to_product | Value copied directly |
| event_data.device.deviceId | target.asset.asset_id | Concatenated with 'CS:' prefix |
| event_data.destination.ips, event_data.destinationIp, event_data.destination.ip, device.carrier.ipAddress, device.network.assignedIp, device.network.publicIp | target.asset.ip | Merged from sources |
| app_id_md5 | target.file.md5 | Value copied directly |
| app_id_sha1 | target.file.sha1 | Value copied directly |
| app_id_sha256 | target.file.sha256 | Value copied directly |
| event_data.destination.name | target.hostname | Value copied directly |
| event_data.destination.ips, event_data.destinationIp, event_data.destination.ip, device.carrier.ipAddress, device.network.assignedIp, device.network.publicIp | target.ip | Merged from sources |
| device.location.countryName | target.location.country_or_region | Value copied directly |
| device.hw.wifiMacAddress, event_data.accessPointBssid, device.network.bssid | target.mac | Merged from sources |
| event_data.device.osType, event_data_device_os_osType, device.os.osType | target.platform | Set to WINDOWS if matches Win, MAC if IOS or MAC_OS, LINUX if Lin, else UNKNOWN_PLATFORM, from event_data first then device |
| event_data_device_os_osVersion, device.os.osVersion | target.platform_version | Value from event_data_device_os_osVersion if not empty, else device.os.osVersion |
| event_data.destination.port | target.port | Converted to integer |
| event_data.device.deviceName | target.resource.name | Value copied directly |
| event_data.user.email | target.user.email_addresses | Merged if matches email regex |
| event_data.user.email, event_data.user.name | target.user.userid | Value from event_data.user.email if not email, else event_data.user.name |
| metadata.product_name | Set to "JAMF_SECURITY_CLOUD" | |
| metadata.vendor_name | Set to "JAMF_SECURITY_CLOUD" |
Need more help? Get answers from Community members and Google SecOps professionals.