Secure Jamf Pro with cnspec
Scan Jamf Pro against security and compliance best practices with cnspec.
Scan your Jamf Pro instance to find security risks across your managed Apple fleet. cnspec evaluates the computer inventory, FileVault and firewall status, OS versions, enrollment state, smart and static computer groups, local user accounts, software packages, SSO configuration, and the Jamf user directory.
Prerequisites
To scan a Jamf Pro instance with cnspec, you must have:
- cnspec installed on your workstation
- A Jamf Pro instance with administrator access to create an API role and client
Give cnspec access using a Jamf Pro API client
To scan your Jamf Pro instance, cnspec needs access through the Jamf Pro API. You create an API role and an API client in Jamf Pro, then provide the credentials when running cnspec commands.
- In Jamf Pro, go to Settings > System > API roles and clients.
- On the API Roles tab, create a role with read-only privileges for the data you want to scan, such as Read Computers, Read Computer Inventory Collection, Read Smart Computer Groups, Read Static Computer Groups, Read Packages, Read User, and Read SSO Settings.
- On the API Clients tab, create a client, assign it the role you created, and enable it.
- Generate a client secret. Carefully record the client ID and client secret, along with your Jamf Pro instance domain (for example,
https://yourdomain.jamfcloud.com).
To test access, open a cnspec shell and verify the connection:
cnspec shell jamf --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET --instance-domain https://yourdomain.jamfcloud.comcnspec> jamf.version
jamf.version: "11.5.1"You can also set environment variables to omit the flags:
export JAMF_CLIENT_ID='YOUR_CLIENT_ID'
export JAMF_CLIENT_SECRET='YOUR_CLIENT_SECRET'
export JAMF_INSTANCE_DOMAIN='https://yourdomain.jamfcloud.com'
cnspec shell jamfScan Jamf
To scan your Jamf Pro instance:
cnspec scan jamf --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET --instance-domain https://yourdomain.jamfcloud.comUnderstand scan output
When a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy. Each check shows a pass or fail result. For example:
✓ Pass: Ensure FileVault is enabled on all computers
✕ Fail: Ensure the firewall is enabled on all computers
✓ Pass: Ensure all computers run a supported macOS versionAt the end of the output, cnspec shows a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues.
Scan with a custom policy
cnspec ships with built-in checks, and you can write your own policies to evaluate Jamf against your specific security and compliance requirements. Pass a policy bundle directly to cnspec:
cnspec scan jamf --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET --instance-domain https://yourdomain.jamfcloud.com \
--policy-bundle ./my-jamf-policy.mql.yamlExplore your Jamf environment
Run cnspec shell jamf --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET --instance-domain https://yourdomain.jamfcloud.com to open the interactive shell.
Query the computer inventory
cnspec> jamf.computerInventory { name operatingSystemName operatingSystemVersion fileVault2Status }
jamf.computerInventory: [
0: {
name: "Suki's MacBook Pro"
operatingSystemName: "macOS"
operatingSystemVersion: "14.5"
fileVault2Status: "VALID"
}
...
]Audit computer groups
cnspec> jamf.computerGroups { name smartGroup }
jamf.computerGroups: [
0: {
name: "All Managed Clients"
smartGroup: false
}
1: {
name: "macOS Sonoma"
smartGroup: true
}
...
]List Jamf users
cnspec> jamf.users { id name }Example security checks
Ensure FileVault is enabled on all computers
cnspec> jamf.computerInventory.all( fileVault2Status == "VALID" )Ensure the firewall is enabled on all computers
cnspec> jamf.computerInventory.all( firewallEnabled )Find computers that have not contacted Jamf recently
cnspec> jamf.computerInventory.where( lastContactTime < time.now - 30*time.day ) { name lastContactTime }Ensure single sign-on is enabled
cnspec> jamf.ssoSettings.ssoEnabled == trueFind local accounts with admin privileges
cnspec> jamf.computerInventory {
name
localUserAccounts.where( admin ) { username fullName }
}Learn more
-
To learn more about how the MQL query language works, read Write Effective MQL.
-
To learn about all the Jamf resources and properties you can query, read the Mondoo Jamf Resource Pack Reference.