12 Feb Securely deploying Xcode with minimum privileges
Xcode is Apple’s development environment. It’s used to develop applications on Macs, iOS devices like iPhones and the Apple Watch. It also includes the new language Swift, which is becoming very popular in higher education. However, Xcode requires users to have “_Developer” group privileges to allow the debugger and emulators to work correctly. We give our users only the minimum privileges they need to get their work done and we take great pains to secure our environment. We felt giving every user “_Developer” rights was unnecessary and something we could script a solution around.
We’re deploying Xcode with the “Crappy App” model as we call it. Crappy Apps are applications with exceptional requirements beyond an average application. For example, a crappy app might:
- have insecure permissions
- require hardcoded variables (usernames, paths, etc.)
- have to update with every launch
- require access to locations we’d prefer they not have access to
- have to be launched by a specific user or group
In most cases we work around crappy app behavior by enclosing the offending application in a disk image, attach a shadow file to capture file system changes and using an AppleScript to launch the program for the user, allowing us to script around undesirable behavior. Our environment is currently maintained with radmind and we create user accounts on the fly with LDAP and Kerberos. Once a user logs out, their documents are temporarily stored locally and their account is removed. If you work in a package-based environment you may still find the overall concepts of use.
Here’s how our approach works:
- The user launches “Xcode”, which is really an AppleScript app.
- The AppleScript discovers the user’s login name.
- The AppleScript calls a shell script with the user’s login name.
- The shell script, with higher system privileges, adds the login name to the “_Developer” group.
- The AppleScript then mounts the Xcode.dmg and launches Xcode for the user.
Another possible solution would be to grant the required group access during login using a similar script.
Why, you may ask, are we going though all of this effort? The vast majority of the machines we support are generic and have a large number of applications installed. This allows patrons to select any machine in any classroom or lab and feel confident that the application they need to do their work will be available.
Our recipe for deploying Xcode
What you’ll need:
- Xcode installer, Apple’s Dev Tools download
- Command Line Tools installer, Apple’s Dev Tools download
- The Icon file for Xcode‘s app icon
- The main AppleScript, included below
- The AddUIDToDevGroup.sh shell script, included below
- Disk Utility,
- Script Editor,
- Install Xcode.
- Use Disk Utility to create a new disk image from folder (
⇧⌘N) of Xcode.app
- Delete /Applications/Xcode.app
- Open Script Editor, and open a new script window (
- Paste in the included script.
- Select View:Show Bundle Contents (
- Drag in the Xcode icon and rename it to “applet.icns”
- Copy in the Xcode.dmg you created in step 2.
- Edit the Short Version string to mimic the version of Xcode you’re installing.
- Save the script as an Application named “Xcode”
- Copy AddUIDToDevGroup.sh into /usr/local/bin , or a location of your choosing. Just be sure to edit the AppleScript to reflect the move.
/etc/sudoers . The line you need to add should look like this:
ALL ALL=(root) NOPASSWD: /usr/local/bin/addUIDToDevGroup.sh
In order to make the command line tools and man pages available to users who don’t need the full Xcode, we also perform a few additional steps:
- Install the separate command line tools package.
- In the terminal, enter:
sudo code-select -s /Library/Developer/CommandLineTools
- vi /etc/manpaths.d/xcode_cli_tools. In the terminal enter:
- Move the Documentation into a shared location:
sudo mv /User/"installing user"/Library/Developer/Shared /Library/Developer
- Adjust ownership of the moved files:
sudo chown -R root:staff /Library/Developer
set myUID to (do shell script "whoami")
set addToGroup to (do shell script "sudo /usr/local/bin/addUIDToDevGroup.sh " & myUID) as integer
if addToGroup is not 0 then
--ignore the result
set attachImage to (do shell script "hdiutil attach /Applications/Programming/Xcode.app/Contents/Resources/Xcode.dmg -quiet -nobrowse -noautoopen -noverify -owners on; echo $?") as integer
if attachImage is not 0 then
--ignore the result, should be an error dialog
set launchXcode to (do shell script "open -a /Volumes/Xcode/Xcode.app; echo $?") as integer
--ignore the result
inSudo=`/usr/bin/grep $inputUID /etc/sudoers -c`
if /bin/test $inSudo -ne 0
/usr/bin/dscl . merge /Groups/_developer GroupMembership $inputUID
Links discussing poorly-made/crappy apps
- PDF of a 2003 presentation on Crappy Apps.