diff --git a/website/LICENSE b/website/LICENSE new file mode 100644 index 00000000..e4891e3b --- /dev/null +++ b/website/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Victor Vrantchan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/website/Makefile b/website/Makefile new file mode 100644 index 00000000..bf2ef25e --- /dev/null +++ b/website/Makefile @@ -0,0 +1,2 @@ +serve: + hugo serve diff --git a/website/README.md b/website/README.md new file mode 100644 index 00000000..93cc83c1 --- /dev/null +++ b/website/README.md @@ -0,0 +1,19 @@ +This is the repository for https://micromdm.io + +The website is built with [hugo](https://gohugo.io/). You're welcome to add to it. + +# Adding a new blog post + +1. Install [hugo](https://gohugo.io/) +2. Fork this repo and create a new branch (`git checkout -b my_post`) +3. Create a new blog post: `hugo new blog/my-post-title.md` +4. Open content/blog/my-post-title.md in your text editor and write an awesome blog post. You can use Markdown syntax for formatting. +5. Use `hugo serve` or `make serve` to view and edit this repo. Your local copy of the website will be visible at `http://localhost:1313` +6. Commit your changes (`git commit -m 'added my-post-title'`) and `git push` your branch. +7. Open a Pull Request. + + +# Making changes to the site + +The templates for the site are all located in the `themes/micromdm` folder. You can view your changes instantly by running +`hugo serve` or `make serve` and opening `http://localhost:1313` in your browser. diff --git a/website/archetypes/blog.md b/website/archetypes/blog.md new file mode 100644 index 00000000..24a617a1 --- /dev/null +++ b/website/archetypes/blog.md @@ -0,0 +1,7 @@ ++++ +title = "an awesome blog post" +date = "2015-08-24T13:04:37+02:00" +tags = ["mdm"] +author = "" +frontpage = true ++++ diff --git a/website/config.toml b/website/config.toml new file mode 100644 index 00000000..6cb36641 --- /dev/null +++ b/website/config.toml @@ -0,0 +1,5 @@ +languageCode = "en-us" +title = "MicroMDM" +baseurl = "https://micromdm.io/" +theme = "micromdm" +canonifyUrls = false diff --git a/website/content/blog/accounts.md b/website/content/blog/accounts.md new file mode 100644 index 00000000..77546124 --- /dev/null +++ b/website/content/blog/accounts.md @@ -0,0 +1,61 @@ ++++ +frontpage = true +author = "Victor Vrantchan" +tags = ["mdm", "dep","enterprise", "account", "apple"] +date = "2017-05-06T13:04:37+02:00" +title = "The business side of MDM - Do you know your DUNS Number?" + ++++ + +Getting started with MDM is hard enough, but the toughest part is not technical, it's getting approval to create all the accounts with Apple in order to begin. I recently went through the whole process for my company and thought it would be useful to others if I blogged about it. Below is infromation about what accounts you might need, and how you might go about acquiring them. + + + +# Have your company's trust + +When you sign up on behalf of your organization with Apple, the form will ask wether you're trusted to make such a decision on behalf of your company. The form will also ask for the contact person of your superior to verify. Apple will most surely call you and the contact you've specified during sign up to verify. I was contacted both during DEP approval and when opening an Enterprise Developer account. + +My advice is to coordinate with the person whose name you write down, and make sure they're available that week. It will really help expedite the approval process if both you and your superior are around and able to take phone calls. In both cases, my conversation with Apple only took a few minutes. + + +# Have a DUNS number + +The Developer program as well as DEP and VPP accounts require that you register with a DUNS Number. While many organizations already have one, not everyone does, and it might take a while to register for one. + +Apple publishes a [help document](https://developer.apple.com/support/D-U-N-S/) and [lookup tool](https://developer.apple.com/enroll/duns-lookup/) in case you don't know yours. + +If you're just applying now, keep this timeline in mind: + +> While expediting your D-U-N-S Number creation process may enable you to receive your number sooner, it will still take up to 14 business days for D&B to provide updated information to Apple. You will not be able to use your number to enroll until this step has been completed. + +# Create your Apple IDs + +Apple will require you to create an AppleID for each account you create. If you're creating accounts on behalf of a company, it's important to remember you might not be the only one accessing it, and that one day you might leave and someone else will inherit that account. With that in mind, I went the route of creating a group in Gmail which has several aliases -- one for each administrative Apple ID. + +# Sign up for an Enterprise Developer Account + +An organizational developer account with Apple is important for any Mac Administrator. If you manage macs in your enterprise, you likely create and distribute scripts and internal applications. And when you do that, the software should always be signed. Beyond the ability to sign software, you also gain access to documentation which is not otherwise acccessible. + +If you're looking to either develop an MDM, or manage one yourself (as opposed to signing up with a vendor), you will need an enterpise developer to get access to the MDM vendor certificate. It is called the `MDM CSR` option. Curiously, this certificate option is only available under iOS certificates, not macOS. + +If you already have an enterprise account, but don't see the the `MDM CSR` option, it's because Apple requires special approval. The main administrator of your enterprise account must email Apple to ask for the option to be enabled. + +If you're creating your enterprise account today, Apple will ask you if you're an MDM vendor. Select yes, even if you don't intend to use MDM beyond your own company's needs. During the phone call for approval, Apple inquired about our intended use, and I specified that it was for internal use. They did not object to this use. + +{{
}} + +You can begin your enterprise developer enrollment [here](https://developer.apple.com/programs/enterprise/). This account also comes with a yearly cost of $299. + +# Purchase your devices direct from Apple or through an authorized reseller + +If you'd like to take advantage of the Device Enrollment Program(DEP), you must first buy your devices through an approved channel, like an authorized reseller or direct from Apple. + +https://ecommerce.apple.com + +# Sign up for DEP and VPP + +Just like the developer account, DEP registration requires a DUNS Number and a phonecall from Apple for approval. The AppleID you sign up with must also be new/not associated with other accounts. You'll also be required to enable 2FA for each of these iCloud accounts. + +You can begin the process at [deploy.apple.com](https://deploy.apple.com), unless you're an EDU organization, in which case sign up with Apple School Manager at [school.apple.com](https://school.apple.com/). Apple School Manager is a version of DEP reserved for educational institutions. + + diff --git a/website/content/blog/certificates.md b/website/content/blog/certificates.md new file mode 100644 index 00000000..3e34c7e5 --- /dev/null +++ b/website/content/blog/certificates.md @@ -0,0 +1,154 @@ ++++ +frontpage = true +author = "Jesse Peterson" +tags = ["mdm", "certificate", "apple"] +date = "2017-05-11T13:04:37+02:00" +title = "Understanding MDM Certificates" +lastmod = "2019-12-19T13:03:00+08:00" + ++++ + +Apple Mobile Device Management (MDM) requires the use of various digital certificates for its operation. But exactly which certificates and the various ways in which they are generated, acquired, signed, used, exported, imported, and managed within an MDM product may not be so clear. Generally speaking a commercial MDM product or service manages most of the complexity related to these certificates for you but in the case of an open source MDM much of that responsibility will land on you. In this post I hope to bring a better understanding of these certificates with the aim that you'll be managing at least a few of them yourself. + + + +This post assumes you have at least a basic familiarity of working with certificates, private keys, certificate authorities and the like. To learn more about these and the TLS/SSL protocols have a look at this [TLS & Certificate Survival Guide](http://www.zytrax.com/tech/survival/ssl.html). + +# Apple Push Notification service certificate + +Perhaps the most important certificate is the Apple Push Notification service (APNs) certificate (or just "push certificate"). Without going into too much detail about the how the [MDM protocol works](https://developer.apple.com/business/documentation/MDM-Protocol-Reference.pdf) exactly suffice it to say that the [Apple Push Notification service](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html) (APNs for short) is crucial to how MDM operates. Push notifications are the only way to have a device talk to your MDM after initial enrollment. + +However not just anybody can send these push notifications to Apple (and in turn to your devices). Only services that have acquired a special Apple-signed certificate for sending these push notifications are allowed. While APNs push notifications for MDM are *similar* to "normal" app-based APNs push notifications they are slightly different and are acquired in different vastly ways. + +## Getting an MDM APNs certificate + +There are a few different options for acquiring an MDM push certificate and each has its own pros and cons. + +### Method A: Roll your own using an MDM Vendor Certificate + +An *MDM Vendor Certificate* (or MDM CSR certificate) is a special certificate that can sign *other MDM APNs certificate requests*. These requests can then be submitted to Apple for signing to get the MDM push certificate. This certificate option is only available to members of the [Apple Developer Enterprise Program](https://developer.apple.com/programs/enterprise/) which has a cost of US$300/year. Victor Vrantchan talks about signing up for this account (and this specific certificate option) in [this blog post](/blog/accounts/). + +This method is probably the most complicated option (due to the two-step nature of the certificates) and certainly the most expensive. However a developer account is a good resource for any Mac admin anyway, as Victor mentions, and this is probably the most Apple-supported option for hosting your own MDM as you're not beholden to any other entity or software than Apple for your certificates. This is the same method a commercial MDM vendor uses to generate certificates for their customers (and hence explains the two-step signing process — typically an actual MDM user/admin wouldn't be doing the "Vendor" steps). + +The high-level overview of getting and using an MDM push certificate with a Vendor certificate is similar to this: + +{{
}} + +1. Sign up for an Enterprise account and request the *MDM CSR* certificate on the account (see [this blog post](/blog/accounts/)) +2. Create a private key and an MDM CSR Vendor Certificate in the Apple portal +3. Once you have the MDM CSR Vendor certificate now generate another, separate "customer" or "end-user" certificate request. +4. This "customer" certificate request needs to be wrapped up and signed into a special format by the MDM Vendor certificate. +5. This signed request must then be uploaded to [identity.apple.com](https://identity.apple.com/) where Apple will issue the final actual push certificate that is used in conjunction with the private key for sending APNs MDM push notifications. + +To see a walk-through on this process take a look at [this presentation on MicroMDM](https://www.youtube.com/watch?v=WGKT-PyHz6I&t=26m55s) starting at 26m55s. This process is also covered here in [Pepijn Bruienne's blog post](http://enterprisemac.bruienne.com/2015/06/06/mdm-azing-setting-up-your-own-mdm-server/). As well for actually working with these certificates [micromdm's mdmctl mdmcert tool](https://github.com/micromdm/micromdm/wiki/Generating-MicroMDM-MDM-Certificates) has documentation on getting started once all the Apple account details have been taken care of. + +Once the final "customer" push certificates are created and downloaded from Apple (with e.g. *mdmctl mdmcert* & [identity.apple.com](https://identity.apple.com/)) they can be used directly with MicroMDM. + +### Method B: Export a Profile Manager certificate + +*Profile Manager* is Apple's reference MDM product (or proof-of-concept, depending on how jaded you are about it). It's bundled with [macOS Server.app](https://itunes.apple.com/us/app/macos-server/id883878097?mt=12) for US$20 and requires macOS (or a VM running it). It has a neat feature where with only an Apple ID it can submit a certificate request to Apple, have an MDM certificate signed, and returned back to it in one step. This skips over a bunch of the rigmarole in getting a push certificate. + +This technique was probably first documented in 2011 as a part of [David Shuetz Black Hat 2011 presentation "Inside Apple’s MDM Black Box."](https://www.youtube.com/watch?v=OifARLlRMyU). [Page seven of his PDF](https://media.blackhat.com/bh-us-11/Schuetz/BH_US_11_Schuetz_InsideAppleMDM_WP.pdf) documents exporting the PKCS#12 certificate & key from Keychain Access.app once you've [turned on Profile Manager](https://help.apple.com/serverapp/mac/5.3/#/apd05B9B761-D390-4A75-9251-E9AD29A61D0C). The [MicroMDM Quickstart guide](https://github.com/micromdm/micromdm/wiki/Quickstart#getting-an-mdm-push-certificate) also has some documentation on getting at this certificate. + +If you just want to try out MicroMDM (or another Open Source MDM solution) this is likely the easiest and quickest way to get an APNs push certificate. The downside is that it is an Apple-proprietary method of getting this certificate that's embedded inside Profile Manager. This probably makes it of questionable legality to use with anything other than Profile Manager. As well there is a nominal cost associated. + +Once the Profile Manager certificate is exported as a `.p12` file it can be used directly with MicroMDM. + +### Method C: Sign up for mdmcert.download + +[mdmcert.download](https://mdmcert.download/) is a service created to issue MDM push certificates to organizations wishing to run open-source MDM solutions. The certificates are free of cost but per Apple, only *organizations* (and not individuals) may agree to request a certificate. Apple also requires gathering some information like business name, email addresses, etc. That may not be something you're willing to share or legally able to do for your organization. + +That said it offers a method to get push certificates that's easier than method A, above, but isn't quite as easy as the Server.app method. As mentioned above it's free, too. + +MicroMDM's [mdmctl mdmcert.download option](https://github.com/micromdm/micromdm/wiki/mdmcert.download) can be used to request an mdmcert.download APNs certificate when following the [mdmcert.download instructions](https://mdmcert.download/instructions). Once mdmctl decrypts the encrypted CSR request (which is then subsequently uploaded to [identity.apple.com](https://identity.apple.com/) in order to retrieve the certificate) the push certificates you download can be directly used with MicroMDM. + +## Push certificate gotchas + +Once you have an MDM APNs certificate you have the ability to send push notifications to devices that are enrolled in your MDM. But there are a couple of caveats that you want to keep in mind: + +* MDM APNs certificates **expire yearly.** This of course means you'll need to renew the certificate with a similar process you followed to get the original certificate. Note that it **must be a renewal** and not a *new* APNs push certificate for a very important reason: +* The APNs Push "topic" (which is embedded in the push certificate and has a `com.apple.mgmt.` prefix for MDM) **can never change during the life of a device's enrollment.** Basically, this means a couple things: + * You can't just use *any* MDM APNs certificate; they're not interchangeable. When devices enroll into an MDM they are tied to that particular APNs certificate push topic. + * This is why a *new* certificate can't be used as a renewal — said new certificate would have a different Push topic and would not be able to be used for sending push notifications to your existing enrolled devices. When you renew the certificate on [identity.apple.com](https://identity.apple.com/) it must be submitted as a Renewal to a previously created certificate. This doesn't mean you have to use the same private key (which is bad practice), just that it is submitted as a renewal to Apple. + * If you're using the Server.app extraction method you'll want to keep that instance of Server.app (computer/VM) around so that you can fire it up to get the push certificate with the same topic renewed and exracted again. But hopefully you're only using that method as a test and not necessarily as your production MDM certificate. +* MDM APNs certificates are tied to an Apple ID — the account that is used to issue the APNs Push certificate on [identity.apple.com](https://identity.apple.com/). Because this is the only account that can issue renewals for your existing enrollments you'll want to keep track of its login credentials. Gentle reminder to always use 2FA as well. +* As with any certificate take note of what format the APNs certificate & key are in. Is it two separate PEM-encoded certificate and key files? Is it a single PKCS#12 file encrypted with a password? Knowing these details will be crucial to getting MicroMDM (or any MDM) up and running with them. + +# Device Identity certificate + +An MDM device enrolls into MDM with an identity certificate & key pair. This certificate and private key can either be a) outright *given* to the device or b) the device can request that a new certificate be signed on its behalf. + +The former is done by embedding a PKCS#12 profile payload in the enrollment profile. This will become the device's identity certificate. The latter is done by the device by itself using the SCEP protocol to request a certificate to be signed. Using the SCEP protocol, for all its faults, is much more secure for a few reasons: + +1. The private key is not transferred over the network. Using the 'embedded' method it is. +2. The private key is not in an enrollment profile on disk in a Download folder which may be inadvertantly exported, shared, or lost. If the identity is compromised you can essentially spoof the device connecting to the MDM server. +3. Each device has a unique certificate and private key generated for it to use. + +The primary use of this device identity certificate is to authenticate the device to the MDM server whenever an HTTPS connection is made. Depending on how the MDM software and enrollment profile are configured the device either performs [TLS/SSL client authentication](https://en.wikipedia.org/wiki/Client_certificate) or it provides a [CMS](https://en.wikipedia.org/wiki/Cryptographic_Message_Syntax) detached signature of the MDM request using its identity key pair. In either case, this cryptographically "proves" that the device is using a certificate that *should* be already known to the MDM server and only belonging to that device. + +In the case of SCEP you likely will never have to touch the identity certificate manually. It automatically enrolls and references the correct certificate. Older versions of MicroMDM and e.g. Project-iMAS required manually providing the device identity certificate & key pair in the enrollment profile but that's no longer needed, or recommended. + +It is also possible to use this certificate to encrypt profiles to a device (and only that specific device in the case of unique per-device certificates). More on that later. + +## Device Identity Certificate Authority + +When using SCEP the device will be issued a certificate from a Certificate Authority (CA). While embedded-profile device identity certificates can also be issued from a CA (this is what [Commandment MDM](https://github.com/jessepeterson/commandment) does for example) they're likely just self-signed. Having a CA implies a certificate chain and associated trust concerns they bring. While not something you may be hands-on managing for MDM these are a few questions and concerns you'll want to think about when deploying your MDM: + +* Where are your device identity certificates getting issued from, which CA? +* How do you trust this CA? Who owns/operates it? +* How do you *revoke* certificates for compromised devices or lost certificate & private key pairs? +* How is the MDM trusting the provided device certificate? Is it merely trusting that the *issuer* issued this certificate? Or is it verifying the contents of the device identity certificate itself? + +In MicroMDM the SCEP CA is built-in using the [micromdm/scep](https://github.com/micromdm/scep) project. On each MDM check-in and MDM command it verifies that the certificate was issued by the built-in SCEP CA. Even with the aid of well-designed and straightforward SCEP systems that work with minimal configuration, it is good to understand where device certificates are issued from, how they actually get issued, and how to verify they are trusted. MicroMDM also [validates that the enrolled certificate matches the UDID of the device](https://github.com/micromdm/micromdm/pull/429) so that devices can only access their own command queue. + +# Configuration Profile signing & encrypting certificates + +Apple's [Configuration Profiles](https://developer.apple.com/business/documentation/Configuration-Profile-Reference.pdf) can be CMS signed and/or encrypted. To do that, you must encrypt them with a public key or sign them with a certificate, respectively. + +Encrypting a Configuration Profile requires using a public key that the device has the private key to. This can be known through sending a SCEP profile, a certificate profile payload, or just using the device's enrollment identity already on the device once it's enrolled. When the device has the corresponding private key, it can decrypt the encrypted profile and install it. In this way, you can use a device's specific identify certificate to encrypt a profile so that *only the target device* can decrypt them. + +Signing a Configuration Profile is also possible. For profile signing to be effective the profile should be signed by a certificate that the device trusts. This can be a certificate in the device's [trusted root store](https://en.wikipedia.org/wiki/Public_key_certificate#Root_programs) (similar to a browser's trusted root store) or it can be a certificate that the device is separately configured to trust. In the case of MDM we likely already have a few certificates that are necessarily trusted that we can use. For example the HTTPS web certificate of the MDM may either be trusted in the system root store or be configured as a part of the enrollment profile (say, for a self-signed certificate, more on that later). This may be used to sign profiles (or packages). Often folks will simply sign profiles with their Apple Developer certificate because the signer of those certificates exists in the trusted root store of the device and will just work without further changes or trust management. + +Seeing as the trusted certificates on a device may be known to the MDM system (e.g. coming through in the enrollment profile) the possibility exists for the MDM system to sign profiles either on command or in an on-the-fly fashion. MicroMDM now has support profile for [signing a profile](https://github.com/micromdm/micromdm/releases/tag/v1.6.0) but not encrypting.. Pre-encrypted or signed profiles should also work. + +# Configuration Profile trusted certificates + +Configuration Profiles are able to add certificates to the trusted store of certificates of a device by using Configuration Profile payloads for certificates. Not only is this valuable in-and-of-itself for normal system administration tasks but also importantly for MDM these certificates can be embedded in the *enrollment profile* such that those certificates will be trusted by the system when the device is enrolled. + +This has implications for MDM operation *especially* in the case of using [self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate) for the HTTPS server. By default a self-signed certificate on a normal website would simply not be trusted by a device and it's no different for an MDM server. However if we place the MDM server's self-signed HTTPS certificate inside the enrollment profile then the system will trust it and MDM operation can commence after enrollment. The same goes for profile signing mentioned above. However, this may not work on iOS devices. + +# HTTPS certificate + +The web server portion of MDM requires HTTPS. This of course implies [TLS/SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security) certificates and the related trust issues they bring. That said an MDM server's use of TLS/SSL certificates isn't all that different from your typical web server's TLS/SSL configuration. + +This means that the types of a certificates you can use are pretty much the same as you can use for a website. These include: + +* A purchased TLS/SSL certificate from a reputable Certificate Authority provider like e.g. [Comodo](https://www.comodo.com/), [GlobalSign](https://www.globalsign.com/en/), [Entrust](https://www.entrust.com/), etc. +* MicroMDM supports [LetsEncrypt](https://letsencrypt.org/) (LE) certificate acquisition for automatic SSL configuration + * Note per usual LE operation this requires public internet inbound TCP port 443 access to your MDM server and properly working public DNS + * MicroMDM's use of Let's Encrypt is currently broken, but there are [workarounds](https://github.com/micromdm/micromdm/wiki/Generating-LetsEncrypt-Certs-with-the-Lego-Client) +* Using a [self-signed](https://en.wikipedia.org/wiki/Self-signed_certificate) (or private CA-signed) certificate + +If self-signed or private CA-signed certificates are used then we must add those certificates to our enrollment profile using the appropriate configuration profile payloads as mentioned above. MicroMDM does this for us. + +MDM is intended for mobile devices and as such there's a reasonable assumption it will be running in a place that is accessible from the public internet. While this is not a technical requirement — an MDM server can run behind a firewall or in a private network as long as APNs push notifications can be sent and received — a lot of the more interesting features of MDM like, say, Remote Wipe lose a lot of their luster without it. + +So by far the easiest TLS/SSL configuration is done with LetsEncrypt. Just make sure your server is publicly accessible on port 443 at a domain name you control. MicroMDM should take care of the rest. That said self-signed & purchased SSL options are supported as well in MicroMDM. + +# DEP token certificate + +Your MDM server talks to Apple's [Device Enrollment Program](https://www.apple.com/business/dep/) API using OAuth tokens. However before you gain access to these tokens you have to complete a [PKI](https://en.wikipedia.org/wiki/Public_key_infrastructure) process where you upload a certificate (which contains a public key) that Apple will use to encrypt the tokens with. Once you've given Apple your public key you can download the encrypted tokens and subsequently decrypt them and start using them to connect to the DEP API (to e.g. fetch & sync devices, configure a DEP profile, etc.). This process is managed via the [Apple Business Manager](https://support.apple.com/guide/apple-business-manager/welcome/web) (ABM) interface once your organization has enrolled in ABM and of course have purchased devices that are registered in your ABM account. If you're a school there is the very similar Apple School Manager (ASM). + +Like with the APNs certificate these DEP tokens (like the VPP tokens) expire yearly and this process must be done again to renew them. + +# DEP anchor certificates + +Remember how we said we could use self-signed HTTPS web certificates? And that we need to embed the trust information for the HTTPS certificate in the enrollment profile? For a manual enrollment (that is where to say where you visit the profile website manually) this is usually not a problem because the *initial* certificate prompt that one will get (like with any self-signed website) can be simply overridden by the admin doing the enrollment. However, what about a DEP MDM enrollment where there is no user doing the enrollment? + +That's what the DEP anchor certificates are for. There's a special property on the DEP profile just for this scenario. Note that DEP profiles should not be confused with Configuration Profiles — DEP profiles are a completely separate JSON structure. This property is called `anchor_certs` in the DEP profile and it allows you to specify trusted certificates to Apple's DEP API. This property will instruct a device at DEP enrollment time to trust the given certificates when connecting to the MDM server over TLS/SSL. + +# Conclusion + +My hope is this overview has been helpful in untangling the various certificates used in the MDM protocol and perhaps sheds some light on some of the nuances and gotchas surrounding them. + +But even so if you've still got questions or are having trouble working with any of these certificates come join us in the MDM-related [MacAdmins Slack channels](/) where we discuss topics like this. diff --git a/website/content/blog/kext-whitelist.md b/website/content/blog/kext-whitelist.md new file mode 100644 index 00000000..4a991224 --- /dev/null +++ b/website/content/blog/kext-whitelist.md @@ -0,0 +1,57 @@ ++++ +author = "Victor Vrantchan" +tags = ["mdm", "kext"] +date = "2017-11-13T13:04:37+02:00" +title = "Surviving the Kextpocalyse, Round 0" +frontpage = true + ++++ + +There's an understandable sense of urgency in the MacAdmin community around MDM and Kernel extensions these days. If you've been [paying attention](http://www.richard-purves.com/2017/11/09/mdm-and-the-kextpocalypse-2/) you know that in order to be able to reliably deploy kernel extensions in an enterprise environment, DEP and MDM are becoming a requirement. Apple is likely not going to stop there, and both MDM and DEP will become a requirement for Mac management over the next year or two. But it all feels extremely rushed, and not every enterprise will be ready. Even Apple is not ready yet -- I recently came back from a vacation abroad, where I noticed I couldn't even log in to the DEP portal, because DEP was not available in the country. + +If there's one thing we sysadmins are good at, it's thinking on our feet under pressure and coming up with _alternative_ solutions to problems in our path. Sure, MicroMDM might be a good solution longterm, but you're not ready to deal with the certificates, and deploy it yet. But you need a solution for your upcoming kext problems as early as today. I have one! + +# The New Kext Rules + +- User will be prompted to approve a kernel extension if the Mac is not enrolled in MDM. +- If there's an MDM, all kext installs are whitelisted. +- You'll be grandfathered in to new rules if the enrollment profile is already there. + +With the above rules in mind, we can start working on an MDM, but short term our only problem is that we need the Mac to be considered enrolled. Turns out, this is actually somewhat trivial. Allow me to explain. + +# MDM Enrollment Rules + +Rolling out a new MDM might be hard, but enrolling into one isn't. When I was [just starting to play with MDM](https://groob.io/posts/mdm-experiments/), there was no public documentation of the spec, yet I was able to have a test device enrolled into an nginx server in just a few minutes. There's only two things you need to enroll into MDM before 10.13.2 rolls out: An HTTP Server that responds with HTTP `200 OK` to any request coming from the MDM. You won't be able to use that to install profiles, or do other things MDMs allow, but you'll be considered enrolled, which is what we're aiming for here. + +# Hackery + +So far we've established that we want enroll our entire Mac fleet into an MDM for the purpose of being grandfathered in to the default Kernel Extension whitelisting rule. Later, when 10.13.2+ ships with new Macs, or when we re-image(is that still a thing???) we'll remove the MDM enrollment and enroll in a proper MDM. +Now we need an enrollment profile. We'll use Profile Manager to create and export it, then a text editor to tweak it, and finally Munki/Puppet/Chef/ARD/Custom Pkg to deploy it to our Mac fleet. + +1) Configure Profile Manger and export the default enrollment profile. + +2) Create a Device Identity Certificate +By default the Profile Manger Enrollment Profile uses SCEP, but we'll get rid of that, and add a .p12 file instead. Export the certificate you created as a P12 file. + +3) Use Apple Configurator to tweak the Enrollment Profile. +- Remove SCEP +- Remove any existing entries from Certificates +- Add your .p12 file as an entry to Certificates + +Now open the enrollment profile in a text editor. There's a few more changes to do there. +- Find ServerURL and CheckinURL keys and change those to a URL that returns 200 OK no matter the request. An `nginx` or `caddy` instance with Let's Encrypt certs will do. `facebook.com` also works, although I don't recommend/endorse that. + +- Find the `IdentityCertificateUUID` key, and make sure that the UUID there is identitical to the `PayloadUUID` for the .p12 payload. if it's not put the `IdentityCertificateUUID` uuid in that field. + +Your Enrollment Profile is now ready. Feel free to deploy it to your fleet of <= 10.13.1 devices and you should be ready to survive the 10.13.2 rollout... for now. + +I added a sample enrollment profile which should work for anyone who wants to try the above steps or double check their own: https://gist.github.com/groob/c54b3907498de18221f5c93d56083a54 + +# Conclusion + +I wrote up the above workflow because I found it amusing that the requirement to be considered "Enrolled" are so light, but Apple is enforcing it everywhere. +Long term, I _do not endorse_, anything I've described above. If you're not yet using an MDM, take a look at setting one up. And set a DEP account as well. The days where you could ignore MDM are long gone, and any enterprise that does not have these services enabled over the next couple months will suffer. + + + + diff --git a/website/content/blog/os_update.md b/website/content/blog/os_update.md new file mode 100644 index 00000000..666d5b6f --- /dev/null +++ b/website/content/blog/os_update.md @@ -0,0 +1,259 @@ ++++ +title = "Updating to Mojave?" +date = "2018-10-16T13:04:37+02:00" +tags = ["mdm", "dep", "os_update"] +author = "Victor Vrantchan" +frontpage = true ++++ + +Earlier this year Apple updated the [MDM Protocol Reference](https://developer.apple.com/enterprise/documentation/MDM-Protocol-Reference.pdf) document to add a previously undocumented key to the `AvailableOSUpdates` command. + +| Key | Content | +| ------------------- | ----------------------------------------------------------------------------- | +| **IsMajorOSUpdate** | Set to true if this is a major OS update (e.g. 10.13.x to 10.14). macOS only. | + +This got a few of us in the `#mdmdev` channel on MacAdmins Slack talking. We've tried scheduling OS Updates in the past, and MicroMDM has had support for all these commands for years. The user experience around them is not as great as it could be (more on this some time) so the feature doesn't get much use. But this update was intriguing. The documentation clearly stated that this would be for a _major_ os upgrade, but every time we ran the command, even on older systems, the only available options were point releases (10.13.5 to 10.13.6 for example). No matter what, the update was not listed. + +Mojave was released, but we still didn't see anything. Someone speculated that Apple might have forgotten to add the necessary update to the catalog, and that's why we weren't seeing it. I ended up filing a bug report in early October asking for clarification on the documentation. Was I doing something wrong? Was the documentation mistaken? +Nothing really worked despite me trying this on 10.12, 10.13 and 10.14 betas. Until today... + +{{
}} + +Today, a new product key was added to the macOS Software Update catalog. + +``` +041-14451 + + ServerMetadataURL + http://swcdn.apple.com/[...]/macOSInstallerNotification_GM.smd + Packages + + + Digest + f11446026976c362a451b89d354c2313af19a1a3 + Size + 1821971 + MetadataURL + https://swdist.apple.com/[...]/macOSInstallerNotification_GM.pkm + URL + http://swcdn.apple.com/[...]/macOSInstallerNotification_GM.pkg + + + PostDate + 2018-10-16T20:05:00Z +``` + +The `.pkg` file includes signed `OSXNotification.bundle` with Info.plist keys like this: +``` +FreeSpaceRequired +12000000000 +HumanReadableName +macOS Mojave +ItemID +1398502828 +ProductBuildVersion +18A391 +``` + +So this is a configuration update which includes information about the Mojave installer, with both the product version and the Mac App Store ItemID. Neat. Normally you don't see the full OS installer when running `softwareupdate`. It's in the App store and you have to download it like you would download an app. This must be a shim Apple is using to enable a MDM only feature. + +A curious side effect of having the notification bundle come from the Software Update catalog, is that it's repsonsible for this notification, which shows up on user machines regardless of whether you have devices enrolled in MDM: + +{{
}} + + +Let's see what happens when we follow the update steps via MDM. +Note, to spare you a lot of XML, I'll be referencing a few shorthand commands for interacting with the MDM. These are some simple wrappers that create cURL requests to the MicroMDM API, and map directly to the documented commands in the spec. You can [find them in the repo](https://github.com/micromdm/micromdm/tree/a230831725f173f779cf7e030a93a71b32e8ab13/tools/api), and combined wth [ngrok](https://github.com/micromdm/micromdm/tree/a230831725f173f779cf7e030a93a71b32e8ab13/tools/ngrok), you can test everything yourself without a production MDM setup. + +1. ScheduleOSUpdateScan -- initiates a software update check. +``` +./tools/api/commands/schedule_os_update_scan $udid true +``` + +2. AvailableOSUpdates -- once the scan is completed, we can see available updates. +``` +./tools/api/commands/available_os_updates $udid +``` + +On a 10.12.6 laptop we see the following: + +``` + + AllowsInstallLater + + AppIdentifiersToClose + + HumanReadableName + macOS Installer Notification + HumanReadableNameLocale + en + IsConfigDataUpdate + + IsCritical + + IsFirmwareUpdate + + MetadataURL + http://swcdn.apple.com/[...]/macOSInstallerNotification_GM.smd + ProductKey + 041-14451 + RestartRequired + + Version + 2.0 + +``` + +Bingo! + +Now we can schedule a OS Update + +3. ScheduleOSUpdate for a product key, InstallASAP is the most aggressive install type. +``` +./tools/api/commands/schedule_os_update $udid 041-14451 InstallASAP +``` + +4. Issue another Scan, followed by AvailableOSUpdates +``` +./tools/api/commands/schedule_os_update_scan $udid true +./tools/api/commands/available_os_updates $udid +``` + +Now we see a new item. + +``` + + DownloadSize + 12000000000 + HumanReadableName + macOS Mojave + HumanReadableNameLocale + en + IsConfigDataUpdate + + IsCritical + + IsFirmwareUpdate + + IsMajorOSUpdate + + ProductKey + _OSX_18A391 + RestartRequired + + Version + 18A391 + +``` + +Very strange ProductKey but I'll take it. + +``` +./tools/api/commands/schedule_os_update $udid _OSX_18A391 InstallASAP +``` + +``` +ErrorChain + + + ErrorCode + 74 + ErrorDomain + MDMClientError + LocalizedDescription + Command requires DEP enrollment: ScheduleOSUpdate <MDMClientError:74> + + +Status +Error +``` + +Did you catch that? User Approved MDM is not enough. We need a [DEP enrollment](https://bugreport.apple.com/web/). No problem... a few seconds later. + +``` +./tools/api/commands/schedule_os_update $udid _OSX_18A391 NotifyOnly +``` + +``` +ErrorChain + + + ErrorCode + 12008 + ErrorDomain + MCMDMErrorDomain + LocalizedDescription + Unsupported InstallAction for this ProductKey + + +``` + +Ah sorry for that detour. I wanted to see if `DownloadOnly` and `NotifyOnly` or `InstallLater` are supported actions. Nope! + +But it's ok: + +``` +./tools/api/commands/schedule_os_update $udid _OSX_18A391 InstallASAP + +UpdateResults + + + InstallAction + InstallASAP + ProductKey + _OSX_18A391 + Status + Installing + + +``` + +Except nothing happens. I can confirm on the Mac there is no network activity. `AvailableOSUpdates` again. We get: + +``` + + DownloadPercentComplete + 0.0 + IsDownloaded + + ProductKey + _OSX_18A391 + Status + Idle + +``` + +I tried this routine about 20 times and nothing was happening. Absolute madness. And then it occured to me. What if this works like iOS and you need to be plugged in. Sure enough. As soon as I plugged the power adapter in, `softwareupdated` began downloading _something_. `12000000000` bytes later I was prompted with a notification: + +> Update Requested +> A new update was requested to be installed by an administrator. + +And a single availabe option `Restart`. I clicked it, but nothing happened. So I checked `AvailableOSUpdates`: + +``` + + DownloadPercentComplete + 1 + IsDownloaded + + ProductKey + _OSX_18A391 + Status + Idle + +``` + +Another `ScheduleOSUPdate _OSX_18A391`. Another notification to Restart. Clicking the button does nothing. I decided to look at logs: + +``` +2018-10-16 21:09:29.624110-0400 0x51e4 Default 0x8000000000002f1f 112 authd: Succeeded authorizing right 'com.apple.ServiceManagement.daemons.modify' by client '/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeinstalld' [596] for authorization created by '/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeinstalld' [596] (12,0) +2018-10-16 21:09:29.624497-0400 0x51f5 Default 0x8000000000002f1f 596 storeinstalld: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallDaemonDelegate: Non-interactive authorization for software install was successful +2018-10-16 21:09:29.624836-0400 0x51f5 Default 0x8000000000002f1f 596 storeinstalld: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallDaemonDelegate: Triggering OS installation via worker connection connection from pid 448 (uid: 0, gid: 0) +2018-10-16 21:09:29.625272-0400 0x4e80 Default 0x8000000000002f1f 719 storeinstallagent: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallController: Initialized with IA path: /Applications/Install macOS Mojave.app +2018-10-16 21:09:29.625356-0400 0x4e80 Default 0x8000000000002f1f 719 storeinstallagent: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallController: Starting configure +2018-10-16 21:09:29.625902-0400 0x4f83 Default 0x8000000000002f1f 719 storeinstallagent: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallController: Setting OSISTarget +2018-10-16 21:09:29.629410-0400 0x4e80 Default 0x0 719 storeinstallagent: (StoreFoundation) [com.apple.commerce.CKLegacy] MajorOSInstallController: helperToolDied +``` + +And then, just as I was about to copy these logs to my other computer, my mac rebooted. This was about 2 minutes after clicking on the Restart button. +I expected to get prompted with a install wizard, similar to going through the `Install macOS Mojave.app` process and having to click next a few times. To my surprise, I got the standard black screen with the Apple logo and a 37 minute progress indicator. 18 minutes after that I was staring at a Mojave login prompt. Hello Dark Mode. diff --git a/website/content/blog/troubleshoot-dep.md b/website/content/blog/troubleshoot-dep.md new file mode 100644 index 00000000..ad0df9fc --- /dev/null +++ b/website/content/blog/troubleshoot-dep.md @@ -0,0 +1,114 @@ ++++ +frontpage = true +author = "Victor Vrantchan" +date = "2017-11-06T13:04:37+02:00" +title = "How to troubleshoot your DEP/MDM Enrollments" +tags = ["mdm", "dep"] + ++++ + +The [Device Enrollment Program](https://www.apple.com/business/dep/)(DEP) allows enterprises to configure their Macs to auto-enroll into a Mobile Device Management(MDM) server of their choice. DEP makes it possible to ensure that a new Mac [becomes managed during the unboxing process](https://blog.kolide.com/macos-on-boarding-at-kolide-fab71345986e), reducing the need for Netboot and complex imaging workflows. Of course, as any workflow that depends on the network, this enrollment process can fail, and it's important for an administrator to know how to troubleshoot it. This article has a few concrete steps that will help a macadmin using any MDM to debug why their enrollment process isn't working. + +# DEP, in brief + +To make the DEP process work, Apple maintains a list of your serial numbers in a server side database. During first boot, the Mac will contact a remote server(`iprofiles.apple.com`) to get an "Activation Record". This record contains the MDM enrollment URL and a few fields that specify Setup Assistant configuration. + +{{
}} + +In the WWDC session where DEP was introduced, Apple called it an _enrollment optimization_, and to this day, it lives to that characterization. If the setup assistant proceeds past the above screen, the DEP process is done, and the MDM is managing the Mac. At the very least, the enrollment profile should be installed. + +Anyone can view what the current activation record for any mac looks like by running `sudo /usr/libexec/mdmclient dep nag`. + +How does the activation record hold the enrollment URL for _your_ MDM? That part is configured by your MDM, by [talking to the API](https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/4-Profile_Management/ProfileManagement.html#//apple_ref/doc/uid/TP40017387-CH7-SW6) server at `mdmenrollment.apple.com`. The record that the MDM configures for your device looks roughly like the JSON structure below, which is almost identical in contents to the record your device receives. + +``` +{ + "profile_name": "(Required) Human readable name.", + "url": "https://mdm.acme.co/mdm/enroll", + "allow_pairing": true, + "is_supervised": false, + "is_mandatory": false, + "await_device_configured": false, + "is_mdm_removable": true, + "anchor_certs": [], + "supervising_host_certs": [], + "skip_setup_items": ["AppleID", "Android", "TOS"], + "devices": ["SERIAL1","SERIAL2"] +} +``` + +As you can see, the Device Enrollment Program is nothing more than a matchmaking API to connect your device to its designated MDM server. I've attempted to summarize the DEP flow in the diagram below. + +{{
}} + +# Troubleshooting Steps + +While developing MicroMDM, we ran the enrollment steps many times, and often needed a way to find out why things weren't happening as we expected them to. Over time a common list of troubleshooting steps emerged. [Owen Pragel](https://twitter.com/opragel) wrote up the most common techniques to debug DEP and MDM on the [micromdm wiki](https://github.com/micromdm/micromdm/wiki/Troubleshooting). + +### Debug Logging + +To enable debug logging for the MDM processes on your Mac, [install this configuration profile](https://gist.github.com/opragel/2b9c518f9a27dce787ed45da832708e2). If you have a VM you're using to test a DEP workflow, it might be a good idea to add this profile to the VM image. + +The `log` utility on macOS 10.12+ allows streaming very detailed logs with the `stream --info --debug` subcommand. +To filter out MDM specific log message, start by adding the following predicates. + +``` +log stream --info --debug --predicate 'subsystem contains "com.apple.ManagedClient.cloudconfigurationd"' +log stream --info --debug --predicate 'processImagePath contains "mdmclient" OR processImagePath contains "storedownloadd" +``` + +As you're watching the log stream, you might want to adjust the predicates to add or remove new conditions. [This blog](https://eclecticlight.co/2016/10/01/using-the-logs-in-sierra-some-practical-tips/) is a good primer on the log command. `man log` has some additional usage examples as well. + +### Build a VM Image + +The way I recommend you test your MDM workflows is by creating a VMWware Fusion VM using [AutoDMG](https://github.com/MagerValp/AutoDMG) and Joseph Chilcote's [vfuse](https://github.com/chilcote/vfuse). If you snapshot the VM before first boot, you'll be able to reset to the snapshot and re-enroll. + + +My `vfuse` template, which sets the serial number to DEP enabled Mac and uses an AutoDMG image: +``` +{ + "fusion_path": "", + "source_dmg": "/Users/groob/Desktop/osx-10.13.1-17B48.apfs.dmg", + "output_dir": "/Users/groob/Desktop", + "output_name": "dep-hs-groob", + "cache": false, + "mem_size": 4096, + "disk_type": 0, + "bridged": false, + "mac_address": "", + "enable3d": false, + "vnc_port": 5901, + "vnc_passwd": "", + "hw_model": "MacBookAir7,2", + "serial_number": "C02T9ZI1CXC4" +} +``` + +Build it with `sudo /usr/local/vfuse/vfuse -t dep-hs-groob.json --snapshot`. + +_Note_ I really want to stress out that you must snapshot your VM before first boot. Otherwise the activation record is cached, and any changes you make to it on the MDM side, will not be reflected in your VM. + +### Reset an enrollment + +Thanks to Owen, we have one more useful [script to share](https://gist.github.com/opragel/12555098f5894267c3aba2a7c023a823) which can be used to trigger your test mac to an un-enrolled state. This is good for testing, although it's becoming clearer that over time VM or APFS snapshots are going to be the recommended way to reset your image. + +If you're still using 10.12 or earlier, you can run these steps instead: + +``` +# Remove indicator that setup assistant has already run +sudo rm /var/db/.AppleSetupDone + +# Clear all configuration profiles off machine (not entirely clean) +sudo rm -rf /var/db/ConfigurationProfiles/ + +# Remove Apple Push Notification service daemon keychain +sudo rm /Library/Keychains/apsd.keychain + +# Reboot the machine. It should bring you back to setup assistant +# where you can re-enroll using DEP. +``` + +# Share your tips + +You can find the above and more on the MicroMDM [wiki](https://github.com/micromdm/micromdm/wiki/Troubleshooting). +If you have a new tip to share, don't hesitate to edit the page and add it. diff --git a/website/content/blog/welcome.md b/website/content/blog/welcome.md new file mode 100644 index 00000000..6f581641 --- /dev/null +++ b/website/content/blog/welcome.md @@ -0,0 +1,23 @@ ++++ +author = "Victor Vrantchan" +tags = ["mdm"] +date = "2015-08-24T13:04:37+02:00" +title = "What's next for MicroMDM" +frontpage = true + ++++ + +I first [wrote](https://groob.io/posts/mdm-experiments/) about experimenting with MDM at the end of 2015. Since then, Apple has made the MDM specification [public](https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/3-MDM_Protocol/MDM_Protocol.html), many administrators are looking to swap imaging devices for a DEP workflow, and even commercial vendors [are taking notice](https://simplemdm.com/2017/03/07/deploy-munki-apple-dep-mdm/) of the [needs](http://blog.eriknicolasgomez.com/2017/03/08/Custom-DEP-Part-1-An-Introduction/) of our community. One thing has become increasingly clear — MDM will play a critical role in the future of managing Apple devices in the enterprise. And with the renewed interest in MDM from the macadmin community, it's only fair to be asked — What is the future of the MicroMDM project? + +# Growing the community + +Last summer I met Jesse Peterson at the Penn State Macadmins conference. Jesse is one of the [pioneers](https://github.com/jessepeterson/commandment) in developing an open source MDM project, and has helped me figure out a lot of the initial hurdles to get MicroMDM up and running. We've had a lot of opportunities to chat about [what features we'd like to see](https://github.com/micromdm/micromdm/issues/110) in an MDM server, and how to make the project easy to get started for new users. + +Jesse and I will be speaking about MDM and DEP at a number of Mac conferences this year, starting with [macdevops::YVR](https://www.macdevops.ca/speakers/) in June. + +If you're interested in the project, follow [@micromdm_io](https://twitter.com/micromdm_io) on Twitter or join the discussion on the [MacAdmins Slack](https://macadmins.herokuapp.com/) in the `#micromdm` channel. + +# Focus on user needs + +Long term, we're looking to make MicroMDM the solution of choice for Apple device management, focusing on usability, extensibility and security. To achieve this goal, MicroMDM development will focus on actual user needs. The immediate focus will be building our integration with [DEP](https://deploy.apple.com) and allowing administrators to provision macOS devices. We're looking at what to build next. If you have a specific need that would help you adopt MicroMDM, consider opening an [issue](https://github.com/micromdm/micromdm/issues/new) or sending an email to [hello@micromdm.io](mailto:hello@micromdm.io). + diff --git a/website/content/blog/wwdc20-v2.md b/website/content/blog/wwdc20-v2.md new file mode 100644 index 00000000..099a74a1 --- /dev/null +++ b/website/content/blog/wwdc20-v2.md @@ -0,0 +1,26 @@ ++++ +title = "Five years behind, Five years ahead" +date = "2020-06-22T00:00:00+05:00" +tags = ["mdm", "wwdc", "v2"] +author = "Victor Vrantchan" +frontpage = true ++++ + +Apple MDM is over 10 years old today. Initially, MDM was a protocol to manage iPhones, but later expanded to the growing range of Apple devices. MicroMDM started about five years ago, when a few of us in the MacAdmin community became curious about what the MDM could do. We were intrigued by the "zero touch" deployment, which was brand new at the time. Lots of things were different. Almost nobody was using MDM and Apple Business Manager for the Mac. There were some vendors (notably JAMF) that had support, but the rest of us, including commercial vendors were making do with our own agents/scripts and imaging. [DeployStudio](https://www.deploystudio.com), [Imagr](https://github.com/imagr) and [Restor](http://github.com/google/restor) were the common tools for setting up a new Mac. The MDM documentation itself was not accessible, except to registered vendors. I [wrote](https://groob.io/posts/mdm-experiments/) a quick post in 2015 about experimenting with MDM. About six months later, the MicroMDM project was officially announced. + +Over the years, MicroMDM attracted some interest from different areas of the industry, which shows the project filling use-cases that aren't otherwise filled by other solutions. +- A few organizations with larger fleets adopted MicroMDM to manage their Mac devices. +- MicroMDM is the backend for multiple commercial startups. These are not necessarily the commercial products you use to manage your devices. Instead, custom workflows in education, healthcare and hospitality are being deferred to dedicated MDM services, and MicroMDM is a part of that story. +- MicroMDM's [SCEP server](https://github.com/micromdm/scep), a project created to support PKI in configuration profiles, became one of the more popular open source SCEP implementations, with many users unrelated to Apple MDM. +- As a lightweight project, un-encumbered by the usual business logic, it's the project of choice for many to validate the Apple protocol and try out new features. Every year after WWDC, MicroMDM is one of the first projects out there to implement any newly announced features. +- The project has over 1k stars on GitHub. More importantly, every release for the last few years has new, external contributors, most of whom are new to both Go and Apple MDM. + +While I'm proud of the achievements highlighted above, and more, I have to also dwell on some things which give me anxiety as a maintainer. +- The project is still difficult to approach. A large motivation for building the project for me was to learn Go programming, and it shows. There's a general lack of documentation for developers, and some choices for writing code that haven't aged well. +- The project [is not recommended](https://github.com/micromdm/micromdm/blob/main/docs/user-guide/introduction.md#not-a-product) for many who'd like to use it. It remains one of the few maintained open source MDM solutions, but it's not what I'd recommend as a low-cost replacement of Profile Manager. I can't tell someone to use MicroMDM without also telling them they'll eventually have to write a bunch of code on their own to make it useful. + +When I reflect on MicroMDM up to now, the aspect I'm most excited by, is the pedagogical one. MicroMDM inspired at least a few people to look at Go as an option. It also made the MDM features more accessible to those who wanted to see exactly how each feature works under the hood. So if I plan on maintaining MicroMDM going forward, and remain happy doing it, that's the area I should be spending more time on. + +Todays is the first day of WWDC 2020. Today is also the day we begin working on the eventual v2 of MicroMDM. With the next version, I want to keep what makes MicroMDM so unique, but also make it a Mac management solution I could recommend to any organization, large or small. I also want to focus on expanding the number of contributors and power users by keeping a development blog, regular office hours and finding new opportunities to teach. + +Let's [see](https://developer.apple.com/wwdc20/) what's new in managing Apple devices this year, then come together to build something new. diff --git a/website/static/certificates/mdm_csr_process.png b/website/static/certificates/mdm_csr_process.png new file mode 100644 index 00000000..88a0891e Binary files /dev/null and b/website/static/certificates/mdm_csr_process.png differ diff --git a/website/static/images/mdm_vendor.png b/website/static/images/mdm_vendor.png new file mode 100644 index 00000000..b36578c6 Binary files /dev/null and b/website/static/images/mdm_vendor.png differ diff --git a/website/static/os_update/os_update.png b/website/static/os_update/os_update.png new file mode 100644 index 00000000..c6188a04 Binary files /dev/null and b/website/static/os_update/os_update.png differ diff --git a/website/static/os_update/os_update_prompt.png b/website/static/os_update/os_update_prompt.png new file mode 100644 index 00000000..3e46a2b3 Binary files /dev/null and b/website/static/os_update/os_update_prompt.png differ diff --git a/website/static/troubleshoot-mdm/dep_enroll.gif b/website/static/troubleshoot-mdm/dep_enroll.gif new file mode 100644 index 00000000..9e24f437 Binary files /dev/null and b/website/static/troubleshoot-mdm/dep_enroll.gif differ diff --git a/website/static/troubleshoot-mdm/dep_process.png b/website/static/troubleshoot-mdm/dep_process.png new file mode 100644 index 00000000..fa8e356f Binary files /dev/null and b/website/static/troubleshoot-mdm/dep_process.png differ diff --git a/website/themes/micromdm/LICENSE.md b/website/themes/micromdm/LICENSE.md new file mode 100644 index 00000000..c097754b --- /dev/null +++ b/website/themes/micromdm/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 Victor Vrantchan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/website/themes/micromdm/archetypes/default.md b/website/themes/micromdm/archetypes/default.md new file mode 100644 index 00000000..ac36e062 --- /dev/null +++ b/website/themes/micromdm/archetypes/default.md @@ -0,0 +1,2 @@ ++++ ++++ diff --git a/website/themes/micromdm/layouts/404.html b/website/themes/micromdm/layouts/404.html new file mode 100644 index 00000000..e69de29b diff --git a/website/themes/micromdm/layouts/_default/list.html b/website/themes/micromdm/layouts/_default/list.html new file mode 100644 index 00000000..1c9c790b --- /dev/null +++ b/website/themes/micromdm/layouts/_default/list.html @@ -0,0 +1,20 @@ + + + {{ partial "head.html" . }} + +
+ {{ partial "navigation.html" . }} +
+ {{ range .Data.Pages }} +
+ {{ .Title }} +
+ +
+
+ {{ end}} +
+
+ {{ partial "footer.html" . }} + + diff --git a/website/themes/micromdm/layouts/_default/single.html b/website/themes/micromdm/layouts/_default/single.html new file mode 100644 index 00000000..8aa7c26a --- /dev/null +++ b/website/themes/micromdm/layouts/_default/single.html @@ -0,0 +1,25 @@ + + + {{ partial "head.html" . }} + +
+ {{ partial "navigation.html" . }} +
+

{{ .Title }}

+ {{ if eq .Type "blog" }} + +
+ +
+ {{ if not (eq .Date .Lastmod) }} + +
+ {{ end }} + Reading Time: {{ .ReadingTime }} minutes + {{ end }} + {{ .Content }} +
+
+ {{ partial "footer.html" . }} + + diff --git a/website/themes/micromdm/layouts/index.html b/website/themes/micromdm/layouts/index.html new file mode 100644 index 00000000..62159ad0 --- /dev/null +++ b/website/themes/micromdm/layouts/index.html @@ -0,0 +1,11 @@ + + + {{ partial "head.html" . }} + +
+ {{ partial "navigation.html" . }} + {{ partial "home.html" . }} +
+ {{ partial "footer.html" . }} + + diff --git a/website/themes/micromdm/layouts/partials/footer.html b/website/themes/micromdm/layouts/partials/footer.html new file mode 100644 index 00000000..a89f3a6a --- /dev/null +++ b/website/themes/micromdm/layouts/partials/footer.html @@ -0,0 +1,31 @@ + + diff --git a/website/themes/micromdm/layouts/partials/head.html b/website/themes/micromdm/layouts/partials/head.html new file mode 100644 index 00000000..a6e0038a --- /dev/null +++ b/website/themes/micromdm/layouts/partials/head.html @@ -0,0 +1,25 @@ + + + {{ .Hugo.Generator }} + + {{ if .IsHome }} + {{ .Site.Title }} + {{ else }} + {{ .Title }} · {{ .Site.Title }} + {{ end }} + + + + + + + + + + + + + + + + diff --git a/website/themes/micromdm/layouts/partials/home.html b/website/themes/micromdm/layouts/partials/home.html new file mode 100644 index 00000000..29c5ee64 --- /dev/null +++ b/website/themes/micromdm/layouts/partials/home.html @@ -0,0 +1,113 @@ +
+

MicroMDM

+

bootstrap your mac deployment

+ +

+ MicroMDM is a project which provides an open source Mobile Device Management + server for Apple devices. Our goal is to create a performant and extensible + device management solution for enterprise and education. +

+ Get Started with MicroMDM +
+ +
+

Documentation

+
    +
  • +
    +

    Get started easily

    + +
    +

    + Read the quickstart tutorial for getting up and running with MicroMDM. The steps in this guide are intended to get you up and running as quickly as possible. +

    + View the Quickstart Guide +
  • +
  • +
    +

    Join the Community

    + +
    +

    + The best place to get help is the #micromdm channel on the MacAdmins Slack team. Join us there by getting an invitation at the link below. +

    + Join Us On Slack +
  • +
  • +
    +

    Contribute to MicroMDM

    + +
    +

    + MicroMDM is open source and the core developers are eager to help you make your first Pull Request. Check out the contributing guide for more details. +

    + Read the Contributing Guide +
  • +
+
+ +
+

What's new with MicroMDM?

+ {{ range first 1 .Data.Pages }} + + {{ end }} +
+ +
+

Do more with MicroMDM

+
    +
  • +
    + +

    Check out the API

    +
    +

    + MicroMDM has a robust set of APIs for scheduling commands, reading device data and managing the server itself. +

    + Explore the API +
  • +
  • +
    + +

    Review the Code

    +
    +

    + MicroMDM is free, open source, and permissively licensed! Read the code, contribute features, and offer feedback. +

    + View the Source Code +
  • +
  • +
    + +

    Contribute your ideas

    +
    +

    + The MicroMDM developers are eager to make a solution that works for everyone. Let us know what you need to use MicroMDM at your organization. +

    + Create a GitHub issue +
  • +
+ +
diff --git a/website/themes/micromdm/layouts/partials/navigation.html b/website/themes/micromdm/layouts/partials/navigation.html new file mode 100644 index 00000000..6b0cc3a0 --- /dev/null +++ b/website/themes/micromdm/layouts/partials/navigation.html @@ -0,0 +1,24 @@ +
+ + +
diff --git a/website/themes/micromdm/static/css/micromdm.css b/website/themes/micromdm/static/css/micromdm.css new file mode 100644 index 00000000..5942858e --- /dev/null +++ b/website/themes/micromdm/static/css/micromdm.css @@ -0,0 +1,485 @@ +@font-face { + font-family: system; + font-style: bold; + font-weight: 700; + src: local(".SFNSText-Bold"), local(".HelveticaNeueDeskInterface-Bold"), local(".LucidaGrandeUI"), local("Ubuntu Bold"), local("Segoe UI Bold"), local("Roboto-Bold"), local("DroidSans"), local("Tahoma"); +} + +@font-face { + font-family: system; + font-weight: 900; + src: local(".SFNSText-Heavy"), local(".HelveticaNeueDeskInterface-Heavy"), local(".LucidaGrandeUI"), local("Ubuntu Heavy"), local("Segoe UI Heavy"), local("Roboto-Heavy"), local("DroidSans"), local("Tahoma"); +} + +@font-face { + font-family: system; + font-weight: 400; + src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), local(".LucidaGrandeUI"), local("Ubuntu Light"), local("Segoe UI Light"), local("Roboto-Light"), local("DroidSans"), local("Tahoma"); +} + +/* Global */ +body { + position: relative; + font-family: "system", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + color: #202532; + margin: 0; +} + +main { + min-height: calc(100vh - 308px); +} + +a { + font-weight: bold; + color: #4a9dff; + text-decoration: none; +} + +p { + max-width: 700px; + font-size: 22px; + line-height: 1.45; + letter-spacing: -0.3px; +} + +section { + min-width: 1280px; +} + +/* Navigation */ +.primary-header { + min-width: 1200px; + margin: 16px auto; + padding: 0 40px; + position: relative; +} + +.primary-nav { + font-size: 16px; + color: #a8b9cd; + position: absolute; + right: 40px; + top: 15px; +} + +.primary-nav__items { + list-style: none; + margin: 0; + padding: 0; +} + +.primary-nav__item { + display: inline-block; + margin-left: 50px; +} + +.primary-nav__item > a { + text-decoration: none; + color: #a8b9cd; + transition: 0.3s all; +} + +.primary-nav__item > a:hover { + text-decoration: none; + color: #4a9dff; +} + +section p { + margin: 0 auto; +} + +/* Blog List */ + +.blog-post-list { + width: 700px; + margin: 100px auto 0 auto; + text-align: center; +} + +.blog-post-list-box { + margin: 40px 0; +} + +.blog-post-list-box > a { + font-size: 28px; +} + +.blog-post-list-box > .post-date { + display: block; + margin-top: 10px; + font-size: 20px; +} + +.post { + width: 700px; + margin: 0 auto; + margin-top: 100px; +} + +.post ol, +.post ul { + font-size: 22px; + line-height: 1.45; +} + +.post img { + max-width: 700px; +} + +/* Hero */ + +.hero { + margin-top: 210px; + position: relative; + padding-bottom: 180px; + z-index: 3; + background: #fff; +} + +.hero__title { + text-align: center; + font-size: 48px; + font-weight: 900; + letter-spacing: -0.9px; + margin-bottom: 0; +} + +.hero__text { + text-align: center; + font-size: 22px; + max-width: 580px; +} + +.hero__subtitle { + text-align: center; + font-size: 24px; + margin-top: 10px; + font-weight: normal; +} + +.hero__logo { + margin: 60px 0; + text-align: center; +} + +.hero__logo-image { + width: 204px; + height: 192px; +} + +.hero__cta { + text-align: center; + font-size: 24px; + display: block; + margin: 65px 0 0 0; +} + +.documentation { + background-color: #f9f9fb; + padding: 80px 0; + position: relative; +} + +.documentation::before { + content: ''; + display: block; + width: 1200px; + height: 94px; + filter: blur(36px); + background: rgba(32, 37, 50, 0.06); + box-shadow: 0 0 66px 0 rgba(32, 37, 50, 0.06); + position: relative; + z-index: 9; + border-radius: 100%; + position: absolute; + top: -40px; + left: 50%; + margin-left: -600px; + z-index: 1; +} + +.documentation__header { + text-align: center; + margin: 0 0 68px; + font-size: 42px; +} + +.documentation__items { + list-style: none; + padding: 48px 20px; + width: 1200px; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 8px 20px 0 rgba(32, 37, 50, 0.14); + margin: 0 auto; + display: flex; +} + +.documentation__item { + margin: 0; + padding: 0; + display: inline-block; + width: 397px; + text-align: center; + vertical-align: top; + position: relative; + flex: 1; +} + +.documentation__item::after { + content: ''; + border-radius: 2px; + background-color: rgba(74, 157, 255, 0.1); + width: 2px; + position: absolute; + top: 0; + right: 0; + bottom: 0; +} + +.documentation__item:last-child:after { + display: none; +} + +.documentation__item-header { + height: 200px; +} + +.documentation__item-image { + height: 140px; +} + +.documentation__item-title { + margin: 0 0 25px; + font-size: 24px; +} + +.documentation__item-description { + font-size: 18px; + line-height: 1.67; + text-align: center; + width: 300px; + margin-bottom: 50px; +} + +.documentation__item-cta { + display: block; + text-align: center; + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +/* Blog Teaser */ +.blog-teaser { + padding: 40px 0 128px; + margin-top: 48px; + z-index: 3; + position: relative; + background: #fff; +} + +.blog-teaser__header { + font-size: 42px; + text-align: center; +} + +.blog-teaser__header::after { + content: ''; + display: block; + margin: 0 auto; + margin-top: 23px; + width: 600px; + height: 2px; + background-color: rgba(74, 157, 255, 0.1); +} + +.blog-post { + width: 640px; + margin: 0 auto; +} + +.blog-post__title { + font-weight: normal; + font-size: 32px; +} + +.blog-post__preview { + font-weight: normal; + font-size: 18px; + line-height: 1.44; +} + +.blog-post__actions { + position: relative; + margin-top: 13px; + font-size: 18px; + letter-spacing: -0.2px; + height: 48px; +} + +.blog-post__additional-actions { + position: absolute; + top: 0; + right: -20px; +} + +.blog-post__read-more-link { + position: absolute; + bottom: 0; + +} + +.blog-post__view-all-link { + display: inline-block; + margin-right: 20px; +} + +.blog-post__view-all-link::after { + content: ''; + display: inline-block; + position: relative; + top: 15px; + left: 10px; + width: 2px; + height: 44px; + background-color: rgba(74, 157, 255, 0.2); +} + +.do-more { + background-color: #f9f9fb; + padding: 80px 0; + position: relative; +} + +.do-more::before { + content: ''; + display: block; + width: 1200px; + height: 94px; + filter: blur(36px); + background: rgba(32, 37, 50, 0.06); + box-shadow: 0 0 66px 0 rgba(32, 37, 50, 0.06); + position: relative; + z-index: 9; + border-radius: 100%; + position: absolute; + top: -40px; + left: 50%; + margin-left: -600px; + z-index: 1; +} + +.do-more__header { + text-align: center; + font-size: 42px; + margin: 0 0 50px; +} + +.do-more__items { + width: 1000px; + margin: 0 auto; + display: flex; + margin: 0 auto; + padding: 0; + list-style: none; +} + +.do-more__item { + flex: 1; + margin: 0; + padding: 0; + position: relative; +} + +.do-more__item:nth-child(2n) { + margin: 0 50px; +} + + +.do-more__item-description { + font-size: 16px; + line-height: 1.88; + margin-bottom: 70px; +} + +.do-more__item-header { + text-align: center; +} + +.do-more__item-cta { + position: absolute; + bottom: 0; + left: 0; + right: 0; + text-align: center; + background: #4a9dff; + color: #fff; + height: 40px; + font-weight: 400; + border-radius: 3px; + line-height: 40px; + font-size: 16px; +} + +/* Footer */ +.primary-footer { + height: 243px; + background: #4a9dff; + color: #fff; + padding-top: 65px; + min-width: 1280px; +} + +.primary-footer__container { + width: 1170px; + margin: 0 auto; + position: relative; +} + +.primary-footer__logo { + position: absolute; + top: 0; +} + +.primary-footer__logo-text { + vertical-align: top; + font-weight: normal; + position: relative; + top: 15px; + left: 7px; +} + + +.primary-footer__navigation { + position: absolute; + right: 0; + top: 0; +} + +.primary-footer__navigation-items { + list-style: none; + display: inline-block; + width: 200px; + margin: 0 0 0 116px; + padding: 0; + vertical-align: top; + font-size: 16px; +} + +.primary-footer__navigation-header { + font-size: 18px; + font-weight: bold; + letter-spacing: 0.8px; +} + + +.primary-footer__navigation-item { + height: 30px; +} + +.primary-footer a { + font-weight: normal; + color: #fff; +} diff --git a/website/themes/micromdm/static/css/normalize.css b/website/themes/micromdm/static/css/normalize.css new file mode 100644 index 00000000..e69de29b diff --git a/website/themes/micromdm/static/images/android-chrome-192x192.png b/website/themes/micromdm/static/images/android-chrome-192x192.png new file mode 100644 index 00000000..d3225c5f Binary files /dev/null and b/website/themes/micromdm/static/images/android-chrome-192x192.png differ diff --git a/website/themes/micromdm/static/images/api.svg b/website/themes/micromdm/static/images/api.svg new file mode 100644 index 00000000..e9043dd2 --- /dev/null +++ b/website/themes/micromdm/static/images/api.svg @@ -0,0 +1,22 @@ + + + + api-160 + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/apple-touch-icon.png b/website/themes/micromdm/static/images/apple-touch-icon.png new file mode 100644 index 00000000..f60f7fd2 Binary files /dev/null and b/website/themes/micromdm/static/images/apple-touch-icon.png differ diff --git a/website/themes/micromdm/static/images/branch.svg b/website/themes/micromdm/static/images/branch.svg new file mode 100644 index 00000000..9ccd7b68 --- /dev/null +++ b/website/themes/micromdm/static/images/branch.svg @@ -0,0 +1,13 @@ + + + + branch-160 + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/browserconfig.xml b/website/themes/micromdm/static/images/browserconfig.xml new file mode 100644 index 00000000..b3930d0f --- /dev/null +++ b/website/themes/micromdm/static/images/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/website/themes/micromdm/static/images/favicon-16x16.png b/website/themes/micromdm/static/images/favicon-16x16.png new file mode 100644 index 00000000..2d7c3ef0 Binary files /dev/null and b/website/themes/micromdm/static/images/favicon-16x16.png differ diff --git a/website/themes/micromdm/static/images/favicon-32x32.png b/website/themes/micromdm/static/images/favicon-32x32.png new file mode 100644 index 00000000..3ac2d4d2 Binary files /dev/null and b/website/themes/micromdm/static/images/favicon-32x32.png differ diff --git a/website/themes/micromdm/static/images/favicon.ico b/website/themes/micromdm/static/images/favicon.ico new file mode 100644 index 00000000..03a66ed2 Binary files /dev/null and b/website/themes/micromdm/static/images/favicon.ico differ diff --git a/website/themes/micromdm/static/images/logo-inverted.svg b/website/themes/micromdm/static/images/logo-inverted.svg new file mode 100644 index 00000000..3651d747 --- /dev/null +++ b/website/themes/micromdm/static/images/logo-inverted.svg @@ -0,0 +1,23 @@ + + + + micromdm-logo-sm-invert + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/logo.png b/website/themes/micromdm/static/images/logo.png new file mode 100644 index 00000000..16a3aef8 Binary files /dev/null and b/website/themes/micromdm/static/images/logo.png differ diff --git a/website/themes/micromdm/static/images/logo.svg b/website/themes/micromdm/static/images/logo.svg new file mode 100644 index 00000000..ea2f8fc6 --- /dev/null +++ b/website/themes/micromdm/static/images/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/website/themes/micromdm/static/images/manifest.json b/website/themes/micromdm/static/images/manifest.json new file mode 100644 index 00000000..74dc5de1 --- /dev/null +++ b/website/themes/micromdm/static/images/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/website/themes/micromdm/static/images/micromdm-docs.svg b/website/themes/micromdm/static/images/micromdm-docs.svg new file mode 100644 index 00000000..150228b5 --- /dev/null +++ b/website/themes/micromdm/static/images/micromdm-docs.svg @@ -0,0 +1,38 @@ + + + + micromdm-docs + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/mstile-150x150.png b/website/themes/micromdm/static/images/mstile-150x150.png new file mode 100644 index 00000000..1851b6d9 Binary files /dev/null and b/website/themes/micromdm/static/images/mstile-150x150.png differ diff --git a/website/themes/micromdm/static/images/octocat.svg b/website/themes/micromdm/static/images/octocat.svg new file mode 100644 index 00000000..80ebb839 --- /dev/null +++ b/website/themes/micromdm/static/images/octocat.svg @@ -0,0 +1,31 @@ + + + + octocat-160 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/safari-pinned-tab.svg b/website/themes/micromdm/static/images/safari-pinned-tab.svg new file mode 100644 index 00000000..9d93d156 --- /dev/null +++ b/website/themes/micromdm/static/images/safari-pinned-tab.svg @@ -0,0 +1,19 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/website/themes/micromdm/static/images/slack-logo.svg b/website/themes/micromdm/static/images/slack-logo.svg new file mode 100644 index 00000000..ffa2327d --- /dev/null +++ b/website/themes/micromdm/static/images/slack-logo.svg @@ -0,0 +1,33 @@ + + + + slack-140 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/static/images/wiki-logo.svg b/website/themes/micromdm/static/images/wiki-logo.svg new file mode 100644 index 00000000..463129b6 --- /dev/null +++ b/website/themes/micromdm/static/images/wiki-logo.svg @@ -0,0 +1,39 @@ + + + + wiki-140 + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/website/themes/micromdm/theme.toml b/website/themes/micromdm/theme.toml new file mode 100644 index 00000000..2486f4ed --- /dev/null +++ b/website/themes/micromdm/theme.toml @@ -0,0 +1,21 @@ +# theme.toml template for a Hugo theme +# See https://github.com/spf13/hugoThemes#themetoml for an example + +name = "MicroMDM" +license = "MIT" +licenselink = "https://github.com/micromdm/website/blob/master/LICENSE.md" +description = "" +homepage = "https://micromdm.io/" +tags = ["", ""] +features = ["", ""] +min_version = 0.18 + +[author] + name = "" + homepage = "" + +# If porting an existing theme +[original] + name = "" + homepage = "" + repo = ""