NanoDEP
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.
- A set of tools and utilities for talking to the Apple DEP API services — mostly implemented as shell scripts that communicate to the
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.
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 aprofilestatus: removed
Curious if this is what others are seeing.
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
).Process empty op_type events from FetchDeviceRequest
We've seen responses from
FetchDeviceRequest
where theop_type
is empty and these events are of interest on the first run of a syncer+assigner:It's also documented by Apple here:
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.
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 thesyncer_cursor_at
withassigner_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 themodTime
for the assigner profile: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.
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
or
This PR adds some error validation, and default value checking to resolve this issue
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.
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.
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.
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
follow the quickstart guide for setting up env vars and then just walk through it...
alternatively, the testing suite handles cleaning and testing writes to the database so you could just do