在我们之前的文章中,我们介绍了基础设施即代码的基础知识,以及如何使用 Terraform 管理 Jamf Pro 和 Jamf Protect 配置。如果你还没有阅读这些文章,建议从那里开始,因为它们涵盖了安装、项目结构和状态管理。
这次我们将关注 Jamf Platform API,这些 API 最近已进入公开测试版。这些 API 为新一代 Jamf 微服务提供支持,这些微服务与 Jamf Pro 和 Jamf Protect 并行运行,包括蓝图、合规基准和设备组。我们构建了一个专用的 Terraform provider,让你可以将这些资源作为代码进行管理。
为什么需要为 Jamf 平台微服务提供专用 provider?
Jamf Platform API 是独立于 Jamf Pro Classic 和 Pro API 的 API 表面。它们提供的功能不同于你使用 Jamf Pro provider 管理的资源,并且它们通过区域 API 网关(us.apigw.jamf.com、eu.apigw.jamf.com 或 apac.apigw.jamf.com)使用不同的凭据进行身份验证。
蓝图让你定义一组设备的所需配置状态,并在单个操作中部署它。合规基准让你应用来自 macOS 安全合规项目 (mSCP) 的行业标准安全基线,并监控你的设备群在基线中的表现。设备组为你提供了在平台级别组织和针对设备的方式。这些都是一流的功能,值得拥有自己的 provider,其架构专为它们管理的资源而构建。
如果你一直在通过 Jamf Pro 控制台管理蓝图和基准,你已经知道在租户之间重新创建设置或跟踪一段时间内的变化需要大量的点击操作。有了这个 provider,你的整个配置存在于 Git 中,通过代码审查进行,并在你需要的任何地方一致地应用。
它涵盖什么?
Provider 附带 3 个资源、12 个数据源、3 个列表资源 和 4 个设备操作。以下是主要领域:
合规基准引擎 - 根据 mSCP 基线(包括 CIS 1 级和 2 级、NIST 800-53(低、中、高)和 DISA STIG)创建和管理合规基准。你可以启用或禁用各个规则、自定义组织定义值 (ODV) 并将基准指定到特定的设备组。数据源让你查询可用的基线、规则和现有基准。
蓝图 - 定义设备配置蓝图,涵盖软件更新强制实施、软件更新设置、密码策略、Safari 设置、书签和扩展、磁盘管理、音频附件设置、数学设置、服务后台任务、服务配置文件、旧版有效载荷和自定义 DDM 声明。每个蓝图针对一个或多个设备组,可以作为代码进行部署或取消部署。数据源让你查询现有蓝图和可用的蓝图组件。
设备组 - 为计算机和移动设备创建智能和静态设备组,对智能组使用基于条件的成员资格规则,对静态组使用显式成员列表。这些组由基准和蓝图引用以进行定位。
统一库存 - 用于在平台级别查询单个设备和设备列表的只读数据源。
设备操作 - Terraform 1.14+ 操作用于对托管设备执行擦除、重启、关闭和取消管理操作。
所有资源都支持完整的 CRUD 操作和 terraform import。
入门
如果你跟随了介绍文章,你应该已经安装了 Terraform 并理解了项目结构的基础。这里的步骤类似。
1. 为 Jamf Platform API 创建 API 凭据
前往 Jamf Account,创建一个 API 客户端,并为你想要管理的资源所需的权限进行配置。Jamf 开发者门户上的入门指南介绍了此过程。
2. 配置 provider
将 provider 添加到 Terraform 配置中:
terraform {
required_providers {
jamfplatform = {
source = "Jamf-Concepts/jamfplatform"
version = "~> 0.15.0"
}
}
}
provider "jamfplatform" {
base_url = var.jamfplatform_base_url
client_id = var.jamfplatform_client_id
client_secret = var.jamfplatform_client_secret
tenant_id = var.jamfplatform_tenant_id
}
你也可以使用环境变量来保持 provider 块简洁:
export JAMFPLATFORM_BASE_URL="https://us.apigw.jamf.com"
export JAMFPLATFORM_CLIENT_ID="your-client-id"
export JAMFPLATFORM_CLIENT_SECRET="your-client-secret"
export JAMFPLATFORM_TENANT_ID="your-tenant-id"
和往常一样,确保这些凭据不会出现在你的 Git 存储库中。使用 terraform.tfvars 文件并将其添加到你的 .gitignore。
3. 定义你的资源
让我们逐步介绍一些高影响力的示例。
设备组
在创建基准或蓝图之前,你需要一个设备组来针对它们。以下是一个智能计算机组,针对运行 macOS 26 或更高版本的设备:
resource "jamfplatform_device_group" "macos_26_plus" {
name = "macOS 26+"
group_type = "smart"
device_type = "computer"
criteria = [
{
criteria = "Operating System Version"
operator = "greater than or equal"
value = "26.0"
}
]
}
然后可以在你的基准和蓝图资源中通过 ID 引用此组,以便 Terraform 理解依赖关系图并按正确顺序创建所有内容。
合规基准
合规基准使用内置于合规基准引擎中的 mSCP 基线。首先,使用数据源获取你想要的基线的规则。然后创建一个引用这些规则并针对你的设备组的基准:
data "jamfplatform_cbengine_rules" "cis_lvl1" {
baseline_id = "cis_lvl1"
}
resource "jamfplatform_cbengine_benchmark" "cis_level_1" {
title = "CIS macOS Level 1"
description = "CIS Level 1 benchmark - Managed by Terraform"
source_baseline_id = "cis_lvl1"
sources = [
for s in data.jamfplatform_cbengine_rules.cis_lvl1.sources : {
branch = s.branch
revision = s.revision
}
]
rules = [
for r in data.jamfplatform_cbengine_rules.cis_lvl1.rules : {
id = r.id
enabled = r.enabled
}
]
target_device_group = jamfplatform_device_group.macos_26_plus.id
enforcement_mode = "MONITOR"
}
这在监控模式下创建一个 CIS 1 级基准,范围限定为我们之前定义的智能组。包括基线中的每个规则,你可以选择性地禁用各个规则或设置自定义 ODV 值以匹配你组织的要求。例如,要自定义特定规则:
rules = [
{
id = "system_settings_time_server_configure"
enabled = true
odv_value = "ntp.example.com"
},
{
id = "system_settings_critical_update_install_enforce"
enabled = true
}
]
将 enforcement_mode 设置为 "MONITOR_AND_ENFORCE" 将自动修正不合规的设置。
值得注意的是,合规基准引擎 API 目前不为基准提供 PUT 或 PATCH 方法。这意味着对 Terraform 配置中基准资源的任何更改都将导致销毁后重新创建(强制替换),而不是原地更新。在对已部署且正在设备上主动报告的基准进行更改时,请牢记这一点。
真正的力量在于你可以对已应用的精确规则集和自定义设置进行版本控制、通过 pull request 审查更改,并在多个租户中以零手工操作一致地复制相同的基准。
蓝图
蓝图将多个配置组件组合成一个单一单位,该单位被部署到一个或多个设备组。每个组件类型对应一个声明式设备管理 (DDM) 声明配置域。以下是一个配置软件更新设置、包含延迟和自动安装的蓝图:
resource "jamfplatform_blueprints_blueprint" "software_update_settings" {
name = "Software Update Settings"
description = "Managed by Terraform"
deployed = true
device_groups = [jamfplatform_device_group.macos_26_plus.id]
software_update_settings = {
allow_standard_user_os_updates = true
automatic_download = "AlwaysOn"
automatic_install_os_updates = "AlwaysOn"
automatic_install_security_updates = "AlwaysOn"
deferral_major_period_days = 30
deferral_minor_period_days = 14
deferral_system_period_days = 3
notifications_enabled = true
rapid_security_response_enabled = true
rapid_security_response_rollback_enabled = false
recommended_cadence = "Newest"
}
}
以下是一个强制实施密码策略的蓝图:
resource "jamfplatform_blueprints_blueprint" "passcode_policy" {
name = "Passcode Policy"
description = "Managed by Terraform"
deployed = true
device_groups = [jamfplatform_device_group.macos_26_plus.id]
passcode_policy = {
require_passcode = true
require_alphanumeric_passcode = true
minimum_length = 12
minimum_complex_characters = 1
maximum_failed_attempts = 10
maximum_inactivity_in_minutes = 5
maximum_passcode_age_in_days = 90
passcode_reuse_limit = 5
}
}
每个蓝图通过 device_groups 属性映射到单一设备组集合,该属性采用平台 UUID 集合。将 deployed 设置为 true 告诉 provider 部署蓝图(如果它过期了则重新部署)。将其设置为 false 将取消部署它。
你也可以使用 software_update 组件在特定日期强制实施特定的操作系统版本、使用 legacy_payloads 属性处理传统配置文件有效载荷,或使用 custom_declarations 处理 provider 尚未具有专用组件的任意 DDM 声明。
4. 应用你的配置
你从其他 provider 了解的相同命令在这里适用:
terraform init # 初始化并下载 provider
terraform plan # 审查将创建、更改或销毁的内容
terraform apply # 应用更改(你将被要求确认)
将现有租户纳入管理
如果你已经在租户中配置了蓝图、基准和设备组,你无需从头开始。provider 中的每个资源都支持 terraform import,因此你可以将现有资源纳入 Terraform 管理,而无需重新创建它们。
使用 Terraform query 发现现有资源
如果你运行 Terraform 1.14+,provider 支持列表资源,一项让你直接从 Terraform 查询现有基础设施的功能。这在导入之前发现租户中已存在的内容时很有用。
创建一个查询文件(例如 discover.tfquery.hcl):
list "jamfplatform_blueprints_blueprint" "software_update" {
provider = jamfplatform
include_resource = true
config {
search = "software update"
}
}
list "jamfplatform_cbengine_benchmark" "cis_benchmarks" {
provider = jamfplatform
include_resource = true
config {
search = "CIS"
}
}
list "jamfplatform_device_group" "smart_computer_groups" {
provider = jamfplatform
include_resource = true
config {
filter {
selector = "deviceType"
argument = "COMPUTER"
}
filter {
join_with = "and"
selector = "groupType"
argument = "SMART"
}
}
}
然后运行:
terraform query -generate-config-out=generated.tf
Terraform 将查询你的租户,返回匹配的资源及其 ID,并将资源块和导入块生成到 generated.tf 中。蓝图和基准列表资源支持 search 筛选器,用于针对名称和描述的不区分大小写的子字符串匹配。设备组列表资源支持带 RSQL 选择器的 filter 块,用于 name、description、deviceType 和 groupType,为你提供对返回哪些组的精确控制。
导入资源
获得所需的 ID 后,你可以使用导入块将它们纳入管理。使用 Terraform 1.5+:
import {
to = jamfplatform_blueprints_blueprint.software_update_settings
id = "your-blueprint-uuid"
}
import {
to = jamfplatform_cbengine_benchmark.cis_level_1
id = "your-benchmark-uuid"
}
运行 terraform plan 为导入的资源生成配置,根据需要进行优化,从那一刻起它们将作为代码进行管理。有关批量导入资源的更多信息,请参阅 HashiCorp 的批量导入文档。
与其他 Jamf provider 一起使用
此 provider 旨在与 Jamf 生态系统中的其他 Terraform provider 一起工作。你可以将其与以下内容一起使用:
- Jamf Protect Provider - 用于通过 Jamf Protect GraphQL API 管理 Jamf Protect 中的资源(端点安全计划、威胁防止、遥测等)。
- Deployment Theory Jamf Pro Provider - 用于通过其 Classic 和 Pro API 管理 Jamf Pro 中的资源(策略、脚本、配置文件、组等)。
在这些 provider 之间,你可以从单个 Terraform 项目将整个 Jamf 环境作为代码进行管理。常见的模式是使用 Jamf Pro provider 创建智能组和策略等资源,然后在 Jamf Platform provider 中为基准和蓝图引用生成的平台 ID。
参与其中
该 provider 是开源的,采用 MPL 许可证,并发布在 HashiCorp 和 OpenTofu 注册表上。它基于 HashiCorp 的 Terraform 插件框架(协议 v6)构建,全程包含集成测试。该 provider 使用我们的开源 jamfplatform-go-sdk,你可以将其导入到你自己的 Go 项目中,用于针对 Jamf Platform API 的脚本编写和自动化。
我们欢迎贡献。错误报告、功能请求和 pull request 都是受欢迎的。随着更多功能的添加,provider 将继续与 Jamf Platform API 同步增长。