Custom DEP Packages

I’m sure everyone who didn’t have an MDM a few weeks ago is scrambling to get one set up - I’m not going to go into anything about MDM, since it really isn’t that interesting. They install profiles and packages - all very unexciting. This article will take you through some of the decisions we made when developing our DEP enrollment package. First attempt If you are of the open source management tool persuasion, chances are that like me, you are very happy with what you have already and see MDM merely as a method for delivering those tools. Before we considered MDM, our deployment workflow was essentially: Imagr lays down a base image Imagr installs Google’s Plan B Plan B install Puppet Puppet performs the configuration As part of that configuration, Puppet installs Munki Munki installs the software So on the face of it, it looked pretty simple for us to use our existing Plan B package with InstallApplication via an MDM. DEPNotify DEPNotify is a great tool by Joel Rennich - you can pass in various commands and it will let your users know what is going on. So we would open up DEPNotify and then kick off our Plan B installation. Which could sit there for 10 minutes without letting the user know what was going on other than “something is happening”. Whilst this obviously wasn’t a great experience for our users, it got the job done. First optimization Rather than make our users sit there and twiddle their thumbs whilst their computer sorted it’s life out, stopped and though about what our users needed to do first off. From our perspective, we really wanted the computer encrypyed before they did anything, and we needed them to get going with our SSO solution and change their password, set up 2FA etc. So this boiled down to two basic requirements: Install Chrome - this is where the majority of ‘IT Time’ is spent during onboarding, so there was no need to wait for Munki to finally put it there. Install and configure Crypt - let’s get the disruptive logout out of the way and let the user use their computer undisturbed. ...

December 20, 2017

Enabling Kernel Extensions in High Sierra

In macOS 10.13 High Sierra, Apple is introducing Secure Kernel Extension Loading (or SKEL for short). This takes the changes introduced with SIP (requiring all KEXTs to be signed) one step further to requiring the user to enable them manually. Whilst this is great for home users, this absolutely sucks for those of us who manage macOS in the enterprise (who need things like VPN clients and anti malware tools running). ...

September 11, 2017

Open sourcing Airbnb's Puppet module for Munki

It’s probably no secret that we use Puppet to configure our macOS fleet at Airbnb. And whilst we have given several talks about how we use Puppet on macOS, there was still a lot of hand waving about how we had our modules set up. So, after several months of me saying “I should open source that”, here is our first open source Puppet module: puppet-munki. What does it do? As you may have guessed, it is a Puppet module that installs and configures Munki. More specifically: ...

September 6, 2017

High Sierra and my open source tools

With this week’s release of the first beta of High Sierra, I wanted to quickly update everyone on the current status of the tools I’ve released, and where I see the future going for them. Sal Sal appears to work fine on High Sierra. Some of the external scripts may need updating, but right now I’m not seeing anything that’s broken. I don’t see anything changing in this regard. Crypt Amazingly, the way we interact with FileVault as admins seems to not have changed at all, so Crypt has been reported to work perfectly (I will confirm when I get back to my testing computers that I don’t mind nuking). Apple has had a habit of wiping out the authorization database for basically every update during Sierra’s life, so this isn’t really a surprise. Whether managing the entries with your configuration management tool, or simply reinstalling the package will get things working again. ...

June 7, 2017

MacDevOps YVR

For those of you who are at the fantastic MacDevOps:YVR, why on earth are you reading this? Regardless, here are the slides from my talk “Something something commercial, something something open source” (and thank you for coming and not throwing things at me, you’re all lovely people). I will update this post when the video is available.

June 6, 2017

Using Python in Puppet Facts

There comes a time when writing Facts in Ruby just isn’t going to cut it - when you need to access Objective C frameworks, for example. Whilst Ruby can’t access these, Python is waiting in the wings ready to come to your rescue. There is the concept of External Facts - Facts that are written in whatever the system can run, and with Puppet 3.4 / Facter 2.0.1, they can even be distributed with pluginsync. ...

April 21, 2017

Using Caddy to HTTPS all the things

Caddy is a lightweight web server that amongst it’s features, has integration with LetsEncrypt to automatically request certificates. This means that you now have absolutely no excuse anymore to run your apps over plain old HTTP anymore. Let me be clearer. If you are running web services over HTTP, regardless of whether it touches the internet or not, you are doing it wrong. ...

April 4, 2017

Loading LaunchAgents as root

There are times when you will need to load a LaunchAgent when a script is running as root - when you are running a postinstall script from a package or when you are loading the LaunchAgent via your management tool of choice (Puppet, Munki, Jamf Pro), for example. All of these example are assuming you have a LaunchAgent at /Library/LaunchAgents/com.company.example.plist. Loading a LaunchAgent #!/bin/bash # get console UID consoleuser=`/usr/bin/stat -f "%Su" /dev/console | /usr/bin/xargs /usr/bin/id -u` /bin/launchctl bootstrap gui/$consoleuser /Library/LaunchAgents/com.company.example.plist #!/usr/bin/python from pwd import getpwnam import subprocess import sys from SystemConfiguration import SCDynamicStoreCopyConsoleUser username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0] if username is None: # Exit if there isn't anyone logged in sys.exit() uid = getpwnam(username).pw_uid subprocess.call(['/bin/launchctl', 'bootstrap', 'gui/{}'.format(uid), '/Library/LaunchAgents/com.company.example.plist']) Unloading a LaunchAgent #!/bin/bash # get console UID consoleuser=`/usr/bin/stat -f "%Su" /dev/console | /usr/bin/xargs /usr/bin/id -u` /bin/launchctl bootout gui/$consoleuser /Library/LaunchAgents/com.company.example.plist #!/usr/bin/python from pwd import getpwnam import subprocess import sys from SystemConfiguration import SCDynamicStoreCopyConsoleUser username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0] if username is None: # Exit if there isn't anyone logged in sys.exit() uid = getpwnam(username).pw_uid subprocess.call(['/bin/launchctl', 'bootout', 'gui/{}'.format(uid), '/Library/LaunchAgents/com.company.example.plist']) The Python version may look more complicated, but is slightly more robust as it is retrieving the current username using Apple’s frameworks and I have also allowed for the script not to fail if there isn’t a user logged in.

March 25, 2017

Something something commercial, something something opensource

Thanks to everyone who came to my session at MacAd.UK. I will link the video here when it is available, but in the meantime here are the slides.

February 8, 2017

Pocket Mac admin's guide to London

It’s less than three weeks now until I give my talk about our journey from commercial management tools to open source nirvana at MacADUK - and whilst I’m very excited about the conference and all the fantastic speakers, I know some of you are equally as excited about visiting London. So, here’s my pocket Mac Admin’s guide to London (views are my own etc etc) ...

January 19, 2017