KMFDDM - 一个苹果声明式设备管理(DDM)服务器

334 阅读8分钟

KMFDDM

KMFDDM是一个苹果声明式设备管理(DDM)服务器。它与NanoMDM一起工作。

实验性的

警告:KMFDDM是实验性的。在这个时候,它被认为是一个研发平台,以进一步了解和研究DDM协议和设备操作。代码是不完善的,几乎没有文档。预计API会被删除和改变。期待数据模型、数据库模式或整个管理范式发生巨大的变化。预计将不得不擦除任何配置并重新开始。期待整个项目在任何时候都不能正常运行。

要求

  • 一个工作的NanoMDM v0.3.0+环境
  • 对NanoMDM实例的网络访问。
  • 具有声明式设备管理(DDM)功能的设备:iOS 15.0+, macOS 13.0+ (Ventura), 等等。
  • MySQL 8.0.19以上数据库
  • 包括Python 3和shell脚本工具(技术上是可选的,但有帮助)

开始使用&文档

在进行快速入门指南之前,请阅读此README。它将为KMFDDM的运行和一些假设奠定一些概念性的基础。

概念和术语

声明

如果你不熟悉什么是声明(或DDM),请查看苹果公司2021年WWDC的第一个视频"认识声明式设备管理"。

声明是JSON blobs,包括Identifier,Type, 和Payload 字段。一个额外的字段,ServerToken ,唯一标识一个声明的 "版本",但KMFDDM为你处理这个字段。Identifier 是你喜欢的任何唯一值,而Payload 对象字段的内容是由声明的类型定义的(如在Type 字段中指定)。各种类型和有效载荷由苹果公司记录。这里有一个声明的例子。

{
    "Type": "com.apple.management.organization-info",
    "Payload": {
        "Name": "ACME Widgets Co."
    },
    "Identifier": "c55aad00-126f-4ed4-be8a-df58d5856c97"
}
    

作为一个旁观者,这是用附带的ideclr.py工具生成的:

$ ./tools/ideclr.py org-info 'ACME Widgets Co.'

另外,我不建议在Identifier 字段中使用UUID(为了你自己的理智)--它只是一个默认值。ideclr.py-i 开关来指定你自己的。

代号

声明式设备管理有两个(半)不同的 "令牌"。其中一个是声明ServerToken 字段,它唯一地标识了一个声明的 "版本"。当声明发生变化时,这个字段表示声明在注册的设备上是否已经过时(与服务器提供的相比)。这个字段在KMFDDM中为你管理,每次你添加一个新的或更新现有的声明时都会更新。作为一个实现细节,它是声明中字段值的散列。

另一个标记(或者说是一个半标记)是DeclarationsToken ,它是声明项目和设备标记(或只是标记)的一部分。与声明类似,这个令牌可以识别注册设备的声明集合是否已经过期,以及是否需要从服务器上更新声明。这个令牌(实际上对声明项目和设备令牌来说是一样的)也是为你管理的,作为一个实现细节,它是从包含在注册的声明项目中的每个声明的ServerToken's。

声明项目和设备令牌

根据DDM协议,声明项目(以及密切相关的设备令牌或只是令牌)是特定注册的声明Identifier's 和声明ServerToken's 的集合。根据上述规定,他们也包括他们自己单独的服务器令牌值。在KMFDDM中,声明项目(和设备令牌)是由所有注册的分配集(以及声明)"合成 "的。更多信息见下文。

集合

在KMFDDM中,一个 "集 "是一个命名的声明集合。声明与集合有多对多的关系:也就是说,一个声明可以 "在 "许多不同的集合中,集合可以包含许多不同的声明。集可以被认为是声明的 "逻辑 "集合。另一种思考方式是 "命名 "声明项。集合本身是 "独立的",并不自动与注册或注册ID相关。

报名

套餐可以与NanoDM的注册ID以多对多的关系联系起来:即注册ID可以与许多套装联系起来,套装也可以与许多注册ID联系起来。值得注意的是,声明不能直接与注册ID相关联。声明只能与集合相关联。

合并

由于上述集合和招生的关联,KMFDDM动态地 "合成 "声明集合为一个招生ID的单一声明项目。通过这种方式,我们可以支持灵活地配置声明到招生的映射关系。比如说:

  • 旨在为所有入学的声明(包含在集合中)。
  • 宣告(包含在集合中),旨在为入学的群体,如。
    • 业务单位、部门、团队等。
    • 逻辑或功能分组。例如,用于特定的配置或设置。
  • 只针对单个注册者的声明(包含在集合中)。
    • 值得注意的是,这允许支持每个学员的管理属性。

这些关联也可以反向工作,当一个单一的声明被修改时,KMFDDM知道如何找到所有适用的注册ID,并通过DM命令通知。

在这个例子中,我们可以看到(在其他可能的组合中):

  • enroll_1 将 "合成 "一个包括 和 的声明项目,而没有其他的。decl_1 decl_2
  • enroll_2 将包括 , , 和 ,没有其他。decl_1 decl_2 decl_3
  • enroll_3 将包括 , , 和 ,没有其他的。decl_3 decl_4 decl_5

在修改的情况下。

  • 如果decl_1,decl_2, 或set_1 被修改,那么enroll_1enroll_2 将被通知。
  • 如果decl_3 被修改,那么enroll_2enroll_3 将被通知。
  • 如果set_2 被修改,那么enroll_2 将被通知。
  • 如果set_3 被修改,那么enroll_3 将被通知。
  • 如果decl_4,decl_5,set_3, 或set_4 被修改,那么只有 enroll_3 将被通知。

你将不得不维护哪些集被分配给哪些个人注册ID(当然,哪些个人申报被分配给哪些集)。但是,一旦你这样做了,KMFDDM就会处理剩下的事情。

特点

  • 代币管理:
    • 申报、申报项目和设备令牌中的版本/更改 "令牌 "都为你管理。
    • 代币是为你创建、更新和生成的。你只需更新你的 "任务 "和你的声明,其余的由KMFDDM来处理。
  • 自动通知:
    • 当关联或声明内容发生变化时,设备会被自动通知(即发送DeclarationManagement MDM命令)。
    • 这包括过渡性地通知那些依赖关系发生变化的设备。
    • 对于单一的注册通知,我们在DeclarativeManagement 命令中直接包括设备令牌。
  • 声明引用跟踪:
    • 我们防止声明引用不存在的声明,保持所有声明的一致性(参考完整性)。
    • 然而,这并没有延伸到集合关联;这取决于你如何保持有效。
  • 状态通道数据 "缓存":
    • 我们存储注册的声明状态和错误,以便以后检索和解构。
    • 我们将所有非声明、非错误的数据存储为 "值",以便以后检索和解压缩。这对于检查一个报名者支持哪些声明或状态订阅是很有用的。
  • 受限制的声明检索:
    • 通过表连接的方式,我们只检索与注册ID相关的声明(过渡性的)。也就是说,注册者不能访问不是为他们准备的声明。这有点像一个ACL。算是吧。
    • 这本身不是一个设计目标,只是一个快乐的意外。

警告和注意事项

  • 报名ID集关联是 "永远的":
    • 一旦你给一个集合分配了一个注册ID,它就永远被分配了,直到你取消分配它。
    • 如果一个设备被取消注册或以其他方式在NanoMDM中变得无人管理,它仍然会收到来自KMFDDM的通知(排队的MDM命令)。
    • 你从KMFDDM "取消注册 "一个设备,通过API将注册ID与任何集合分离。请记住,这不会关闭DDM的注册 - 这只是停止未来的通知。
    • 这也将通知设备,它不再有任何声明需要管理。这与DDM的 "取消注册 "一样好。
  • 你可以琐碎地创建无效的申报集:
    • 对于从集合内的其他声明中引用声明,没有做太多的审查。也就是说,你可以将一个声明添加到一个集合中,而这个集合中引用的是另一个在该集合中的声明。如果另一个集合不包含这个缺失的声明,这将最终成为一个由入学报告的错误。
    • 然而,大多数声明模型问题会在DDM状态报告通道上反馈给你。每个招生单位主动管理的申报项目状态被保存下来,可以被检索和检查。
    • 但还是要注意:注意什么被分配到了哪里。
  • 外壳脚本可能很混乱:
    • 大多数shell脚本工具都需要位置参数,而哪个位置参数是什么并不总是很明显。特别是对于 "关联 "脚本来说。
    • 一般来说,第一个参数是在文件名的第一个实体之后。例如,api-set-declarations-put.sh 是关于集合和声明之间的关联,第一个参数是集合名称,第二个是声明标识符。
  • 过度通知:
    • 由于在SQL中使用了ON DUPLICATE KEY ,我们并不能总是准确地判断出哪些报名者需要被通知。因此,当声明或集合发生变化时,我们可能会过度通知一些(或很多)成员。
    • 然而,这在技术上并不是一个问题,因为DDM协议的 "令牌 "架构不会考虑声明的实际变化。只是需要注意的是,这可能会浪费MDM命令和DDM令牌及往返次数。