onemorething.co_London · since 2002

Blog · Terraform · Beginner · 20 minutes · 21 October 2026

Your first Jamf Pro resource in Terraform

One smart group, start to finish

Most Jamf estates are configured by clicking. Here is the 20-minute version of managing one with Terraform instead, so every change is reviewed, versioned and repeatable.

  • Create an API client in Jamf Pro with the minimum permissions
  • Write one smart group as code with the Jamf Pro Terraform provider
  • Plan, apply, and see the group appear in the console

If you have never used Terraform, this is the post to start with. By the end you will have one smart computer group in Jamf Pro that exists because a file says it should, and you will have seen the plan → apply loop that every later post builds on. Nothing here touches your existing configuration.

Before you start

You need: a Jamf Pro tenant you are allowed to change (a sandbox or trial tenant is ideal), a Mac with Terraform 1.6 or later installed (brew install terraform), and twenty minutes. We use the community Jamf Pro provider maintained by Deployment Theory; check the provider's documentation for the version you install, as resource arguments change between releases.

1. Create an API client in Jamf Pro

Terraform talks to Jamf Pro through the API, and the API wants an API client, not your admin login. Give it the least it needs.

  1. In Jamf Pro go to Settings → System → API roles and clients.
  2. Under API Roles, create a role called terraform-smart-groups with just two privileges: Create Smart Computer Groups and Read Smart Computer Groups. (Add Update and Delete later when you are ready to manage changes, not before.)
  3. Under API Clients, create a client called terraform, assign the role, enable it, and generate a client secret. Copy the client ID and secret now; the secret is shown once.

Why a separate role: when something goes wrong in Terraform, the blast radius is exactly the privileges you granted. Start small and widen deliberately.

2. Put the credentials somewhere Terraform can read them, not in the code

Never write the secret into a .tf file; it will end up in Git. Use environment variables for now (a vault later).

export JAMFPRO_INSTANCE_FQDN="yourcompany.jamfcloud.com"
export JAMFPRO_AUTH_METHOD="oauth2"
export JAMFPRO_CLIENT_ID="paste-the-client-id"
export JAMFPRO_CLIENT_SECRET="paste-the-secret"

Put those four lines in a file called .env in your project folder, run source .env, and add .env to .gitignore before you do anything else.

3. Write the provider block

Make a folder, and in it a file called main.tf:

terraform {
  required_version = ">= 1.6"
  required_providers {
    jamfpro = {
      source  = "deploymenttheory/jamfpro"
      version = "~> 0.20"
    }
  }
}

# Reads JAMFPRO_* from the environment. Nothing secret goes in this file.
provider "jamfpro" {}

Pin the provider version. The ~> 0.20 means "any 0.20.x", so you get fixes but not surprises. Check the current release on the Terraform Registry and use that.

4. Write the smart group

Add a second file, groups.tf. One group: Macs that have not checked in for more than thirty days. It is a useful group to have and a harmless one to create.

resource "jamfpro_smart_computer_group" "stale_30d" {
  name = "TF · Stale · No check-in 30 days"

  criteria {
    name        = "Last Check-in"
    priority    = 0
    and_or      = "and"
    search_type = "more than x days ago"
    value       = "30"
  }
}

Two habits worth starting on day one. The TF · prefix tells anyone in the console that this group is managed by code, so they should not edit it by hand. And the name says what the group is for, not how it is built.

5. Initialise, plan, apply

terraform init      # downloads the provider
terraform plan      # shows what would change: 1 to add, 0 to change, 0 to destroy
terraform apply     # asks for confirmation, then creates the group

Read the plan before you type yes. This is the whole point: Terraform tells you what it will do, in full, before it does it. In the console, go to Computers → Smart Computer Groups and your group is there.

6. Change it, and see the difference

Edit groups.tf and change "30" to "45". Run terraform plan again. You will see one attribute changing, nothing else. That line, the diff, is what you will put in front of a reviewer in a pull request in the next post. (You will need the Update privilege on the API role for the apply to succeed; add it now, deliberately.)

7. What you now have

  • A Jamf Pro resource whose source of truth is a file, not a memory
  • A terraform.tfstate file in your folder. It maps your code to the real group's ID. Do not commit it; the next post moves it to remote storage
  • The plan → apply habit, which is the same for one smart group and for a whole tenant

The mistake everyone makes once

Creating the group in Terraform, then "just quickly" editing it in the console. The next terraform plan will propose to change it back, and someone will be surprised. The rule is simple: if it has the TF · prefix, the file wins. If you need it different, change the file.

Next

The next post takes an existing smart group, one you made by clicking years ago, and brings it under Terraform with terraform import, without deleting or recreating it. That is the post that makes this useful on a real estate.

Questions about this one, or want it adapted for your estate? letstalk@onemorething.co

The newsletter

New walkthroughs, by email

A short email when a new post goes up: what it covers, how long it takes, and the mistake everyone makes once. At most twice a month. No sales pitch.

Next: All posts →