How To: Package a Docker Installer that Does Not Request Admin Privileges

Jacher
New Contributor II

b9c261957662430aa13822579cd4cd8b

When Docker installs on a machine, it asks the user for root privileges to finish its installation process after you start it the first time. In our environment, we decided that it's best users don't need to enter any sort of credentials to finish the installation of an application. So, via a trail of troubleshooting steps I found online and some trial & error, I was able to put together an installer that does not need root privileges to finish its installation.

Use the following directions to create a version of the installer that does not require Admin Rights. If you are already familiar with making JSS policies and using Composer, check out the TLDR section at the bottom.

  1. Download Docker For Mac
  2. Mount the Docker DMG
  3. Open Composer
  4. Click on New
  5. Select Normal Snapshot
  6. Click Next
  7. Name the Snapshot and click next
  8. Once the Snapshot has finished creating, drag the Docker application into the root Applications folder
  9. Open Applications, and then open Docker
  10. Docker will post an introductory window, click OK
  11. Docker will ask for privileged access, click OK
  12. Enter your Admin credentials and click okay
  13. Docker will run its final installation steps
  14. Click Got It after Docker has finished running its post-installation d14f28b4a41743ba9355c5e2a24870db
  15. In Composer, click Create Package Source
  16. Drill down Library>LaunchDaemons
  17. Select the com.docker.vmnetd.plist file
  18. Ensure that the file's owner is root, and group is wheel.
  19. Check the box for X (execute) on the Owner row. Verify that it states Mode: 744 (not 644) e2159ca02bba4e98bf4f7525189a309f
  20. Drill down Users>{username}>Library>Containers>com.docker.docker
  21. Delete the Data folder within the com.docker.docker folder afb33a1bf1e444da8c8e4d247841f592
  22. Ensure there are no additional folders unrelated to the Docker installation in the package source. In my case I removed the Saved Application State folder.
  23. Once you've done this, click on Build as DMG and save to your package build location
  24. Open Casper Admin and drag the DMG into Casper Admin to upload.
  25. Change the settings on the DMG to turn on FEU (Fill Existing User Template)
  26. Categorize the file
  27. Save
  28. Log into the JSS and Create the Docker policy.
  29. Place the DMG in the policy
  30. Set the policy to restart after install (Restart Options>User Logged In Action> Restart)
  31. Add Files and Processes, add the following one liner to Execute Command: /bin/launchctl load -Fw /Library/LaunchDaemons/com.docker.vmnetd.plist
  32. Setup to install from Self Service

TLDR Version;
Install using a composer snapshot as normal.
The only major differences are as follows:
Change /Library/LaunchDaemon/com.docker.vmnetd.plist to 744 and root:wheel
Delete the Data folder found in Users/{username}/Library/Containers/com.docker.docker
Save as DMG, place on Casper Admin with FEU enabled
In Policy: Ensure that the computer restarts after install. Add the following one liner in Execute Command:
/bin/launchctl load -Fw /Library/LaunchDaemons/com.docker.vmnetd.plist

37 REPLIES 37

jimmy-swings
Contributor II

Trying this now...

jimmy-swings
Contributor II

Worked like a charm!

jimmy-swings
Contributor II

Hey @Jacher - have you had a chance to package / distribute an update? As a test I've successfully packaged Docker Edge and now just packaging the update in preparation to test the distribution of this.193a10acc7b0423499f6586c99453438

I'd be interested to see if you have investigated how to suppress any update notifications. I've already had a support ticket raised about not being able to install the update without elevated rights.

Thanks!

jimmy-swings
Contributor II

This process seems to be broken in the recent 1803 drop. Error messages suggest that the docker app is looking for the folder path of the compose user rather than the local user when installed on a remote host. I'll work through the issue and post any updates.

EUC600
New Contributor III

Does anyone know if this is possible still? I'm hoping to do this for our company as well but also get an error. It would be nice if there were some commands for it to extract what it needs that could be used in a script. Similar to the Xcode post install commands. It's hard to find any information like that on Docker though.

jimmy-swings
Contributor II

Hi @DakotaS96 - I've been working with Docker Engineering to see how best to package and distribute at scale. The process hasn't significantly changed although there is now a dependency on accessing the com.docker.docker directory. It's not automatically recreated as previously mentioned.

Let me see if a support ticket or feature request exists so you can add your contact details.

In a change to the above documentation:
Step 21: DO NOT DELETE the Data folder within the com.docker.docker folder
Step 31: Create an alias mapping your local user's account to your packaging account. ln -s /Users/$CURRENT_USER/ /Users/docker-package-user

EUC600
New Contributor III

Awesome! Looks like that worked. Thanks for the update!

I'm not sure if I needed to but in order to keep both step 31's I created a script to run after the package install.

!/bin/sh

currentUser=ls -l /dev/console | cut -d " " -f 4

launchctl load -Fw /Library/LaunchDaemons/com.docker.vmnetd.plist
ln -s /Users/$currentUser/ /Users/docker-package-user

marcR
New Contributor

@jaz Might be a bit late, but i asked myself the same thing. Found out that theres a Preferences .plist in /User/username/Library/Preferences/com.docker.docker.plist. you can disable Autoupdate via:

defaults write /Users/$username/Library/Preferences/com.docker.docker.plist SUEnableAutomaticChecks 0

But it will just uncheck the checkbox, user can change it if he wants to.

sdb2029
New Contributor II

@jaz @DakotaS96 When you run the "ln -s /Users/$currentUser/ /Users/docker-package-user" command, who exactly do you mean as the Docker-Package-User? I'm assuming that I'm supposed to substitute that out with a user specific to my environment. Is it supposed to be an admin account? I should also mention that don't know much about docker, so that probably doesn't help.
Thanks for posting updates on this! It seems to be working without that command oddly enough.

Andrew_Rogers
New Contributor II

@jaz @DakotaS96 @sdb2029 I am interested in some more detail about the package user as well. I have to deploy this app to users that do not have and cannot have admin rights. I followed @Jacher 's steps and wound up with a copy of Docker that is happy to install but hits a fatal error on launch and cannot reset to factory, cannot start fully so I can uninstall. /halp/

Cornoir
Contributor II

I have come across this same issue when installing applications that use the squirrel.framework to autoupdate (Yammer, MS Teams, et al).
The fix I came to was to install those apps in the User template in a users local Application folder (/System/Library/User Template/English.lproj/Applications) for new users and placing via script the squirrel App in existing user's local Application folder.

This allows the local user to never be prompted for admin rights as they have full rights to their local Applications folder, Applications within that folder and the subsequent sub-apps within the Application.

josborne3
New Contributor

@jaz @DakotaS96 @sdb2029 @Jacher

Does anyone have an update to if this is possible with DockerCE 2.0 and up?

I have a need for this as well, but so far I have not been successful.

I have tried copying the Docker App to the user's application folder, but that still prompts for admin credentials to configure things.

Any guidance here or update to the original workflow would be greatly appreciated!

Thanks!

tonybilzi
New Contributor

These post-install commands seem to be working for me:

cp /Applications/Docker.app/Contents/Library/LaunchServices/com.docker.vmnetd /Library/PrivilegedHelperTools
cp /Applications/Docker.app/Contents/Resources/com.docker.vmnetd.plist /Library/LaunchDaemons
chown root:wheel /Library/LaunchDaemons/com.docker.vmnetd.plist /Library/PrivilegedHelperTools/com.docker.vmnetd
chmod 744 /Library/LaunchDaemons/com.docker.vmnetd.plist
launchctl load -Fw /Library/LaunchDaemons/com.docker.vmnetd.plist

clint_arndt
New Contributor II

I am trying to create a dmg in Composer with docker 2.3.0.3 with these instructions and can't even get the dmg to verify and mount. Current failure logs show:

Error: An error occurred attempting to mount the package "Docker 2.3.0.3.dmg".

Does anyone have any advice on this?

stutz
Contributor

@tonybilzi I confirmed these commands work on version 2.3.0.4. Thank you for posting these as it saved me time trying to figure it out.

ravi_iits
New Contributor

This screenshot have username so dmg will work?
Please suggest if we need to create pkg file of this.

Jason33
Contributor II

@tonybilzi Thanks for putting up those post-install commands. Worked like a charm for 2.3.0.5

jmahlman
Valued Contributor

If anyone here uses AutoPkg(r), chilcote's Docker recipe adds the post install script to it automatically 🙂

efil4xiN
New Contributor III

Greetings Nation,

I was given the task to find out why docker desktop was not working/admin prompt popping up. Our devices are 1 to 1, but I am sure something like Outset could work for shared devices. The version we are using is 2.4.0.0, and it is deployed via Self-Service. The following worked in our case. I am not sure if docker has posted an "official" method. I make no guarantees, and the usual rules apply test, test, test and use at your own risk.
I did not package it but will leave a suspicious package screenshot. The team had made the package with the user similar to the above process. Well, that was problem number one. That user was not on the production Macs, so soft linking did not work.
The next problem was that they did not have a post-install script. So I grabbed the settings.json file, made the below edit to "datafolder" to blank ( it will default to the current logged in user's home folder). I dropped it in /var/tmp and made a package.
Next, I used the following script, with help from all of you. So what this does is check for "/Users/currntloggedinuser/Library/Group Containers/group.com.docker" folder. If it is not present, it creates the folder then copies the settings.json file over to "/Users/currentloggedinuser/Library/Group Containers/group.com.docker". It installs the app Package, then runs the post-install. The last step was to create a PPPC file for the desktop folder, documents folder, and reminders(?) with PPPC Utility. I will tackle updates next.

#!/bin/sh
currentUser=`stat -f "%Su" /dev/console`

/usr/bin/sudo -u $currentUser mkdir /Users/$currentUser/Library/Group Containers/group.com.docker
/usr/bin/sudo -u $currentUser cp /var/tmp/settings.json /Users/$currentUser/Library/Group Containers/group.com.docker/

sleep 5

/usr/bin/sudo defaults write /Users/$currentUser/Library/Preferences/com.docker.docker.plist SUEnableAutomaticChecks 0
/usr/bin/sudo cp /Applications/Docker.app/Contents/Library/LaunchServices/com.docker.vmnetd /Library/PrivilegedHelperTools
/usr/bin/sudo cp /Applications/Docker.app/Contents/Resources/com.docker.vmnetd.plist /Library/LaunchDaemons
/usr/bin/sudo chown root:wheel /Library/LaunchDaemons/com.docker.vmnetd.plist /Library/PrivilegedHelperTools/com.docker.vmnetd
/usr/bin/sudo chmod 744 /Library/LaunchDaemons/com.docker.vmnetd.plist
/usr/bin/sudo launchctl load -Fw /Library/LaunchDaemons/com.docker.vmnetd.plist

/usr/bin/sudo  rm -rf /var/tmp/settings.json

3c037900a0954f3f880cf17836b396ec

0ff4715526384dae9b538eff4a7ca0ec

sdagley
Honored Contributor II

@efil4xiN Thanks for sharing your work on this, and the configuration script. One suggestion however - when the jamf agent is running a script the context is root, so except for where you're using sudo to run a command in the context of currentUser there is no need to prefix your commands with /usr/bin/sudo

efil4xiN
New Contributor III

@sdagley is correct. sometimes I get on an absolute path kick 🙂

user-BqBTAgwquG
New Contributor II

Can anyone advise on how to get the latest Docker Desktop version (v3.3.0) working without requesting admin privileges?

I tried the workflows covered above without success, I just got a prompt to reset the software to factory settings and I was then asked for administrator credentials after that process completed.

Jason33
Contributor II

Anyone get this working for version 3.3.3? I'm in the same boat as the user post from 4/14.

jmahlman
Valued Contributor

Yeah, I'm also seeing this. Guessing Docker changed something...

cgarvey
New Contributor

For version 3.3.x and higher, Docker no longer bundles the .plist in the application bundle for you to copy to /Library/LaunchDaemons anymore (as per the steps above).

Some binary within the app bundle is generating this .plist now (and Docker checks for its existence on startup now, which is why you're getting the admin credentials prompt).

I haven't seen a way to call a binary to generate this file (which would be ideal), but you can grab a copy of this .plist from a successful install, and copy it to the /Library/LaunchDaemons (with correct ownership/permissions as per the steps above).

Be aware, though, that there is a <version> element in this that changes (e.g. v3.3.3 was 59, and v3.4.0 is 60), so you'll need to update your scripts pretty frequently until there's a better way.

jmahlman
Valued Contributor

Thanks fore the tip, @cgarvey, I'll give that a shot.

jmahlman
Valued Contributor

-- Deleted

jmahlman
Valued Contributor

So I thought I had this but something isn't working.

I made my Docker package with this edited post install script:

#!/bin/bash

# REF: https://forums.docker.com/t/feature-request-cli-tool-for-automated-installation/18334/4
# assumes the following directories exist:
# /usr/local/bin
# /Library/PrivilegedHelperTools

declare -r docker_bundle_dir=/Applications/Docker.app/Contents
declare -r privtools=/Library/PrivilegedHelperTools
declare -r launchDaemon=/Library/LaunchDaemons/com.docker.vmnetd.plist

for tool in com.docker.frontend docker docker-compose docker-diagnose docker-machine notary; do
    /bin/ln -sf "${docker_bundle_dir}"/Resources/bin/${tool} /usr/local/bin
done

[[ ! -d "${privtools}" ]] && /bin/mkdir -p "${privtools}" ; /bin/chmod 1755 "${privtools}"

/usr/bin/install -m 0544 -o root -g wheel "${docker_bundle_dir}"/Library/LaunchServices/com.docker.vmnetd "${privtools}"

# This file no longer exists in the installer. You need to copy a known good plist over now. For an example of the file, see the end.
#/usr/bin/install -m 0644 -o root -g wheel ${docker_bundle_dir}/Resources/com.docker.vmnetd.plist /Library/LaunchDaemons

# Let's get the correct vmnetd version to set the launchDaemon 
VERSION=$(/usr/bin/defaults read /Applications/Docker.app/Contents/Info.plist VmnetdVersion)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# LAUNCH DAEMON CREATION
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

/bin/cat << EOF > "$launchDaemon"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.docker.vmnetd</string>
    <key>Program</key>
    <string>/Library/PrivilegedHelperTools/com.docker.vmnetd</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/PrivilegedHelperTools/com.docker.vmnetd</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Sockets</key>
    <dict>
        <key>Listener</key>
        <dict>
            <key>SockPathMode</key>
            <integer>438</integer>
            <key>SockPathName</key>
            <string>/var/run/com.docker.vmnetd.sock</string>
        </dict>
    </dict>
    <key>Version</key>
    <string>$VERSION</string>
</dict>
</plist>
EOF

/usr/bin/plutil -convert xml1 "$launchDaemon"
## Set the permission on the file just made.
/usr/sbin/chown root:wheel "$launchDaemon"
/bin/chmod 0644 "$launchDaemon"
/bin/launchctl load "$launchDaemon"

Running this without a package, works! Docker loads without admin and everything is nice. If I run it from jamf (or as a pkg) it doesn't work. Any ideas?

jmahlman
Valued Contributor

I have been successful in creating a deployable Docker package....but I'm confused why I had to do it this way, so maybe someone can shed some light on it.

I made a standard package with the Docker app in the Applications folder. I added scripts to the post-install but it didn't work when I put it in the actual package! So what I did was break the scripts out and put them in Jamf and just run those after install. Same script I included in the package..just removed from the package. Why it works this way, i don't know.

First Post-install script:

#!/bin/bash
# Based on https://github.com/autopkg/chilcote-recipes/blob/master/Docker/Docker.munki.recipe
# which in turn is based on:
# <https://forums.docker.com/t/feature-request-cli-tool-for-automated-installation/18334/4>
# Will create:
# /Library/PrivilegedHelperTools
# /usr/local/bin
# if missing

declare -r docker_bundle_dir=/Applications/Docker.app/Contents
declare -r privtools=/Library/PrivilegedHelperTools
declare -r usr_local_bin=/usr/local/bin

[[ ! -d ${usr_local_bin} ]] && /bin/mkdir -p ${usr_local_bin} ; /bin/chmod 1755 ${usr_local_bin}
for tool in docker docker-compose docker-diagnose docker-machine notary; do
    /bin/ln -sf ${docker_bundle_dir}/Resources/bin/${tool} /usr/local/bin
done

[[ ! -d ${privtools} ]] && /bin/mkdir -p ${privtools} ; /bin/chmod 1755 ${privtools}

# unload com.docker.vmnetd if present
if [[ -e /Library/LaunchDaemons/com.docker.vmnetd.plist ]] ; then
    /bin/launchctl unload /Library/LaunchDaemons/com.docker.vmnetd.plist
fi

/usr/bin/install -m 0544 -o root -g wheel ${docker_bundle_dir}/Library/LaunchServices/com.docker.vmnetd ${privtools}

## this bit no longer works because the LD plist is no longer in the app bundle.
## See https://github.com/docker/roadmap/issues/80#issuecomment-853446920
#/usr/bin/install -m 0644 -o root -g wheel #${docker_bundle_dir}/Resources/com.docker.vmnetd.plist /Library/LaunchDaemons
##
## fragile replacement
/bin/cat > /Library/LaunchDaemons/com.docker.vmnetd.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.docker.vmnetd</string>
    <key>Program</key>
    <string>/Library/PrivilegedHelperTools/com.docker.vmnetd</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/PrivilegedHelperTools/com.docker.vmnetd</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Sockets</key>
    <dict>
        <key>Listener</key>
        <dict>
            <key>SockPathMode</key>
            <integer>438</integer>
            <key>SockPathName</key>
            <string>/var/run/com.docker.vmnetd.sock</string>
        </dict>
    </dict>
</dict>
</plist>
EOF
/bin/chmod 644 /Library/LaunchDaemons/com.docker.vmnetd.plist
## end fragile replacement
VERSION=$(/usr/bin/defaults read /Applications/Docker.app/Contents/Info.plist VmnetdVersion)
/usr/bin/defaults write /Library/LaunchDaemons/com.docker.vmnetd.plist Version -string ${VERSION}
/usr/bin/plutil -convert xml1 /Library/LaunchDaemons/com.docker.vmnetd.plist
/bin/chmod 0644 /Library/LaunchDaemons/com.docker.vmnetd.plist
/bin/launchctl load /Library/LaunchDaemons/com.docker.vmnetd.plist

And then the next one which sets up preferences:

#!/bin/zsh
#
# Description: Script to set Docker Settings.
#
#

# Set variables
JQ="/usr/local/bin/jq"
JQTrigger="${4}"
SettingsVersion="${5}"
# 3.4.0 is version 11
# 3.3.3 is version 10
# 2.5.0.1 is version 6

# Look for JQ for JSON editing
if [[ ! -f "$JQ" ]]; then
    echo "JQ not installed, installing..."
    /usr/local/bin/jamf policy -event "$JQTrigger"
fi

localUsers=( $(dscl . list /Users UniqueID | awk '$2 >= 501 {print $1}' | grep -Ev "^(lms-account|mfe|casperctrl|y_.*)$") )
for usr in ${localUsers[@]}; do
    SettingFile="/Users/$usr/Library/Group Containers/group.com.docker/settings.json"
    TmpSettings="/Users/$usr/Library/Group Containers/group.com.docker/old_settings.json"

    if [[ ! -f "$SettingFile" ]]; then
        echo "Settings file does not exist for $usr, creating..."
        mkdir -p "/Users/$usr/Library/Group Containers/group.com.docker/"
        echo "{}" > "$SettingFile" # Creating a json from scratch
        chmod 755 "/Users/$usr/Library/Group Containers/group.com.docker/"
        chmod 666 "$SettingFile"
        chown -R "$usr" "/Users/$usr/Library/Group Containers/group.com.docker/"
    fi

    # Do the stuff
    $JQ '. + {"checkForUpdates":false, "analyticsEnabled":false, "settingsVersion":'$SettingsVersion'}' "$SettingFile" > "$TmpSettings" && cp "$TmpSettings" "$SettingFile"
    defaults write /Users/$usr/Library/Preferences/com.docker.docker.plist SUEnableAutomaticChecks 0
done

I use JQ to do this and install if it's not already installed. Note that the "settings version" is required for an upgrade to work properly.

With all of this in place, I have successfully deployed 3.3.3 and 3.4.0.

Chris_Potrebka
New Contributor

I found that the following command works well.

 /Applications/Docker.app/Contents/MacOS/Docker --install-privileged-components

my install script steps as root:

  1. Curl down latest DMG
  2. Mount dmg
  3. ditto Docker.app to /Applications/Docker.app
  4. unmount dmg
  5. run the --install-privileged-components command.

I've tested as standard user and Docker launches and works as expected.

Jason33
Contributor II

This guy @Chris_Potrebka knows what he's talking about

jmahlman
Valued Contributor

@Chris_Potrebka Does this work with upgrades as well?

jmahlman
Valued Contributor

Update: It works! Thank you so much, @Chris_Potrebka !

Chris_Potrebka
New Contributor

Happy to help!

This is how I discovered docker --install-privileged-components

I started poking around the Docker.app using strings to see if there was any hidden commands and while the docker binary didn't provide anything interesting, the DockerHelper.app revealed what I was hoping for. I found it with the following command.

% strings /Applications/Docker.app/Contents/Library/LoginItems/DockerHelper.app/Contents/MacOS/DockerHelper | grep install

which gave me:

LLVM Profile Warning: Unable to install an exit signal handler for %d (errno = %d).
installPrivilegedComponents
uninstall
--install-privileged-components
installPrivilegedComponents
uninstall

I then tested...

/Applications/Docker.app/Contents/Library/LoginItems/DockerHelper.app/Contents/MacOS/DockerHelper --install-privileged-components

and it failed.

I then tested...

/Applications/Docker.app/Contents/MacOS/Docker --install-privileged-components

and it worked.

mm2270
Legendary Contributor II

Just wanted to mention how perfect the --install-privileged-components command mentioned by @Chris_Potrebka was. Saved my day. You get an extra Kudos!

I'm not sure why Docker doesn't seem to document that from what I can tell. If it is documented, it's not easy to find. Though now that I know the term to search for, it seems to show up on a couple of threads on Docker's forum at least.

cpotrebka
New Contributor II

Thanks tones for the kudos! Greatly appreciated. 

P.S. l've consolidated my Jamf accounts down to this my original one. 🙂 

user-iZgcKItEmv
New Contributor

This seems broken again with the latest version of Docker:

Beginning on August 31, 2021, you must agree to the Docker Subscription Service Agreement to continue using Docker Desktop. Read the Blog and the Docker subscription FAQs to learn more about the changes.

Using the --install-privileged-components command doesn't bypass needing to accept the new Service Agreement. 

Any thoughts?