MDMs

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:

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.

  1. In Jamf Pro, go to Settings > System > API roles and clients.
  2. 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.
  3. On the API Clients tab, create a client, assign it the role you created, and enable it.
  4. 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.com
cnspec> 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 jamf

Scan 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.com

Understand 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 version

At 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.yaml

Explore 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 == true

Find local accounts with admin privileges

cnspec> jamf.computerInventory {
    name
    localUserAccounts.where( admin ) { username fullName }
}

Learn more

On this page