NanoDEP is a set of tools and a Go library powering them for communicating with Apple's Device Enrollment Program (DEP) API servers.

  • By MicroMDM
  • Last update: Dec 7, 2022
  • Comments: 11

NanoDEP

Go Go Reference

NanoDEP is a set of tools and a Go library powering them for communicating with Apple's Device Enrollment Program (DEP) API servers.

Getting started & Documentation

  • Quickstart
    A guide to get NanoDEP up and running quickly.

  • Operations Guide
    A brief overview of the various tools and utilities for working with NanoDEP.

Tools and utilities

NanoDEP contains a few tools and utilities. At a high level:

  • DEP configuration & reverse proxy server. The primary server component, called depserver is used for configuring NanoDEP and talking with Apple's DEP servers. It hosts its own API for configuring MDM server instances used with Apple's servers (called DEP names) and also hosts a transparently authenticating reverse proxy for talking 'directly' to Apple's DEP API endpoints.
  • Device sync & assigner. The depsyncer tool handles the device fetch/sync cursor logic to continually retrieve the assigned devices from one or more Apple DEP MDM server instance(s).
  • Scripts, tools, and helpers.
    • A set of tools and utilities for talking to the Apple DEP API services — mostly implemented as shell scripts that communicate to the depserver.
    • A stand-alone deptokens tool for locally working with certificate generation for DEP token decryption.

See the Operations Guide for more details and usage documentation.

Go library

NanoDEP is also a Go library for accessing the Apple DEP APIs. There are two components to the Go library:

  • The higher-level godep package implements Go methods and structures for talking to the individual DEP API endpoints.
  • The lower-level client package implements primitives, helpers, and middleware for authenticating to the DEP API and managing sessions tokens.

See the Go Reference documentation (or the Go source itself, of course) for details on these packages.

Download

nanodep.zip

Comments(11)

  • 1

    Handle assignment to moved devices

    This came up in our internal testing when using the assigner, but unsure if we're right to make this change. This PR is mostly to gain consensus on what the behavior in ABM actually is when re-assigning devices from one server to another.

    In our environment we aren't assigning newly purchased devices to our dev server. Instead we are moving devices in and out with the hope that the sync/assign would know what to do. The observation is that devices moved to our dev server were coming in with an op_type: modified and a profilestatus: removed

    Curious if this is what others are seeing.

  • 2

    Add MySQL storage and tests

    Hi folks.

    This PR implements a MySQL storage, issue #4. I've added tests that can be run on any future storage (which caught a small bug in the FileStorage).

  • 3

    Process empty op_type events from FetchDeviceRequest

    We've seen responses from FetchDeviceRequest where the op_type is empty and these events are of interest on the first run of a syncer+assigner:

    It's also documented by Apple here:

    op_type: Indicates whether the device was added (assigned to the MDM server), modified, or deleted. Contains one of the following strings: added, modified, or deleted. This field is only applicable with the sync the list of devices command.

  • 4

    Allow setting CN and validity days on certificate generation

    This allow setting a custom CN and validity days on GET /v1/tokenpki/{name}. Such API was always using default values CN=depserver and days=1.

    See https://github.com/micromdm/nanodep/pull/5#discussion_r927016919.

  • 5

    Add cursor modification time to `storage.AllStorage`'s `RetrieveCursor` interface method

    We believe this is needed by syncer+assigner for the following scenario:

    If all device events have been fetched/synced (the cursor in storage is updated), and the operator/administrator updates the assigner profile UUID, then we would like to re-apply the profile to all devices.

    With this change, projects that use nanodep can support the above scenario by comparing the syncer_cursor_at with assigner_profile_uuid_at, and remove/clear the cursor from storage if the latter is newer than the former.

    This is mimicking RetrieveAssignerProfile which also returns the modTime for the assigner profile:

    RetrieveAssignerProfile(ctx context.Context, name string) (profileUUID string, modTime time.Time, err error)
    
  • 6

    MongoDB Support

    See https://github.com/micromdm/nanomdm/pull/57

    We'd like to implement a mongoDB connector that satisfies the AllStorage interface and maintain support for the connector as this project continues.

  • 7

    Fix initial token loading

    Currently token bootstrapping with the file backend is non-functional. This PR resolves that issue

    When performing the token upload operation you'd get one of the two errors

    {
      "error": "retrieving auth tokens: open db/nanomdm-dev.tokens.json: no such file or directory"
    }
    

    or

    {
      "error": "mismatched consumer key"
    }
    

    This PR adds some error validation, and default value checking to resolve this issue

  • 8

    Consider ability to force CK change

    The fix for #1 guarded against uploading tokens with a differing consumer key. However if the CK legitimately changes there may be a need to allow "forcing" replacing the OAuth tokens for a given DEP name.

  • 9

    Consumer key change "force" mode

    3edfc1f79416797871952cd2314b81ea6c688850 introduced a change to try and protect from accidentally overwriting the incorrect DEP tokens by rejecting a mismatched consumer key for #1. However, it had a bug, reported in #10 whereby if no initial token existed, saving a new one would fail. Further, there are legitimate cases where a consumer key can change, so this is a workflow we need to support. To do that we introduce the "force" parameter in this PR that can be specified when saving tokens to bypass the matching consumer key check. See the modified docs for usage. We also fixed the initial loading situation reported in #10.

    Resolves #1. Resolves #7. Resolves #10.

  • 10

    Consider updating default DEP version to 3 from 7

    Latest version of DEP protocol is v7 as noted in Apple docs — example 1. While users of NanoDEP can explicitly set any protocol version they like we set default to 3 here:

    https://github.com/micromdm/nanodep/blob/3b6c00009e0e4fc7198dd7af7053d7076186da71/client/transport.go#L19

    Consider upping the default to the current version 7.

  • 11

    MongoDB Connector

    https://github.com/micromdm/nanodep/issues/12

    Adding MongoDB Support to nanodep

    How to test this PR

    create a local mongodb using the docker-compose file located in this PR storage/mongodb/docker-compose.yml

    export MONGO_ROOT_USER=root
    export MONGO_ROOT_PASSWORD=root
    
    docker-compose -f path/to/compose.yml up -d
    
    make release
    
    ./depserver-darwin-amd64 -api supersecret -storage=mongodb -storage-dsn=mongodb://root:[email protected]:27017
    

    follow the quickstart guide for setting up env vars and then just walk through it...

    ./tools/cfg-get-cert.sh > $DEP_NAME.pem
    
    ./tools/cfg-decrypt-tokens.sh /path/to/depname_Token_2022-10-19T19-48-43Z_smime.p7m
    
    ./tools/cfg-set-assigner.sh 6E19C113DD0D67948306CB70F7FA0338
    

    alternatively, the testing suite handles cleaning and testing writes to the database so you could just do

    export NANODEP_MONGODB_STORAGE_TEST=true
    go test -v ./...