Often you want to control settings on client machine with scripts rather than packages. One such example is controlling ssh acces, aka ‘Remote Login’ in the OS X UI.
Note: please consider supporting the author of this site by purchasing one of my books! Thank you!
Having ssh access to the clients allows for remote access for trouble shooting and analysis. You can also remotely start or stop processes, like initiating managedsoftwareupdate
right now instead of waiting.
However, since there is potential to abuse ssh, we should restrict ssh access to a subset of users. The OS X UI allows you restrict ssh access to a list of users or groups. In our example we will enable Remote Login and give access to any user with administrative privileges, i.e. the admin
group.
You could write the scripts to enable these settings and put them in a so called “payload free package.” However, Munki has a simpler and more flexible way of handling this. Ironically, you create a pkginfo
file with the nopkg
setting.
Building the Install_Check
script
Usually when you create the pkginfo
for a package or dmg installation, Munki will analyze the files you give it and create conditions on which to install. If the dmg contains an application Firefox, it will look in /Applications
for an application named Firefox and compare versions. If the application on the client is not present or of an older version, Munki will perform the installation.
For configurations other than files or applications, we can provide a script that runs and can tell Munki wether to perform the installation first. It might seem a little odd, but it makes a lot of sense to develop this install_check
script first.
We need to check wether
- Remote Login/ssh is enabled
- access is not set to ‘All Users’
- the admin user group is allowed access
Open your favorite text editor and create a new script called ssh_install_check.sh
and start typing:
#!/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH
# this will run as a munki install_check script
# exit status of 0 means install needs to run
# exit status not 0 means no installation necessary
So if the script runs and returns 0
as the exit code, Munki will perform the installation. If the script returns any non-zero code, then Munki will assume everything is alright and not perform the installation.
First thing we want to test for is wether Remote Login/ssh is enabled. The CLI tool systemsetup
has a command for that:
systemsetup -getremotelogin
Will return Remote Login: On/Off
depending on the status. Testing for this is easy enough. Add these lines to the script:
# Is SSH enabled
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
echo 'Remote login is off!'
exit 0
fi
You can save and test the script on your Mac right now. Use the UI in System Preferences > Sharing to toggle Remote Login and see what the script returns.
Next we want to test wether the access is set to ‘All Users’. There is a group called com.apple.access_ssh
on your Mac that contains the users which are allowed ssh access. However, if the access is set to ‘All Users’ the OS renames this group to com.apple.access_ssh-disabled
. Add these lines to the script:
ssh_group="com.apple.access_ssh"
# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
echo "access set to 'All Users'"
exit 0
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
echo "no group '$ssh_group'"
exit 0
fi
First we defined a variable with the name ofthe group test for, this saves a lot of typing, reduces errors and makes the code more re-usable incase you want to use this for other control groups as well.
Then we run dscl /Local/Default list Groups
and grep
for the names to see if these groups exist. Then we do the same again in case the group does not exist at all (it really should, but it cannot hurt to test).
You can save and run the script to test again. Switch from ‘All Users’ to ‘Only these users’ in the UI. and see the results of the script.
Finally we want to test wether the admin
group is allowed for ssh. We need to see if the group ‘admin’ is contained in the access_ssh group. This is a bit harder than it sounds. We can list nested groups using dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups
, but this will list long UUID strings, not the names of the groups.
To get the UUID of the admin we can use dsmemberutil getuuid -G admin
. and then rest is easy. Add these lines to your script:
# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
echo 'admin group not nested in $ssh_group!'
exit 0
fi
Sidenote 1: this will only test wether the admin group is directly nested in the access_ssh group. You could have another group in the access_ssh group, which itself contains the admin group. So the admin group would have the privilege to use ssh, but this script would still fail. You could also have all members of the admin group listed directly in the access_ssh group, and the script would not check for that. Either way the script will fail and cause Munki to add the admin group (we will learn how later) and it wouldn’t change access, so we are ok with this somewhat superficial test.
Sidenote 2: this script will also ignore other groups or users in the access_ssh group. If you wanted to enforce stricter access policies, you might want to test wether admin is the only group nested in access_ssh.
Finally the script should return a non-zero value when all the tests are passed. Our final script will look like this (cleaning it up a bit):
#!/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH
# this will run as a munki install_check script
# exit status of 0 means install needs to run
# exit status not 0 means no installation necessary
ssh_group="com.apple.access_ssh"
# Is SSH enabled
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
echo 'Remote login is off!'
exit 0
fi
# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
echo "access set to 'All Users'"
exit 0
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
echo "no group '$ssh_group'"
exit 0
fi
# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/com.apple.access_ssh NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
echo 'admin group not nested in $ssh_group!'
exit 0
fi
echo "everything seems as it should be, no install needed"
exit 1
Building the postinstall_script
Now that we have a script that tests wether we need to change settings, we can start building the actual script to do the changes. The good news is that while writing the install_check script we already built the outline for the actual install script. We use the same same tests, but instead of merely reporting and exiting, we now perform the necessary change:
#!/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/munki export PATH
ssh_group="com.apple.access_ssh"
# enable ssh
if [[ $(systemsetup -getremotelogin) = 'Remote Login: Off' ]]; then
echo "turning on Remote Login/SSH"
systemsetup -setremotelogin On
fi
# Does a group named "com.apple.access_ssh" exist?
if [[ $(dscl /Local/Default list /Groups | grep "${ssh_group}-disabled" | wc -l) -eq 1 ]]; then
#rename this group
echo "renaming group '${ssh_group}-disabled'"
dscl localhost change /Local/Default/Groups/${ssh_group}-disabled RecordName ${ssh_group}-disabled $ssh_group
elif [[ $(dscl /Local/Default list /Groups | grep "$ssh_group" | wc -l) -eq 0 ]]; then
# create group
echo "creating group $ssh_group"
dseditgroup -o create -n "/Local/Default" -r "Remote Login Group" -T group $ssh_group
fi
# does the group contain the admin group?
admin_uuid=$(dsmemberutil getuuid -G admin)
if [[ $(dscl /Local/Default read Groups/$ssh_group NestedGroups | grep "$admin_uuid" | wc -l) -eq 0 ]]; then
echo "adding admin group to $ssh_group"
dseditgroup -o edit -n "/Local/Default" -a admin -t group $ssh_group
fi
exit 0
Note that we use dseditgroup
instead of manipulating the NestedGroup
property with dscl. This is the official and safe way to manipulate groups in OS X.
Save this as ssh_postinstall.sh
. Open the Remote Login Sharing UI in System Preferences > Sharing, change the settings and then run this script. To see the changes from the script reflected in the Preference you have to quit and restart System Preferences.
Building the pkginfo
file
Now we that we have a script to test and another to change the settings we have to build a pkginfo
file that will explain all of this to Munki. Let’s use makepkginfo
to get us started:
makepkginfo --name EnableSSH --nopkg --pkgvers=1.0 --installcheck_script=ssh_install_check.sh --postinstall_script=ssh_postinstall.sh --unattended_install > enableSSH.pkginfo
--nopkg
sets the install_type
and tells Munki that this item has no pkg or dmg file associated with it. The two scripts we built are included in the plist. Munki will read this pkginfo and execute the code when necessary.
You can change or add some more keys (such as description
or displayname
) and then copy the file to your Munki repository and run makecatalogs
. Then add EnableSSH to a manifest on your test machine(s) and run Managed Software Update on it. EnableSSH should appear and run the postinstall
script. Check wether SSH works now.
Further, you can go in the UI and change some setting for Remote login, then run Managed Software Update again (or logout to make it run). Notice how our scripts detect that the settings changed from what they are supposed to be and re-ran our postinstall script to re-set them.
more options
You could add a third script to the pkginfo to ‘uninstall’ the settings. That way you could revert your settings to the default. There is even an option for a uninstallcheck_script
that will check wether Munki should uninstall your settings.
Summary
The nopkg
option allows us to run scripts with Munki, without need to bundle a pkg or dmg payload. Using an installcheck_script
allows us to give Munki very precise instructions on when to run the script and repeatedly enforce configurations.
Good stuff–one note: The goal of the script is to enable the local “Administrators” group, however by default the “Administrators” group is nested in the “com.apple.access_ssh” group. If it is _not_ desired to have the “Administrators” group nested in the “com.apple.access_ssh” group, it’ll need to be removed.