Summary

This document describes the protocol between Santa and the sync server, also known as the sync protocol. Implementors should be able to use this to create their own sync servers.

Background

Santa can be run and configured with a sync server. This allows an admin to easily configure and sync rules across a fleet of macOS systems. In addition to distributing rules, using a sync server enables an admin to override some local configuration options e.g. LOCKDOWN mode on both a fleet-wide and per-host basis.

Protocol Overview

The sync protocol is an HTTP/JSON based protocol. As such it is assumed that both the server and client add Content-Type headers are set to application/json.

The sync protocol is client initiated and consists of 4 request-response transactions called stages, preflight, eventupload, ruledownload, and postflight. A sync may consist of all 4 stages, just the eventupload stage or just the ruledownload stage.

Stage What it Does
Preflight Report current Santa settings and machine attributes to sync server & retrieve configuration settings
Event Upload Report new blockable events to the sync server
Rule Download Retrieves new rules
Postflight Reports stats

If the server returns an HTTP status other than 200 for any stage than the sync stops and the next stage is not performed.

At a high level this looks like the following sequence:

sequenceDiagram
   client ->> server: POST /preflight/<machine_id>
   server -->> client: preflight response (200)
   loop until all events are uploaded
   client ->> server: POST /eventupload/<machine_id>
   server -->> client: eventupload response (200)
   end
   loop until all rules are downloaded
   client ->> server: POST /ruledownload/<machine_id>
   server --> client: ruledownload response (200)
   end
   client ->> server: POST /postflight/<machine_id>
   server -->> client: postflight response (200)

Where <machine_id> is a unique string identifier for the client. By default Santa uses the hardware UUID. It may also be set using the MachineID, MachineIDPlist, and MachineIDKey options in the configuration.

Authentication

The protocol expects the client to authenticate the server via SSL/TLS. Additionally, a sync server may support client certificates and use mutual TLS.

Stages

All URLs are of the form /<stage_name>/<machine_id>, e.g. the preflight URL is /preflight/<machine_id>.

Preflight

The preflight stage is used by the client to report host information to the sync server and to retrieve a limited set of configuration settings from the server. These configuration options override the initial values set from the application configuration profile.

This follows the following transaction:

sequenceDiagram
   client ->> server: POST /preflight/<machine_id>
   server -->> client: preflight response

preflight Request

The request consists of the following JSON keys:

Key Required Type Meaning Example Value
serial_num YES string The macOS serial number from IOKit kIOPlatformSerialNumberKey “XXXZ30URLVDQ”
hostname YES string The FQDN hostname of the client markowsky.example.com
os_version YES string The OS version of the client from /System/Library/CoreServices/SystemVersion.plist 12.4
os_build YES string The OS build from /System/Library/CoreServices/SystemVersion.plist “21F5048e”
model_identifier NO string The model of the macOS system  
santa_version YES string 2022.3  
primary_user YES string The username markowsky
binary_rule_count NO int Number of binary allow / deny rules the client has at time of sync 1000
certificate_rule_count NO int Number of certificate allow / deny rules the client has at time of sync 3400
compiler_rule_count NO int Number of compiler rules the client has time of sync  
transitive_rule_count NO int Number of transitive rules the client has at the time of sync  
teamid_rule_count NO int Number of TeamID rules the client has at the time of sync 24
client_mode YES string The mode the client is operating in, either “LOCKDOWN” or “MONITOR” LOCKDOWN
request_clean_sync NO bool The client has requested a clean sync of its rules from the server true

Example preflight request JSON Payload:

{
  "compiler_rule_count" : 14,
  "client_mode" : "MONITOR",
  "santa_version" : "2022.6",
  "serial_num" : "XXXZ30URLVDQ",
  "binary_rule_count" : 43676,
  "hostname" : "markowsky.example.com",
  "primary_user" : "markowsky",
  "certificate_rule_count" : 2364,
  "teamid_rule_count" : 0,
  "os_build" : "21F5048e",
  "transitive_rule_count" : 0,
  "os_version" : "12.4",
  "model_identifier" : "MacBookPro15,1",
  "request_clean_sync": true
}

preflight Response

If all of the data is well formed, the server responds with an HTTP status code of 200 and provides a JSON response.

The JSON object has the following keys:

Key Required Type Meaning Example Value
enable_bundles NO boolean Enable bundle scanning true
enable_transitive_rules NO boolean Whether or not to enable transitive allowlisting true
batch_size YES integer Number of events to upload at a time 128
full_sync_interval YES integer Number of seconds between full syncs 600
client_mode YES string Operating mode to set for the client either “MONITOR” or “LOCKDOWN”
allowed_path_regex NO string Regular expression to allow a binary to execute from a path “/Users/markowsk/foo/.*”
blocked_path_regex NO string Regular expression to block a binary from executing by path “/tmp/”
block_usb_mount NO boolean Block USB mass storage devices true
remount_usb_mode NO string Force USB mass storage devices to be remounted with the following permissions (see configuration)  
clean_sync YES boolean Whether or not the rules should be dropped and synced entirely from the server true
override_file_access_action NO string Override file access config policy action. Must be:
1.) “Disable” to not log or block any rule violations.
2.) “AuditOnly” to only log violations, not block anything.
3.) “” (empty string) or “None” to not override the config
“Disable”, or “AuditOnly”, or “” (empty string)

Example Preflight Response Payload

{
 "batch_size": 100,
 "client_mode": "MONITOR",
 "allowed_path_regex": null,
 "blocked_path_regex": null,
 "clean_sync": false,
 "bundles_enabled": true,
 "enable_transitive_rules": false
}

EventUpload

After the preflight stage has completed the client then initiates the eventupload stage if it has any events to upload. If there aren’t any events this stage is skipped.

It consists of the following transaction, that may be repeated until all events are uploaded.

sequenceDiagram
   client ->> server: POST /eventupload/<machine_id>
   server -->> client: eventupload response

eventupload Request

Key Required Type Meaning Example Value
events YES list of event objects list of events to upload see example payload
Event Objects

:information_source: Events are explained in more depth in the Events page.

Key Required Type Meaning Example Value
file_sha256 YES string SHA256 hash of the executable that was executed “fc6679da622c3ff38933220b8e73c7322ecdc94b4570c50ecab0da311b292682”
file_path YES string Absolute file path to the executable that was blocked “/tmp/foo”
file_name YES string Command portion of the path of the blocked executable “foo”
executing_user NO string Username that executed the binary “markowsky”
execution_time NO float64 Unix timestamp of when the execution occured 23344234232
loggedin_users NO list of strings List of usernames logged in according to utmp [“markowsky”]
current_sessions NO list of strings List of user sessions [“markowsky@console”, “markowsky@ttys000”]
decision YES string The decision Santa made for this binary, BUNDLE_BINARY is used to preemptively report binaries in a bundle. Must be one of the examples “ALLOW_BINARY”, “ALLOW_CERTIFICATE”, “ALLOW_SCOPE”, “ALLOW_TEAMID”, “ALLOW_UNKNOWN”, “BLOCK_BINARY”, “BLOCK_CERTIFICATE”, “BLOCK_SCOPE”, “BLOCK_TEAMID”, “BLOCK_UNKNOWN”, “BUNDLE_BINARY”
file_bundle_id NO string The executable’s containing bundle’s identifier as specified in the Info.plist “com.apple.safari”
file_bundle_path NO string The path that the bundle resids in /Applications/Santa.app
file_bundle_executable_rel_path NO string The relative path of the binary within the Bundle “Contents/MacOS/AppName”
file_bundle_name NO string The bundle’s display name “Google Chrome”
file_bundle_version NO string The bundle version string “9999.1.1”
file_bundle_version_string NO string Bundle short version string “2.3.4”
file_bundle_hash NO string SHA256 hash of all executables in the bundle “7466e3687f540bcb7792c6d14d5a186667dbe18a85021857b42effe9f0370805”
file_bundle_hash_millis NO float64 The time in milliseconds it took to find all of the binaries, hash and produce the bundle_hash 1234775
file_bundle_binary_count NO integer The number of binaries in a bundle 13
pid NO int Process id of the executable that was blocked 1234
ppid NO int Parent process id of the executable that was blocked 456
parent_name NO Parent process short command name of the executable that was blocked “bar”  
quarantine_data_url NO string The actual URL of the quarantined item from the quarantine database that this binary was downloaded from https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg
quarantine_referer_url NO string Referring URL that lead to the binary being downloaded if known https://www.google.com/chrome/downloads/
quarantine_timestamp NO float64 Unix Timestamp of when the binary was downloaded or 0 if not quarantined 0
quarantine_agent_bundle_id NO string The bundle ID of the software that quarantined the binary “com.apple.Safari”
signing_chain NO list of signing chain objects Certs used to code sign the executable See next section
signing_id NO string Signing ID of the binary that was executed “EQHXZ8M8AV:com.google.Chrome”
team_id NO string Team ID of the binary that was executed “EQHXZ8M8AV”
Signing Chain Objects
Key Required Type Meaning Example Value
sha256 YES string SHA256 thumbprint of the certificate used to sign “7ae80b9ab38af0c63a9a81765f434d9a7cd8f720eb6037ef303de39d779bc258”
cn YES string Common Name field of the certificate used to sign “Apple Worldwide Developer Relations Certification Authority”
org YES string Org field of the certificate used to sign “Google LLC”
ou YES string OU field of the certificate used to sign “G3”
valid_from YES int Unix timestamp of when the cert was issued 1647447514
valid_until YES int Unix timestamp of when the cert expires 1678983513
eventupload Request Example Payload
{
  "events": [{
    "file_path": "\/Applications\/Santa.app\/Contents\/MacOS",
    "file_bundle_version": "9999.1.1",
    "parent_name": "launchd",
    "logged_in_users": [
      "markowsky"
    ],
    "quarantine_timestamp": 0,
    "signing_chain": [{
        "cn": "Apple Development: Google Development (EQHXZ8M8AV)",
        "valid_until": 1678983513,
        "org": "Google LLC",
        "valid_from": 1647447514,
        "ou": "EQHXZ8M8AV",
        "sha256": "7ae80b9ab38af0c63a9a81765f434d9a7cd8f720eb6037ef303de39d779bc258"
      },
      {
        "cn": "Apple Worldwide Developer Relations Certification Authority",
        "valid_until": 1897776000,
        "org": "Apple Inc.",
        "valid_from": 1582136027,
        "ou": "G3",
        "sha256": "dcf21878c77f4198e4b4614f03d696d89c66c66008d4244e1b99161aac91601f"
      },
      {
        "cn": "Apple Root CA",
        "valid_until": 2054670036,
        "org": "Apple Inc.",
        "valid_from": 1146001236,
        "ou": "Apple Certification Authority",
        "sha256": "b0b1730ecbc7ff4505142c49f1295e6eda6bcaed7e2c68c5be91b5a11001f024"
      }
    ],
    "file_bundle_name": "santasyncservice",
    "executing_user": "root",
    "ppid": 1,
    "file_bundle_path": "/Applications/Santa.app",
    "file_name": "santasyncservice",
    "execution_time": 1657764366.475035,
    "file_sha256": "8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85",
    "decision": "ALLOW_BINARY",
    "file_bundle_id": "com.google.santa.syncservice",
    "file_bundle_version_string": "9999.1.1",
    "pid": 2595,
    "current_sessions": [
      "markowsky@console",
      "markowsky@ttys000",
      "markowsky@ttys001",
      "markowsky@ttys003"
    ],
    "team_id": "EQHXZ8M8AV",
    "signing_id": "EQHXZ8M8AV:com.google.santa"
  }]
}

eventupload Response

The server should reply with an HTTP 200 if the request was successfully received and processed.

Key Required Type Meaning Example Value
event_upload_bundle_binaries NO list of strings An array of bundle hashes that the sync server needs to be uploaded [“8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85”]
eventupload Response Example Payload
{
   "event_upload_bundle_binaries": ["8621d92262aef379d3cfe9e099f287be5b996a281995b5cc64932f7d62f3dc85"]
}

Rule Download

After events have been uploaded to the sync server, the ruledownload stage begins in a full sync.

Like the previous stages this is a simple HTTP request response cycle like so:

sequenceDiagram
   client ->> server: POST /ruledownload/<machine_id>
   server -->> client: ruledownload response

If either the client or server requested a clean sync in the preflight stage, the client is expected to purge its existing rules and download new rules from the sync server.

If a clean sync was not requested by either the client or the sync service, then the sync service should only send new rules seen since the last time the client synced.

Santa applies rules idempotently and is designed to receive rules multiple times without issue.

ruledownload Request

This stage is initiated via an HTTP POST request to the URL /ruledownload/<machine_id>

Key Required Type Meaning
cursor NO string a field used by the sync server to indicate where the next batch of rules should start
ruledownload Request Example Payload

On the first request the payload is an empty dictionary

{}

In the ruledownload response a special field called cursor will exist if there are more rules to download from server. The value and form of this field is left to the sync server implementor. It is expected to be used to track where the next batch of rules should start.

On subsequent requests to the server the cursor field is sent with the value from the previous response e.g.

{"cursor":"CpgBChcKCnVwZGF0ZWRfZHQSCQjh94a58uLlAhJ5ahVzfmdvb2dsZS5jb206YXBwbm90aHJyYAsSCUJsb2NrYWJsZSJAMTczOThkYWQzZDAxZGRmYzllMmEwYjBiMWQxYzQyMjY1OWM2ZjA3YmU1MmY3ZjQ1OTVmNDNlZjRhZWI5MGI4YQwLEgRSdWxlGICA8MvA0tIJDBgAIAA="}

ruledownload Response

When a ruledownload request is received, the sync server responds with a JSON object containing a list of rule objects and a cursor so the client can resume downloading if the rules need to be downloaded in multiple batches.

Key Required Type Meaning
cursor NO string Used to continue a rule download in a future request
rules YES list of Rule objects List of rule objects (see next section).
Rules Objects
Key Required Type Meaning Example Value
identifier YES string The attribute of the binary the rule should match on e.g. the team ID of a binary or sha256 hash value “ff2a7daa4c25cbd5b057e4471c6a22aba7d154dadfb5cce139c37cf795f41c9c”
policy YES string Identifies the action to perform in response to the rule matching (must be one of the examples) “ALLOWLIST”,”ALLOWLIST_COMPILER”, “BLOCKLIST”, “REMOVE”, “SILENT_BLOCKLIST”
rule_type YES string Identifies the type of rule (must be one of the examples) “BINARY”, “CERTIFICATE”, “SIGNINGID”, “TEAMID”
custom_msg NO string A custom message to display when the rule matches “Hello”
custom_url NO string A custom URL to use for the open button when the rule matches http://lmgtfy.app/?q=dont+download+malware
creation_time NO float64 Time the rule was created 1573543803.349378
file_bundle_binary_count NO integer The number of binaries in a bundle 13
file_bundle_hash NO string The SHA256 of all binaries in a bundle “7466e3687f540bcb7792c6d14d5a186667dbe18a85021857b42effe9f0370805”
Example ruledownload Response Payload
{
  "rules": [{
    "identifier": "ff2a7daa4c25cbd5b057e4471c6a22aba7d154dadfb5cce139c37cf795f41c9c",
    "rule_type": "CERTIFICATE",
    "policy": "BLOCKLIST",
    "custom_msg": "",
    "creation_time": 1573543803.349378
  }, {
    "identifier": "233e741538e1cdf4835b3f2662e372cf0c2694b7e20b4e4663559c7fb0a9f234",
    "rule_type": "BINARY",
    "policy": "ALLOWLIST",
    "custom_msg": "",
    "creation_time": 1573572118.380034
  },
  {
    "identifier": "EQHXZ8M8AV",
    "rule_type": "TEAMID",
    "policy": "ALLOWLIST",
    "custom_msg": "Allow Software Google's Team ID",
    "creation_time": 1576623399.151607
  }],
  "cursor": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXzfmdvb2dsZS5jb206YXBwbm90aHJyYAsSCUJsb2NrYWJsZSJANGYyYTA2MjY1ZjRiODQ2M2Y2YjI0MmNiZTMwMTNkMGZhNjlkNDUxNmI4OTU3Y2I3ZDAxZDcyMTJkM2NhZmZiNAwLEgRSdWxlGICA8Kehk9MKDBgAIAA="
}

Postflight

The postflight stage is used for the client to inform the sync server that it has successfully finished syncing. After sending the request, the client is expected to update its internal state applying any configuration changes sent by the sync server during the preflight step.

This stage uses an HTTP POST request to the url /postflight/<machine_id>

sequenceDiagram
   client ->> server: POST /postflight/<machine_id>
   server -->> client: postflight response

postflight Request

The request consists of the following JSON keys:

Key Required Type Meaning Example Value
rules_received YES int The number of rules the client received from all ruledownlaod requests. 211
rules_processed YES int The number of rules that were processed from all ruledownload requests. 212

Example postflight request JSON Payload:

{
  "rules_received" : 211,
  "rules_processed" : 212
}

postflight Response

The server should reply with an HTTP 200 if the request was successfully received and processed. Any message body is ignored by the client.