Munki and postinstall scripts

One the great features of Munki is that it will run postinstall scripts. This is great for creating quick and dirty custom pkgs as well as customizing vendor supplied pkgs for any environment. Three such cases in our environment are (1) Adobe Acrobat 9, (2) MS Office 2011, (3) Firefox 4.0.1

Adobe Acrobat 9

Acrobat is the enterprise’s standard application for editing/creating PDFs. As such it’s important to keep Acrobat up to date and working on client machines. The problem with this occurs at two places. The first being updates. Before the release of CS5, Acrobat had no real solution to packaging and deploying updates, and this has plagued Acrobat 9. The latest acrobat update requires you to have all previous updates installed (the reason for this will be explained a little later), and it requires you to select which acrobat installation to upgrade. This can be very troublesome, however Munki easily solves that problem with update_for and requires keys. The most annoying feature Acrobat has is the self-heal feature which requires the user to authenticate on first run after a patch install to “fix” the installation. There is documentation on the Munki wiki as how to bypass this:

              <key>postinstall_script</key>
        <string>#!/bin/bash
sed -i .bak 's/\&lt;string\&gt;AcroEFGPro90SelfHeal\.xml\&lt;\/string\&gt;//g' /Applications/Adobe\ Acrobat\ 9\ Pro/Adobe\ Acrobat\ Pro.app/Contents/MacOS/SHInit.xml
sed -i .bak 's/\&lt;string\&gt;AcroEFGDist90SelfHeal\.xml\&lt;\/string\&gt;//g' /Applications/Adobe\ Acrobat\ 9\ Pro/Acrobat\ Distiller.app/Contents/MacOS/SHInit.xml
        </string>

This suppresses the self heal and the user is happy. However with this fix, a CORE file in Acrobat’s setup has been altered and the patching process will break in the future. Going back to a little earlier, the reason Acrobat requires that all previous updates be installed is because it checksums the files it expects, if a patch has been skipped, the checksum on a later patch will fail. This is the same for the SHInit.xml file. The update process doesn’t always checksum the file, but for certain patches it does. Therefore, a preinstall_script is needed to fix the installation before the update starts:

        <key>preinstall_script</key>
        <string>#!/bin/bash
          if [ -f "/Applications/Adobe Acrobat 9 Pro/Adobe Acrobat Pro.app/Contents/MacOS/SHInit.xml.bak" ]
          then
          mv "/Applications/Adobe Acrobat 9 Pro/Adobe Acrobat Pro.app/Contents/MacOS/SHInit.xml.bak" "/Applications/Adobe Acrobat 9 Pro/Adobe Acrobat Pro.app/Contents/MacOS/SHInit.xml"
          fi
        </string>

Now with little effort on the sysadmin’s part, Acrobat has been fixed.

MS Office 2011

Munki installs office very nicely, and in our environment, we have a pkg that customizes and registers Office. However, it does so by writing files to the User Template directory. This way Office is registered for every new local user on the machine. However, existing users would still need to register and activate Office. In order to install the pkg for them, we use the following postinstall_script to copy the files from the User Template directory to existing users directories:

        <key>postinstall_script</key>
        <string>#!/bin/sh
dir="/System/Library/User*Template/English.lproj/Library"

for folder in /Users/*
do
if [ $folder != "/Users/Shared" ]
then
/bin/cp $dir/"Preferences/com.microsoft.autoupdate2.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.error_reporting.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.Excel.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.language_register.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.office.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.outlook.database_daemon.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.outlook.office_reminders.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.Powerpoint.plist" $folder/Library/Preferences/
/bin/cp $dir/"Preferences/com.microsoft.Word.plist" $folder/Library/Preferences/
chown -R ${folder/\/Users\//} "$folder/Library/Preferences/"

fi
done

exit 0</string>

This allows for quick and messy pkgs (such as the one above) to be cleaned up with a postinstall_script.

Firefox 4.0.1

The case of Firefox is very similar to that of Acrobat, because vendor supplied software is being customized for the environment. Firefox is customized by writing to three files within the application that contain our settings:

        <key>postinstall_script</key>
        <string>#!/bin/bash
localsettings="/Applications/Firefox.app/Contents/MacOS/defaults/pref/local-settings.js"
touch -f $localsettings
echo "// MyOrganization additions
pref('general.config.obscure_value', 0);
pref('general.config.filename', 'firefox_CUL.cfg');" &gt; $localsettings

firefox_cul="/Applications/Firefox.app/Contents/MacOS/firefox_CUL.cfg"
touch -f $firefox_cul
echo "// 
// This file sets some default prefs for use at Columbia Libraries
// and locks down some other prefs.
// application updates
//
lockPref('app.update.enabled', false);
lockPref('app.update.autoUpdateEnabled', false);
lockPref('extensions.update.autoUpdate', false);
lockPref('extensions.update.enabled', false);
lockPref('browser.search.update', false);
lockPref('browser.startup.homepage_override.mstone','ignore');
// Password Manager
pref('signon.rememberSignons', false);
// Default browser check
pref('browser.shell.checkDefaultBrowser', false);
// Home page
pref('browser.startup.homepage','http://library.columbia.edu');
pref('browser.startup.homepage_reset','http://library.columbia.edu');" &gt; $firefox_cul

override="/Applications/Firefox.app/Contents/MacOS/override.ini"
touch -f $override
echo "[XRE]
EnableProfileMigrator=false" &gt; $override

exit 0</string>

The main difference between the Acrobat and Firefox case is that in this case files are being created and then written to. There are other use cases such as RealPlayer where the postinstall_script create plists to register the product and hide annoying prompts from the user, however those are better handled with MCX rather than Munki.

Advertisements

Getting Munki up and running.

Munki is a great tool for installing/updating/uninstalling software packages. Munki provides a central repository of software and allows for easy software-build management. With Munki, you can keep all your software in the repo, write manifests for each of your builds and push out the manifests out. Another advantage of Munki (that may be later utilized in our environment) is that it allows non-admin users to update the software on their machines through the updates provided by Munki.
Previously we were using DeployStudio to push out tiered builds, however the downside of this method is that it’s not simple to mass-update/uninstall software. The methods to make these changes would include either (a) writing a script that uninstalls packages, (b) rebuilding the machine with the new software build. With Munki, all of that is eliminated, and it comes down to maintaining a software manifest.
Currently we’ve installed Munki on https://adams.cul.columbia.edu. The wiki pages used for this are the following:

Step 1: Create a CA and certificate for our Munki Server to use

When setting up Adams, I more or less followed the instructions above (Using Munki with SSL client certificates). A quick outline of the steps would be:
1. Download materials
2. Edit config/openssl.conf (optional, either do this step to setup default values or enter in values as you run the following steps)
3. run bin/createCA.sh – creates cert, use Common Name MUNKI_CA (identifies which CA you’re creating).
4. run bin/newServer.sh – create server certificate, use the domain of your server as the Common Name (e.g. Common Name = adams.cul.columbia.edu).
5. run bin/addClient.sh – creates client certificate, use Common Name has to be the argument you used to start the script.
6. Store the contents of the parent folder (that contains bin, demoCA, servers, clients) in /private/etc/munki)
7. In Server Admin (assuming your munki server is running on an OS X server 10.6+), under add the certificates you just created.

Step 2: Set up your repo

1. Add a site under “Web” with Server Admin, under the security tab, use the certificate you have just imported.
2. Within the directory of your site, create the following directories:
a. munki/
b. munki/repo
c. munki/repo/pkgs
d. munki/repo/pkgsinfo
e. munki/repo/catalogs
f. munki/repo/manifests

Step 3: Configure Munki on the server

When setting up Munki, you could follow the steps in “Installing on a standalone machine”, but I found a very useful alternative to that in the “Creating Disk Images” page. The nugget being: /usr/local/munki/munkiimport, which will import .pkg files and turn .mpkg files into a disk image for Munki. That’s not the best part though, the best part is that it creates the catalog files, pkginfos and puts the disk image/pkg in the repository. The only setup that needs to be done is running /usr/local/munki/munkiimport –configure to set up the basic values, i.e. the repo path, munki’s url.

Step 4: Secure the server with some basic authentication

Firstly, in Server Admin, go to Web -> Sites -> YOUR SITE -> Options and enable all overrides. Then in terminal cd to your repo directory and create a .htpasswd file with the following command:

$ htpasswd -c .htpasswd munki
New password:
Re-type new password:
Adding password for user munki

Then you need to create the .htaccess file in your repo’s directory with the following content:

AuthType Basic
AuthName "Munki Repository"
AuthUserFile /path/to/your/munki/repo_root/.htpasswd
Require valid-user

Step 5: Configure Munki on the client

First move munki_client.pem from clients/munki_client/ and cacert.pem from demoCA/ to the certs directory in /Library/Managed Installs/ folder (or wherever you’ve set the ManagedInstallDir) on the client, you may have to create this directory.
Munki’s configuration plist values lists all the possible values for the plist that we’ll use on the clients. Make sure the following are set properly:

  • ClientIdentifier (the manifest that the client is going to use)
  • ManagedInstallDir (local directory that Munki will use to store pkgs)
  • LogFile
  • LoggingLevel
  • UseClientCertificate (set to TRUE)
  • SoftwareRepoCAPath (set to the certs directory)
  • SoftwareRepoCACertificate (set to cacert.pem’s path)
  • SuppressUserNotification (if set to true, will make the process silent)

There’s more on that page, customize your own.

In our deployment we plan to:

1. Create a custom Munki client pkg, which will contain the certificates and ManagedInstalls.plist (as well as create custom directories if we see move in that direction). We will deploy this package via DeployStudio, and then run a script that will call Munki to install software.
2. Create sub directories within our repo based on software vendor and manifest.