filevault, bootstrap tokens, secure tokens -- best approach

braillle
New Contributor III

Filevault was disabled at our organization due to issues with secure tokens. A lot of devices are in student labs, or shared between co-workers. Enabling filevault caused issues when the previous user didn't logout, or the device experienced power failure/random restart. The device was locked until the user came back and signed in. This caused problems when students wouldn't log out. The device was rendered useless. Could not deploy commands to the device. The only solution was to erase and reinstall the OS.

 

We've been told by Jamf support  Filevault is does not work well in environments with multiple users logging into devices. We have intels and M1s sprinkled throughout the company. Our Security departmnets wants this enabled, and I'm not sure where to start. 

 

What is best plan? Just create bootstrap tokens? create institutional keys? Are those two things related?

1 ACCEPTED SOLUTION

AJPinto
Honored Contributor III

JAMF Support is correct. The way Apple has FileVault setup and configured it does not do well with shared device use cases. FileVault provisioning is by user, not by system. Apple also requires user interaction to be granted a FileVault token which makes automation very difficult. Apples dream for Macs is 1:1, as far as I can tell its to maximize the number of Macs in Starbucks or something.

 

Enabling FileVault, just use the configuration profile option. That is how Apple wants it done, JAMF still says use a policy and script but that workflow is deprecated by Apple on macOS. Admin accounts on the Mac at time of FileVault enablement will just get a FileVault token. 

 

Time for the fun part. If a user does not have a FileVault token they simply cannot unlock FileVault, that is it.

  • You could create a local account to just unlock FileVault and train your uses to unlock macOS with that then switch users to their account. 
    • This option will probably be needed no matter what.
  • Granting FileVault access requires both the user/pass of a FileVault token holder and the user to be granted FileVault access (which I think is stupid, why does the user need to bless they are being given access)
    • Generally speaking this must be done manually
    • Scripts are a thing, and fdesetup does exist. I have used the script below to automate granting FileVault removing the tech from the equation. 

Using a script is not without risk, but if you want the script I used its below. You can try adjusting this old script I made to see if it works for your environment. It still requires user interaction, but removes techs from the equation as the script enters the local account user and password.

#!/bin/bash

######################
# Script Name: 
# Author: 
# Date: 
# Enhancements
# Change popup dialog
######################

######################
# Exit Codes
# 0 - Sucess: General Sucess
# 1 - Failed: Admin account credentials are not correct
# 2 - Failed: Mac not domain bound, or otherwise cannot talk to the domain controller
# 3 - Failed: User account to be cached not found in Active Directory
# 4 - Sucess: FileVault Not enabled
###################### 

echo "Begin script"

######################
# Gather and verify admin account
######################

#*------------------------ STRING DECRYPTION ------------------------*#

# Get the user and password of the local admin account to be used to pass the filevault token
# Admin user account name is stored in the JAMF Policy, but can be manually entered in line 40
# lines 31-37 are if you are encrypting the password, the password can be manually entered in line 41. 
function DecryptString() {
    echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}

Pass="some value"
Salt="some value"
DecryptString=$(DecryptString "$5" "$Salt" "$Pass") 
        

adminUser="$4"
adminPass="$DecryptString"

osvers=$(sw_vers -productVersion | awk -F. '{print $2}')
check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`

## verify that adminuser and pass variables are both passed to the user
if [[ -z "$adminUser" ]] || [[ -z "$adminPass" ]] ; then
    dialog="either Admin User or Password is missing"
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 1
fi

## check the admin password
adminCheck=$(/usr/bin/dscl /Local/Default -authonly "$adminUser" "$adminPass")
if [[ -z "$adminCheck" ]] ; then
    echo "Admin password is verified"
else
    echo "Admin Password not working"
    exit 1
fi


######################
# Check for domain bind, fails out of not bound
######################

#Remove section is not domain bound.
echo "Checking for Domain Bind"


if [ "${check4AD}" != "Active Directory" ]; then
    dialog="This machine is not bound to Active Directory.\nPlease bind to AD first. "
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 2
fi

######################
# Popups asking for user to ender userID and Password
######################

#Use Apple Script to prompt the user for their credentials to be used later in the script to authorize filevault access provision
echo "Prompting for userToAdd credentials."

## Prompt for Username
userToAdd=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your userID:" default answer "" buttons {"Continue"} default button 1)
end tell
END
)

## Prompt for Password
userPass=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
end tell
END
)

#Delete if not using domain binding.
loopCount=0
while [ "$loopCount" -lt 3 ]; do
    # Refresh Directory Services
    if [[ ${osvers} -ge 7 ]]; then
        /usr/bin/killall opendirectoryd
    else
        /usr/bin/killall DirectoryService
    fi
    sleep 15

    ## try to auth the user in advance. this seems to increase the success of the ID command.
    /usr/bin/dscl /Search -authonly "$userToAdd" "$userPass"

    adCheck=`id $userToAdd`
    echo "AD Check is: $adCheck"
    if [[ -z "$adCheck" ]] ; then
        ((loopCount++))
    else
        echo "AD Check successful"
        break
    fi
done 

######################
# Fails script if user account is not found on domain controller
######################

#Delete if not using domain binding.
if [[ -z "$adCheck" ]] ; then
    dialog="AD User Not found. Please contact the support center at 205.261.4357"
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 3
fi

sleep 2

######################
# Remove FV Access if existing
###################### 

sleep 2
sudo fdesetup remove -user $userToAdd

######################
# Provision Admin Access
###################### 

dscl . -append /groups/admin GroupMembership $userToAdd
echo "Provisioning admin access for $userToAdd."

######################
# Provision FileVault Access
###################### 

## Check to see if the encryption process is complete
encryptCheck=fdesetup status\
statusCheck=$(echo "${encryptCheck}" | grep "FileVault is On.")
expectedStatus="FileVault is On."
    if [ "${statusCheck}" != "${expectedStatus}" ]; then 
        echo "The encryption process has not completed, unable to add user at this time." echo "${encryptCheck}" exit 4
    else
        echo "Adding $userToAdd to FileVault 2 list."
    fi

sleep 5
## Get the user to be added to FV
userName=$userToAdd

## This "expect" block will populate answers for the fdesetup prompts that normally occur while hiding them from output
expect -c "
log_user 0
spawn fdesetup add -usertoadd $userName
expect \"Enter the primary user name:\"
send ${adminUser}\r
expect \"Enter the password for the user '$adminUser':\"
send ${adminPass}\r
expect \"Enter the password for the added user '$userName':\"
send ${userPass}\r
log_user 1
expect eof
"

echo "${userName} has been added to the FileVault 2 list."

######################
# Runs JAMF Recon to assign Mac to $userToAdd
###################### 

#Remove if you dont want JAMF automatically assigning devices to users
jamf recon -endUsername $userToAdd

######################
# Clean up
###################### 

echo "Script completed"


exit 0

 

View solution in original post

3 REPLIES 3

AJPinto
Honored Contributor III

JAMF Support is correct. The way Apple has FileVault setup and configured it does not do well with shared device use cases. FileVault provisioning is by user, not by system. Apple also requires user interaction to be granted a FileVault token which makes automation very difficult. Apples dream for Macs is 1:1, as far as I can tell its to maximize the number of Macs in Starbucks or something.

 

Enabling FileVault, just use the configuration profile option. That is how Apple wants it done, JAMF still says use a policy and script but that workflow is deprecated by Apple on macOS. Admin accounts on the Mac at time of FileVault enablement will just get a FileVault token. 

 

Time for the fun part. If a user does not have a FileVault token they simply cannot unlock FileVault, that is it.

  • You could create a local account to just unlock FileVault and train your uses to unlock macOS with that then switch users to their account. 
    • This option will probably be needed no matter what.
  • Granting FileVault access requires both the user/pass of a FileVault token holder and the user to be granted FileVault access (which I think is stupid, why does the user need to bless they are being given access)
    • Generally speaking this must be done manually
    • Scripts are a thing, and fdesetup does exist. I have used the script below to automate granting FileVault removing the tech from the equation. 

Using a script is not without risk, but if you want the script I used its below. You can try adjusting this old script I made to see if it works for your environment. It still requires user interaction, but removes techs from the equation as the script enters the local account user and password.

#!/bin/bash

######################
# Script Name: 
# Author: 
# Date: 
# Enhancements
# Change popup dialog
######################

######################
# Exit Codes
# 0 - Sucess: General Sucess
# 1 - Failed: Admin account credentials are not correct
# 2 - Failed: Mac not domain bound, or otherwise cannot talk to the domain controller
# 3 - Failed: User account to be cached not found in Active Directory
# 4 - Sucess: FileVault Not enabled
###################### 

echo "Begin script"

######################
# Gather and verify admin account
######################

#*------------------------ STRING DECRYPTION ------------------------*#

# Get the user and password of the local admin account to be used to pass the filevault token
# Admin user account name is stored in the JAMF Policy, but can be manually entered in line 40
# lines 31-37 are if you are encrypting the password, the password can be manually entered in line 41. 
function DecryptString() {
    echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}

Pass="some value"
Salt="some value"
DecryptString=$(DecryptString "$5" "$Salt" "$Pass") 
        

adminUser="$4"
adminPass="$DecryptString"

osvers=$(sw_vers -productVersion | awk -F. '{print $2}')
check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`

## verify that adminuser and pass variables are both passed to the user
if [[ -z "$adminUser" ]] || [[ -z "$adminPass" ]] ; then
    dialog="either Admin User or Password is missing"
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 1
fi

## check the admin password
adminCheck=$(/usr/bin/dscl /Local/Default -authonly "$adminUser" "$adminPass")
if [[ -z "$adminCheck" ]] ; then
    echo "Admin password is verified"
else
    echo "Admin Password not working"
    exit 1
fi


######################
# Check for domain bind, fails out of not bound
######################

#Remove section is not domain bound.
echo "Checking for Domain Bind"


if [ "${check4AD}" != "Active Directory" ]; then
    dialog="This machine is not bound to Active Directory.\nPlease bind to AD first. "
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 2
fi

######################
# Popups asking for user to ender userID and Password
######################

#Use Apple Script to prompt the user for their credentials to be used later in the script to authorize filevault access provision
echo "Prompting for userToAdd credentials."

## Prompt for Username
userToAdd=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your userID:" default answer "" buttons {"Continue"} default button 1)
end tell
END
)

## Prompt for Password
userPass=$(/usr/bin/osascript<<END
tell application "System Events"
activate
set the answer to text returned of (display dialog "Enter your Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
end tell
END
)

#Delete if not using domain binding.
loopCount=0
while [ "$loopCount" -lt 3 ]; do
    # Refresh Directory Services
    if [[ ${osvers} -ge 7 ]]; then
        /usr/bin/killall opendirectoryd
    else
        /usr/bin/killall DirectoryService
    fi
    sleep 15

    ## try to auth the user in advance. this seems to increase the success of the ID command.
    /usr/bin/dscl /Search -authonly "$userToAdd" "$userPass"

    adCheck=`id $userToAdd`
    echo "AD Check is: $adCheck"
    if [[ -z "$adCheck" ]] ; then
        ((loopCount++))
    else
        echo "AD Check successful"
        break
    fi
done 

######################
# Fails script if user account is not found on domain controller
######################

#Delete if not using domain binding.
if [[ -z "$adCheck" ]] ; then
    dialog="AD User Not found. Please contact the support center at 205.261.4357"
    echo "$dialog"
    cmd="Tell app \"System Events\" to display dialog \"$dialog\""
    /usr/bin/osascript -e "$cmd"
    exit 3
fi

sleep 2

######################
# Remove FV Access if existing
###################### 

sleep 2
sudo fdesetup remove -user $userToAdd

######################
# Provision Admin Access
###################### 

dscl . -append /groups/admin GroupMembership $userToAdd
echo "Provisioning admin access for $userToAdd."

######################
# Provision FileVault Access
###################### 

## Check to see if the encryption process is complete
encryptCheck=fdesetup status\
statusCheck=$(echo "${encryptCheck}" | grep "FileVault is On.")
expectedStatus="FileVault is On."
    if [ "${statusCheck}" != "${expectedStatus}" ]; then 
        echo "The encryption process has not completed, unable to add user at this time." echo "${encryptCheck}" exit 4
    else
        echo "Adding $userToAdd to FileVault 2 list."
    fi

sleep 5
## Get the user to be added to FV
userName=$userToAdd

## This "expect" block will populate answers for the fdesetup prompts that normally occur while hiding them from output
expect -c "
log_user 0
spawn fdesetup add -usertoadd $userName
expect \"Enter the primary user name:\"
send ${adminUser}\r
expect \"Enter the password for the user '$adminUser':\"
send ${adminPass}\r
expect \"Enter the password for the added user '$userName':\"
send ${userPass}\r
log_user 1
expect eof
"

echo "${userName} has been added to the FileVault 2 list."

######################
# Runs JAMF Recon to assign Mac to $userToAdd
###################### 

#Remove if you dont want JAMF automatically assigning devices to users
jamf recon -endUsername $userToAdd

######################
# Clean up
###################### 

echo "Script completed"


exit 0

 

braillle
New Contributor III

Thanks for this! I will test the script ASAP. I have found that the local admin account that gets created during the enrollment process receives the bootstrap token. Anyone who logs in after that receives a secure token. This means, anyone with the secure token and input their credentials and get the Mac OS back to the Jamf Connect login window in the event of a power failure or restart. 

AJPinto
Honored Contributor III

If the devices power up directly to the JAMF Connect login window then FileVault is not enabled. 

 

The first account on a Mac must be an admin account and will get a FileVault token automatically. Beyond that its really up to how the account is created and what permissions it has (ie admin) on if it will automatically get a FileVault Token. JAMF connect can also be configured to grant FileVault access if it has access to an account with a FileVault token.

 

The script I shared is a bit old, but it still works. You will see references to password encryption in there. That stuff can be removed and just hard code the user name and password to get it up and going, I put comments in the script to cover this. Good luck with FileVault, it can be a beast.