Jamf Concepts

指南

使用 Terraform 管理 Jamf 配置简介

~3 min read

传统的"Click-Ops"方法处理现代 SaaS 应用和企业服务正在快速成为许多组织的过时方法。关注未来规划和编码化设置的团队已经开始寻求 GitOps 友好的系统管理方法。

这确实是有充分理由的。

基础设施即代码("IaC")和持续集成/持续部署(CI/CD)简介

越来越多的组织倾向于通过代码或配置定义文件实施更改,而不是依赖管理员在控制台中点击操作,这通常被称为 ClickOps。在 CI/CD(或"GitOps")方法中,首先定义所需状态,通常采用 YAML 文件或其他结构化格式,然后将文件提交到 Git 分支。提交拉取请求以启动测试、审查和批准工作流,然后执行一系列合并到分支的操作,其中自动化操作通过 API 在 Jamf Pro 中实施更改。这些技术也可以用于在影响整个舰队的生产环境中发生任何事情之前,将更改转移到测试和用户接受阶段。

将配置定义为代码允许定义良好的代码审查、批准和拉取请求工作流,与专业软件开发的方式相同。这意味着您的环境变得可测试、可重复和可扩展,同时还提供了回滚到以前版本的途径,以防更改导致意外问题。

您可以快速迭代和快速恢复,而无需在用户界面和文档中四处查找以了解故障发生在何处。

我们的团队在丹佛的 JNUC 2025 上讨论了整个方法。在这篇文章中,我们打算进一步深入,希望为您提供清晰的跑道来开始自己的研究。

首先,我们为什么选择 Terraform?

Terraform 是基础设施即代码领域中非常强大的工具——它灵活敏捷,可以被定制以映射到您想与之通信的任何 API。当我们开始研究这整个方法时,我们联系了已经为 Jamf Pro 构建了 Terraform Provider 的 Deployment Theory。我们的团队开始与他们一起工作,了解它的应用,并从那时起对该项目做出了很多贡献。此外,我们甚至为 Apple Business 和 Apple School Manager 构建了我们自己的 provider,以及为 Jamf Platform API 构建了新的 provider。

我们已经记录了这些内容,并将在我们的开发者网站上继续在未来更新:https://developer.jamf.com/jamf-pro/docs/jamf-pro-api-developer-resources#terraform-providers

在我们继续进行之前,请不要在生产实例中测试此内容。Terraform 是一个强大的工具,因此我们建议使用测试实例。如果您没有沙箱或测试实例,可以从 Jamf Account 获取 beta Jamf Pro 实例用于此目的。

现在,让我们开始使用 Terraform 在 Jamf Pro 中构建一些资源。

注意:为了保持简单,我们将使用基本身份验证,但您可以在将来切换到使用 OAuth。

安装 Terraform

为了简洁起见,我们将使用 Homebrew 来安装 Terraform。如果您尚未安装 Homebrew,请按照此处的步骤进行操作。

打开 Terminal 并执行以下步骤:

首先,我们将访问 HashiCorp 官方目录。

brew tap hashicorp/tap

接下来,我们将安装 Terraform。

brew install hashicorp/tap/terraform

最后,我们将验证一切是否正常工作。运行此命令应该显示您安装的 Terraform 版本。如果没有,请重试上述步骤。

terraform -version

当然,HashiCorp 在此处也有他们的安装步骤文档供参考。

安装 Visual Studio Code

您实际上可以使用任何文本编辑器或集成开发环境(IDE)来编写 Terraform。但是,我们发现 Visual Studio Code 对 Terraform 的支持很好,随时可用的语法高亮显示扩展。由于 VS Code 也是免费工具,这使其成为我们推荐用于此测试的理想选择。

您可以在此处下载 VS Code 并在您的系统上完成安装。

安装 VS Code 后,您可以单击左侧的"扩展"选项卡(或在键盘上按 Shift + Command + X)并搜索"HashiCorp Terraform"。继续安装此扩展以获得完整的 Terraform 语法高亮显示。

启动 Terraform 项目

Terraform 项目文件将包含许多特定项目,这些项目是启动和运行并开始构建项目所必需的。大多数相关文件的扩展名为 .tf 或类似 .tfvars 的东西。

有许多组件构成此处的功能,但我们将在稍后的时间覆盖这些。

入门可能感觉有点令人畏惧——有很多东西需要启动和运行。因此,我们想让这变得容易一些。

首先,让我们打开 Terminal 并创建一个文件夹来存储我们的 Terraform 项目。我们将在您的用户级别创建此文件夹以便于访问。

mkdir jamf-terraform

然后,我们将在 Terminal 中将目录更改为新创建的文件夹

cd ~/jamf-terraform

现在,我们将从我们的主 Terraform 模块 repo 中克隆我们的模板分支。

git clone -b template https://github.com/Jamf-Concepts/terraform-jamf-platform

完成此操作后,您将拥有一个完整的功能性 Terraform 项目模板,可以立即用于 Jamf Pro 和 Jamf Security Cloud。

添加变量文件

您不希望在 Github repo 中最后出现的是您的登录凭证或客户端密钥。幸运的是,Terraform 为此提供了一个路径。

打开您选择的文本编辑器并复制以下文本:

jamfpro_auth_method   = "basic" ## oauth2 或 basic
jamfpro_instance_url  = "https://<tenant-name>.jamfcloud.com" 
jamfpro_username      = ""
jamfpro_password      = ""
jamfpro_client_id     = ""
jamfpro_client_secret = ""

## Jamf Protect 账户详情
jamfprotect_url             = "https://<tenant-name>.protect.jamfcloud.com"
jamfprotect_clientid        = ""
jamfprotect_client_password = ""

## (Jamf Pro) 常规设置开关 ##
include_categories = false

您将此文件命名为 terraform.tfvars 并将其保存到新克隆模板 repo 的顶层。

现在,您可以开始填充新创建的 terraform.tfvars 文件中的信息。我已将身份验证方法设置为 basic 以简化您的工作,但请注意您可以在将来更改为 oauth2。所以,现在您只需将您的本地用户名和密码分别输入 jamfpro_usernamejamfpro_password 字段。您也可以输入您的 Jamf Protect 信息——您只需在您的 Protect tenant 中创建一个 API Client。

我们还为此模板 repo 中包含的一个模块包含了一个开关。这实际上是一个简单的布尔变量,让我们声明是否将应用任何特定模块。您可以选择在将来构建的其他模块中使用这种方法,或者简单地删除所有布尔要求并让所有内容每次都运行。

Terraform 状态文件

由于我们尚未在实例中实际提交任何真实资源——现在是讨论 Terraform 中状态文件是什么的完美时机。

每次通过 Terraform 添加、更改或销毁资源时,这些更新都会保存在称为 terraform.tfstate 的文件中,然后备份到称为 terraform.tfstate.backup 的文件中。

这是 Terraform 记住它在您的实例中所做的事情的方式,对于未来的功能至关重要。每次对实例运行 Terraform 时,此状态文件在执行任何操作之前都会被查询。每个状态文件都需要与其自己的实例相关联,因此重要的是将它们分开以保持功能并避免混淆。

运行 Terraform

现在,您处于一个良好的位置——您已安装 Terraform、拥有模板 repo 和在变量文件中定义的凭证。

现在,您已准备好对您的测试或 beta Jamf Pro 实例运行我们的模板模块。为此,您将打开 Terminal 并运行以下命令。

terraform init -upgrade

这将初始化 Terraform 并将任何所需的 provider 升级到最新版本,适用于之前在其机器上使用过此功能的任何人,但如果您完全是这个主题的新手,它也将进行所需 Terraform provider 的初始安装。

terraform fmt -recursive

这将递归格式化本地克隆分支中的任何 Terraform 代码,以确保它们都看起来正确并正常工作。

terraform plan

这将查看您的测试 Jamf Pro 实例、您的 Terraform 状态文件和您的 Terraform 模块代码,以查找要应用或从实例中删除的任何更改或新内容,并返回运行模块时将发生的完整计划或概述。

terraform apply

这将首先运行计划并报告将添加、更改或销毁的内容。然后它会要求您确认此操作。该字段只接受 2 个输入:yes 或 no。

terraform apply -parallelism=1

这将强制正在创建的所有资源轮流进行,一次一个地进行。由于许多 SaaS 应用都有系统来检测潜在攻击,有时这是运行 Terraform 的最佳方式。

terraform destroy -parallelism=1

这将销毁在 Terraform 中引用的状态文件中的任何已创建资源。

任何 plan、apply 或 destroy 命令的后续运行都将查询您的状态文件,评估需要添加、更改或销毁的内容,然后执行适当的操作。

运行此特定模块

当您运行我们包含的模板模块时,它将在您的 Jamf Pro 中创建 7 个类别,分别以 Apollo 11-17 任务命名作为简单测试。

添加这些后,您可以使用上述命令轻松销毁它们。

更大的目标是向您展示 Terraform 的结构,以便您可以开始为您的环境构建相关模块,这引出了本文写的下一部分。

Terraform 的解剖

这里功能的核心是 .tf 文件的层次结构。根级 main.tf 调用子模块 main.tf,它引用 .tfvars 文件和 variables.tf 文件。以下是线程和通信顺序的完整分解:

当您运行 terraform apply 时:

状态文件被查询。

main.tf 被评估以查找所请求的子模块。

variables.tf 被扫描以查找用于应用子模块的相关变量。

terraform.tfvars 被扫描以查找运行每个子模块的所有相关变量。

然后调用并执行子模块 main.tf 文件,为相关的本地子模块变量引用它们自己的本地 variables.tf 文件。

然后创建每个资源并将引用保存到 terraform.tfstate

Terraform 将报告成功或失败以及相关代码和响应消息,供您在排查问题时使用。

需要记住的事项

当您开始构建自己的模块时,您可以复制我们包含的模板模块并将其更改为满足您的需求。

每个子模块必须有自己的 main.tfvariables.tf 文件。

每个子模块需要在根级 main.tf 中表示。

仔细阅读模板 repo 中的模块并查找每个引用点,以便您完全理解每个部分如何协同工作以实现目标。

您可以在您的 terraform.tfvars 文件中使用布尔操作(也称为开关)来调用子模块,或者简单地让它们在每次运行 terraform apply 时始终被调用。

您还可以让模块调用依赖于已填充的变量,甚至可以设置简单的包含或排除语句来根据您自己的条件确定模块何时运行。

Terraform 是一个非常强大的工具,具有许多您可以使用的内置函数。构建特定功能时,某些功能是必需的,有些功能您永远不会使用,但它们都在 https://developer.hashicorp.com/terraform 上有很好的记录

参考资源

Deployment Theory Jamf Pro Provider

Jamf Platform Provider

Jamf Security Provider

Jamf AutoUpdate Provider

Jamf 创建的示例和参考模块