Building a Mac Installer for Gravitl Netclient- updated

This is a (hopefully) simpler updated version of the original post
To make an installer that will work on a Mac, there’s a LOT of requirements. But to make sure the project succeeds into the future we need to do all of this to make the project useful for ‘normal’ people. This means it has to be easy to install, uninstall, get working and stay working!
You will need-
1. a Mac running recent operating system
5. a ‘Developer ID Application’ signing certificate in Keychain
6. a ‘Developer ID Installer’ certificate in Keychain
7. ‘Packages’ app
8. Git
9. Go v1.18 or higher
1. Download the binaries
1. netclient (pick a version for your chosen platform)
2. wireguard-go
2. Make, re-name and make executable 
On an Intel Mac, netclient-darwin becomes netclient
For wireguard-tools you’ll need to ‘make’ this and rename to wg
You’ll also need to ‘make’ wireguard-go according to the instructions on the website
Example-
git clone https://git.zx2c4.com/wireguard-go
cd wireguard-go
make
then make wireguard-go executable with
chmod +x appname
3. Hardening binaries
Place the executable binary in a folder with a .plist file called ‘binaryname.entitlements’
– this describes the security entitlements that the binary requires to run, and your executable will not work unless hardened
– You only need to harden the main binary
– the ones I made might be completely wrong but they work, I added these ‘features’-
com.apple.developer.networking.multicast

com.apple.developer.networking.manage-thread-network-credentials
and uploaded the files to Github. This means we can add them to a script.
4. Signing binaries
For wg and netclient, do something like-
codesign -s "Developer ID Application: Servicemax (XXXXXXXXX)" --timestamp --options runtime -f --entitlements entitlements.plist --deep YourApp.app
At this point you have 2 signed binaries, they need to be added to an installer. We will use a product called ‘Packages’ to do this
4b. Make a Postinstall Script
I’ve simplified this to only include the necessary bits
This is optional- In this case, we are on a Mac and can name our clients in a repeatable way. This postinstall script will
patch the automatically generated launchd for the correct location of the binary. At some time in the future, it won’t be needed.

#!/bin/sh

export PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

# Patch launchd so it works- this is to cope with the binary location changing from /etc to /usr/local...

sudo sed -i '' 's|/etc/netclient/netclient|/usr/local/bin/netclient|g' /Library/LaunchDaemons/com.gravitl.netclient.plist

# Load new launchd

launchctl load -w /Library/LaunchDaemons/com.gravitl.netclient.plist &>/dev/null

# Need to enable it so it launches at startup?

sudo launchctl enable system/com.gravitl.netclient

echo restarted patched launch daemon
Again, this script has been uploaded to Github and can be used in a build script.
5. Putting it all together
Here is a good tutorial on Packages
In the app named ‘Packages’ create a new Project (in Packages this is a ‘Raw Package’)
In ‘Settings’ Add the identifier in reverse domain notation
Add an Apple ID Installer certificate under ‘Project’
In ‘Payload’ go to ‘Hierarchy’ and select ’Show hidden Folders’
Add all 3 binaries to /usr/local/bin
– NOTE- we are putting the binaries here because /etc seems to be a protected location in modern macOS. If you think there’s a better spot, please let us know…
Packages>File>Save
Packages>Build>Build
This will output a signed package to the Build folder in your project folder
6. Notarise the Installer
Use a script to upload the new .pkg and notarise it. I used one kindly provided Armin Briegel here
I’ll try to clean up the script and add here but this could take some time…
(But it’s also possible to do this manually- adding this info in case it’s useful in future, this might be better if not using an installer?)

For notarisation we need to zip the app like this (don’t zip normally, it won’t work)

/usr/bin/ditto -c -k --keepParent YourApp.app YourApp.zip

 

Then upload the app like this (you need to set up an app specific password to use this method)

xcrun altool --notarize-app --primary-bundle-id "<id>" -u "<appleid>" -p "<app-specific password>" --file YourApp.zip
When notified of success, you need to staple the notarisation to the app-
xcrun stapler staple "YourApp.app"
7. Check your work
Download a copy of Suspicious Package and drop your new installer package on it- see any errors? Nope?
Go ahead and distribute you legend!
Here’s some stuff I removed from the original article to make the process easier. As time goes on, we may add some of these things back –
Making a Pre-Install Script
This is optional as well, but I’ve installed and uninstalled netclient so many times that it seems prudent to uninstall properly…
#!/bin/sh
# unload lanchd
launchctl unload /Library/LaunchDaemons/com.gravitl.netclient.plist
# remove launchd
rm -f /Library/LaunchDaemons/com.gravitl.netclient.plist
# remove old bits from Servicemax install
rm /usr/local/bin/netclient
rm /usr/local/bin/wg
rm /usr/local/bin/wireguard-go
# remove receipts
rm /private/var/db/receipts/com.gravitl.pkg.NetclientWireguard.bom
rm /private/var/db/receipts/com.gravitl.pkg.NetclientWireguard.plist
# remove bits from the Netmaker standard install that doesn't work on macOS
rm -rf /private/etc/netclient

Recent posts