nanocmd

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2024 License: MIT

README

NanoCMD

Go

NanoCMD is a modular Go library and reference server for abstracting Apple MDM commands and responses into a concept of workflows.

The NanoCMD project is comprised of three major components:

  • Workflows: domain-specific sequences of Apple MDM "v1" commands and responses.
  • Subsystems: simple reference implementations of domain-specific MDM infrastructure.
  • The Workflow Engine: intermediary and logisitcal coordinator between MDM servers and workflows.

These are discussed more below.

NanoCMD tries to be modular, componentized, and somewhat unopinionated. While it ships with a reference server that can be used itself in a turn-key fashion the project can also be imported as a library to build your own workflows, implement custom subsystems or adapters, etc.

Getting started & Documentation

  • Quickstart
    A guide to getting NanoCMD up and running quickly.

  • Operations Guide
    A brief overview of operating the NanoCMD server including command line and API interfaces.

Getting the latest version

  • Release .zip files containing the server should be attached to every GitHub release.
    • Release zips are also published for every main branch commit.
  • A Docker container is built and published to the GHCR.io registry for every release.
    • docker pull ghcr.io/micromdm/nanocmd:latestdocker run ghcr.io/micromdm/nanocmd:latest
    • A Docker container is also published for every main branch commit (and tagged with :main)
  • If you have a Go toolchain installed you can checkout the source and simply run make.

What NanoCMD is not

NanoCMD is neat. But there are some things it does not do. There are also some things that are out of scope that it may never do. Here's some of the things NanoCMD is not:

  • Not a complete MDM server solution. As we like to say: it is not a product. 😉
  • Not an exhaustive inventory of all MDM commands, workflows, or subsystems. This project is primarily focused on the engine and workflow interface.
  • We expect that Declarative Management will lessen the need for NanoCMD over time. See the note below about DDM.
  • Not a "fleet management" tool or "orchestrator" (at least not yet). The NanoCMD server is currently ad-hoc/API and event driven. It does not have a concept of a "fleet" or automatically managing workflows across a group of machines. At least not yet.
    • You can trivally script this capability with your own list of devices with e.g. curl but it is not built-in.
    • We may never get this ability and instead focus on Declarative Management.
  • Not all encompasing (i.e. an MDM server product). NanoCMD is limited in scope. Before submitting a PR for a major feature please drop the maintainers a message to discuss first.

Overview

Why does one need all this complexity related to MDM commands? In short: because some (sets of) MDM commands require it. Take a look at this blog post from Kandji about MDM software updates. Notice the description of the "flow" of these MDM commands and diagram of the back-and-forth of the commands. This is just the reality of some MDM command worklfows.

NanoCMD tries to provide a mechanism with its workflow APIs to accomplish this sort of back-and-forth for MDM commands. Here's a sequence diagram to (hopefully) better illustrate. It outlines the general flow into and out of the workflow engine and workflows for a given workflow start:

sequenceDiagram
    autonumber
    actor Start as Start (API/Event)
    box NanoCMD
    participant Engine
    participant Workflow
    end
    actor Enrollment as Enrollment/Device
    Start->>Engine: Start workflow for n ID(s)
    Engine->>+Workflow: Start workflow for n ID(s)
    loop Next Step or Polling
        Workflow->>-Engine: Send Step (n Command(s))
        Engine->>+Enrollment: MDM command(s) from Step
        Enrollment->>-Engine: MDM response(s) for Step
        Engine->>+Workflow: Step Complete
        Workflow-->>-Engine: (Optional) Send next Step (n Command(s))
        break Timeout
            Engine-->>Workflow: Step Timeout
        end
    end

Not shown in this diagram is that the output of most workflows talk to the subsystems to store/persist data. This diagram is mostly illustrating the workflow sequence between the workflow, engine, and enrollment (device).

Workflows

Workflows adhere to the set of interfaces that the workflow engine provides for coordinating MDM commands and responses. A workflow is the specific implementation using those interfaces.

The intent with workflows is to take away somea lot of the drudgery of dealing with sending and receiving MDM commands and processing responses. By doing this we can give more focus to the higher-level goals of what those MDM commands and responses are supposed to accomplish. To that end the workflows are provided with a number of features by the workflow engine. For example as a workflow many things are taken care of for you automatically:

  • Command responses are "routed" back to you after you send them
  • Command responses are unmarshalled into the correct and specific MDM structured response type
  • Multiple grouped commands (called steps) are recevied all at once when they complete. You don't need to track ordering or complete status.
  • Straight-forward coordination of sequences of MDM commands — especially those that need to take different action depending on the outcome of previous commands.
  • "Future" command (step) scheduling. This effectively allows for ad-hoc context-aware temporary command polling
  • Consistent context interface that can be passed between steps. Storage/persistence of this context is also transparently handled by the engine for you.
  • In addition to workflow steps you can optionally get notified of any arbitrary command type that was sent by the engine — by any workflow.
  • Optionally get notified and take action on MDM events (such as enrollment or check-out)

As well, the engine works to make sure workflows don't have to worry about things like:

  • NotNow responses: the engine keeps track of actual command completion and only hands over completed commands.
  • Re-sending push notifications for outstanding steps (MDM commands)
  • "Exclusivity" tracking: the engine, by default, prevents multiple workflows from running at a time for an enrollment. This prevents "stacking" of steps/commands being queued for a device that hasn't yet dealt with its previous set of commands.
  • Steps timeouts: Workflow steps can configure a Timeout that the engine manages. The workflow will get notified when that timeout elapses without command responses.
  • Marshaling and unmarshaling proper commands: the engine knows which command responses came from what type of command Request Types, so it'll properly hand over the correct already-unmarshalled command responses for you to work with.

The workflow interface is relatively simple with much of the heavy lifting and logistics being taken care of by the engine. This frees the workflow developer to concentrate on accomplishing useful things with the MDM commands rather than worry about the above logistics.

The operations guide discusses the specific workflows included in NanoCMD.

Subsystems

Subsystems are "reference" implementations of MDM "infrastructure." The included subsystems are domain-specific, limited in scope, and generally simple. For example one subsystem is for Configuration Profiles. The subsystem provides the capability for working with its data (e.g. via the API). But the real usefulness comes from workflows that need to use this functionality. E.g. some workflows depend on having access to read profiles. The profile subsystem facilitates that capability.

Note that "subsystem" is just the name of NanoCMD's built-in MDM/domain-specific infrastructure. While they do have a shared similar design they need not be treated as design advice. If NanoCMD is imported into your project and/or you use it as a library then workflows can interface with whatever infrastructure they need in whatever way makes sense for them.

The operations guide discusses the specific subsystems included in NanoCMD.

Engine

The workflow engine is what coordinates MDM commands and responses with the workflows interface. It communicates with MDM servers, including sending MDM commands and receiving responses and events, and coordinates most of the underlying data so that the workflows don't have to.

As just one (important) example it keeps track of the Request Type of an MDM command that is enqueued to an MDM server and associates this with the command UUID. In this way when we receive the response command UUID we can lookup the Request Type of the original command and instantiate the correct response type. This all happens before responses are delivered to the workflow so a workflow doesn't need to worry about that bookkeeping. It can just deal with the responses to the commands it sent.

What about Declarative Device Management?

It would seem this is an odd project to release this late in the MDM game. So why invest in this? While we fully realize MDM "v1" commands and responses will likely be deprecated in favor of Declarative Management counterparts, there's a few reasons to continue with this:

There's a few reasons:

  • Older devices/OSes still need to support MDM v1.
  • Some MDM operations may continue to be (or stay) MDM v1-only.
  • Bugs or delays in Declarative Management features.
  • At the time it was written the workflows that were required were not avaialble as Declarative Management functionality yet.

Directories

Path Synopsis
cmd
nanocmd
Package main starts a NanoCMD server.
Package main starts a NanoCMD server.
Package engine implements the NanoCMD workflow engine.
Package engine implements the NanoCMD workflow engine.
http
Package http contains HTTP handlers that work with the NanoCMD engine.
Package http contains HTTP handlers that work with the NanoCMD engine.
storage
Package storage defines types and primitives for workflow engine storage backends.
Package storage defines types and primitives for workflow engine storage backends.
storage/diskv
Package diskv implements an engine storage backend using the diskv key-value store.
Package diskv implements an engine storage backend using the diskv key-value store.
storage/inmem
Package inmem implements an engine storage backend using the a map-based key-value store.
Package inmem implements an engine storage backend using the a map-based key-value store.
storage/kv
Package kv implements a workflow engine storage backend using a key-value interface.
Package kv implements a workflow engine storage backend using a key-value interface.
Package http includes handlers and utilties.
Package http includes handlers and utilties.
api
log
ctxlog
Package ctxlog allows logging data stored with a context.
Package ctxlog allows logging data stored with a context.
logkeys
Package logkeys defines some static logging keys for consistent structured logging output.
Package logkeys defines some static logging keys for consistent structured logging output.
mdm
Package mdm defines types for the core MDM protocol.
Package mdm defines types for the core MDM protocol.
foss
Package foss implements communication with with Free/Open Source MDM servers.
Package foss implements communication with with Free/Open Source MDM servers.
subsystem
cmdplan/http
Package http contains HTTP handlers for working with Command Plans.
Package http contains HTTP handlers for working with Command Plans.
cmdplan/storage
Package storage defines types supporting Command Plans.
Package storage defines types supporting Command Plans.
cmdplan/storage/diskv
Package inmem implements a command plan storage backend backed by an on-disk key-valye store.
Package inmem implements a command plan storage backend backed by an on-disk key-valye store.
cmdplan/storage/inmem
Package inmem implements a command plan storage backend backed by an in-memory key-valye store.
Package inmem implements a command plan storage backend backed by an in-memory key-valye store.
cmdplan/storage/kv
Package kv implements a cmdplan storage backend using JSON with key-value storage.
Package kv implements a cmdplan storage backend using JSON with key-value storage.
filevault/http
Package http provides HTTP handlers related to the FileVault enable workflow.
Package http provides HTTP handlers related to the FileVault enable workflow.
filevault/storage
Package storage defines types supporting FileVault FDE commands and responses.
Package storage defines types supporting FileVault FDE commands and responses.
filevault/storage/diskv
Package diskv implements a diskv-backed FileVault storage backend.
Package diskv implements a diskv-backed FileVault storage backend.
filevault/storage/inmem
Package diskv implements an in-memory FileVault storage backend.
Package diskv implements an in-memory FileVault storage backend.
filevault/storage/invprk
Package invprk implements retrieving and storing PRKs in inventory storage.
Package invprk implements retrieving and storing PRKs in inventory storage.
filevault/storage/kv
Package kv implements a key-value FileVault storage.
Package kv implements a key-value FileVault storage.
inventory/http
Package http contains HTTP handlers for working with the inventory subsytem.
Package http contains HTTP handlers for working with the inventory subsytem.
inventory/storage
Package storage defines types and interfaces to support the inventory subsystem.
Package storage defines types and interfaces to support the inventory subsystem.
inventory/storage/diskv
Package diskv implements a diskv-backed inventory subsystem storage backend.
Package diskv implements a diskv-backed inventory subsystem storage backend.
inventory/storage/inmem
Package inmem implements an in-memory inventory subsystem storage backend.
Package inmem implements an in-memory inventory subsystem storage backend.
profile/http
Package http provides HTTP handlers for the Profile subsystem.
Package http provides HTTP handlers for the Profile subsystem.
profile/storage
Package storage defines types and methods for a profile storage backend.
Package storage defines types and methods for a profile storage backend.
profile/storage/diskv
Package inmem implements a storage backend for the Profile subsystem backed by diskv.
Package inmem implements a storage backend for the Profile subsystem backed by diskv.
profile/storage/inmem
Package inmem implements an in-memory storage backend for the Profile subsystem.
Package inmem implements an in-memory storage backend for the Profile subsystem.
utils
kv
Package kv defines an interface for key-value store.
Package kv defines an interface for key-value store.
kv/kvdiskv
Package kvdiskv wraps diskv to a standard interface for a key-value store.
Package kvdiskv wraps diskv to a standard interface for a key-value store.
kv/kvmap
Package kvmap implements an in-memory key-value store backed by a Go map.
Package kvmap implements an in-memory key-value store backed by a Go map.
mobileconfig
Package mobileconfig parses Apple Configuration profiles for basic information.
Package mobileconfig parses Apple Configuration profiles for basic information.
uuid
Package uuid provides UUID generation and test utilities.
Package uuid provides UUID generation and test utilities.
Package workflow defines workflow interfaces, types, and primitives.
Package workflow defines workflow interfaces, types, and primitives.
cmdplan
Package cmdplan implements a NanoCMD Workflow for sending pre-configured commands to enrollments.
Package cmdplan implements a NanoCMD Workflow for sending pre-configured commands to enrollments.
fvenable
Package fvenable implements a NanoCMD Workflow for enabling FileVault on a Mac.
Package fvenable implements a NanoCMD Workflow for enabling FileVault on a Mac.
fvrotate
Package fvrotate implements a NanoCMD Workflow for FileVault key rotation.
Package fvrotate implements a NanoCMD Workflow for FileVault key rotation.
inventory
Package inventory implements a NanoCMD Workflow that updates an inventory system.
Package inventory implements a NanoCMD Workflow that updates an inventory system.
lock
Pacakge lock implements a DeviceLock PIN escrow workflow.
Pacakge lock implements a DeviceLock PIN escrow workflow.
profile
Package profile implements a NanoCMD Workflow for "statefully" installing and removing profiles.
Package profile implements a NanoCMD Workflow for "statefully" installing and removing profiles.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL