From c61ea7e5cd3476c6e9eb6aa483f61f26440a2ba4 Mon Sep 17 00:00:00 2001 From: Dave Siederer <113131122+ds0x@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:51:24 -0500 Subject: [PATCH] Create aws-ec2-mac-setup.sh (#35217) Script to run during the first launch of an AWS EC2 Mac instance to make it easier to set up the Amazon Machine Image (AMI). Uses data from https://github.com/aws-samples/amazon-ec2-mac-mdm-enrollment-automation/blob/main/Secret_SecretsManager_CF.yaml that the AWS instance accesses at runtime. Co-authored-by: Brock Walters <153771548+nonpunctual@users.noreply.github.com> --- .../macos/scripts/aws-ec2-mac-setup.sh | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 docs/solutions/macos/scripts/aws-ec2-mac-setup.sh diff --git a/docs/solutions/macos/scripts/aws-ec2-mac-setup.sh b/docs/solutions/macos/scripts/aws-ec2-mac-setup.sh new file mode 100644 index 0000000000..708521faf9 --- /dev/null +++ b/docs/solutions/macos/scripts/aws-ec2-mac-setup.sh @@ -0,0 +1,136 @@ +#!/bin/bash + +# This script is to set up an AWS EC2 Mac instance with auto-login for MDM enrollment. +# Paste this script into the "User data" field when launching your EC2 Mac instance. +# Once launched, connect via VNC or Apple Screen Sharing to accept the permissions prompts. +# Once the prompts are accepted, after clicking OK, create the image: +# In the AWS console, go to EC2, click the instance in the list, then click Image and templates -> Create image. +# Launching new instances from this AMI will automatically enroll them into MDM. + +# Set the below to your AWS Secrets Manager secret containing credentials. +# Credential block template available at enroll-ec2-mac repo. This secret name will also be written to the image for enrollment as part of this script. +credentialID="SET-TO-YOUR-SECRETS-MANAGER-SECRET-NAME" + +# Path prefix for AWS CLI. +PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/opt/homebrew/sbin" + +# JSONVoorhees: made from code by Matthew Warren, under MIT license. +# https://macblog.org/parse-json-command-line-mac/ +function jsonParse() ( +JSONVar="${1}" +INCOMINGDATA="${2}" +JSONReturn=$( osascript -l 'JavaScript' <<< "function run() { var jsoninfo = JSON.parse(\`$INCOMINGDATA\`) ; return jsoninfo.$JSONVar;}" ) +echo "${JSONReturn}" +) + +# The below retry function is used for AWS Secrets Manager retrieval only. +function retry() { +local n max waitFor +n=1 +max=5 +waitFor=15 +while true; do +"${@}" && break || { + if [[ "${n}" -lt "${max}" ]]; then + ((n++)) + echo "Command failed. Attempt ${n}/${max}:" >&2; + sleep "${waitFor}"; + else + echo "The command has failed after ${n} attempts." ; exit 111 + fi +} +done +} + +### Metadata token for authorization to retrieve data from local EC2 Mac instance, +MDToken=$(curl -X PUT "http://169.254.169.254/latest/api/token" -s -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") + +### Get current AWS region from running instance metadata. +### If Secrets Manager secret is in a different region, uncomment below to set a static region. +currentRegion=$(curl -H "X-aws-ec2-metadata-token: $MDToken" -s http://169.254.169.254/latest/meta-data/placement/region) +# currentRegion="us-east-1" + +# Retrieves credentials from AWS Secrets Manager. To set statically, comment out credentialBlock and set EBSAdminUser and EBSAdminPassword. +credentialBlock=$(retry aws secretsmanager get-secret-value --region "$currentRegion" --secret-id "$credentialID" --query SecretString --output text) + +# EBSAdminUser is "ec2-user" by default. If another account is named, it will be created (as an administrator). +EBSAdminUser=$(jsonParse "localAdmin" "$credentialBlock") +EBSAdminPassword=$(jsonParse "localAdminPassword" "$credentialBlock") + +function createUserAccount () ( + userToCreate="${1}" + userPassword="${2}" + userID="${3}" + sudo /usr/sbin/sysadminctl -addUser "$userToCreate" -fullName "$userToCreate" -UID "$userID" -GID 80 -shell /bin/zsh -password "$userPassword" -home "/Users/$userToCreate" + sudo /usr/sbin/createhomedir -c -u "$userToCreate" +) + +function kcpasswordEncode () ( + thisString="${1}" + cipherHex_array=( 7D 89 52 23 D2 BC DD EA A3 B9 1F ) + thisStringHex_array=( $(/bin/echo -n "${thisString}" | xxd -p -u | sed 's/../& /g') ) + if [ "${#thisStringHex_array[@]}" -lt 12 ]; then + padding=$(( 12 - ${#thisStringHex_array[@]} )) + elif [ "$(( ${#thisStringHex_array[@]} % 12 ))" -ne 0 ]; then + padding=$(( (12 - ${#thisStringHex_array[@]} % 12) )) + else + padding=12 + fi + for ((i=0; i < $(( ${#thisStringHex_array[@]} + ${padding})); i++)); do + charHex_cipher=${cipherHex_array[$(( $i % 11 ))]} + + charHex=${thisStringHex_array[$i]} + printf "%02X" "$(( 0x${charHex_cipher} ^ 0x${charHex:-00} ))" | xxd -r -p > /dev/stdout + done +) + +# If account exists, do not create it. +if ( dscl . -list /Users | grep -q "$EBSAdminUser" ); then +echo "$EBSAdminUser account already exists." +else +# Creates and elevates account to admin. +highestUID=$(dscl . -list /Users UniqueID | sort -nr -k 2 | head -1 | grep -oE '[0-9]+$') +((newUserUID=highestUID+1)) +echo "Creating $EBSAdminUser account (UID $newUserUID)." +createUserAccount "$EBSAdminUser" "$EBSAdminPassword" $newUserUID +sudo /usr/bin/dscl . -append /Groups/admin GroupMembership "$EBSAdminUser" +fi + +# Sets password for user account using variables above. +echo "Setting password for $EBSAdminUser account." +sudo /usr/bin/dscl . -passwd "/Users/$EBSAdminUser" "$EBSAdminPassword" + +# Invisible directory for staging. +stagingDir="/Users/Shared/._ec2-auto-login" +sudo mkdir -p "$stagingDir" +sudo chown 501:20 "$stagingDir" +sudo chmod -R 775 "$stagingDir" + + +# Enable auto-login for user. +sudo defaults write "/Library/Preferences/com.apple.loginwindow" autoLoginUser "$EBSAdminUser" + +# Set name of Secret for enroll-ec2-mac script to run. +sudo defaults write "/Users/$EBSAdminUser/Library/Preferences/com.amazon.dsx.ec2.enrollment.automation" MMSecret "$credentialID" +sudo chown $EBSAdminUser:staff "/Users/$EBSAdminUser/Library/Preferences/com.amazon.dsx.ec2.enrollment.automation.plist" + +kcpasswordEncode "$EBSAdminPassword" > "$stagingDir/kcpassword" +sudo cp "$stagingDir/kcpassword" "/etc/" +sudo chown root:wheel "/etc/kcpassword" +sudo chmod u=rw,go= "/etc/kcpassword" + +# Downloads and installs the latest enroll-ec2-mac.scpt, including loading the LaunchAgent for setup. +sudo curl -H 'Accept: application/vnd.github.v3.raw' https://api.github.com/repos/aws-samples/amazon-ec2-mac-mdm-enrollment-automation/contents/enroll-ec2-mac.scpt | sudo tee "/Users/Shared/enroll-ec2-mac.scpt" > /dev/null ; sudo chmod +x "/Users/Shared/enroll-ec2-mac.scpt"; osascript "/Users/Shared/enroll-ec2-mac.scpt" --setup && echo "Setup Done" || echo "Setup Not Done" + +# Enable Screen Sharing for remote GUI connection. +sudo launchctl enable system/com.apple.screensharing ; sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.screensharing.plist + +# Sets a flag to prevent script from attempting to run twice. +if [ -f "$stagingDir/.userSetupComplete" ]; then +# Clean up auto-login database. +rm -rf "$stagingDir/kcpassword" +sleep 1 +else +touch "$stagingDir/.userSetupComplete" +sudo launchctl reboot +fi