Script pour créer des jetons sécurisés pour macOS : Un guide pour les professionnels de l’informatique

Dans le monde informatique actuel, la gestion des comptes d’utilisateurs et la garantie d’un accès sécurisé sont essentielles au maintien d’une solide sécurité des systèmes. L’un des aspects clés de cette gestion sur macOS est l’utilisation de jetons sécurisés. Les jetons sécurisés sont essentiels pour diverses fonctions de sécurité, notamment l’activation de FileVault et l’exécution de certaines tâches administratives.

Ce billet de blog se penche sur un script qui automatise le processus d’octroi d’un accès sécurisé par jeton aux comptes d’utilisateurs sur macOS, en expliquant son importance, sa fonctionnalité et ses cas d’utilisation pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP).

Contexte

Les jetons sécurisés sont une fonctionnalité de sécurité de macOS qui fournit des mesures d’authentification supplémentaires, en particulier lorsqu’il s’agit du chiffrement FileVault. Pour les professionnels de l’informatique et les MSP, la gestion de ces jetons est essentielle pour maintenir des environnements sécurisés sur de nombreux appareils.

Le script fourni simplifie le processus d’octroi d’un accès par jeton sécurisé à un compte d’utilisateur, et même la création du compte s’il n’existe pas encore. Cette automatisation est particulièrement utile dans les environnements à grande échelle où la configuration manuelle serait peu pratique et prendrait beaucoup de temps.

Le script

#!/usr/bin/env bash
# Description: Grants secure token access to Service Account. Account will be created if it doesn't exist. Service Accounts will not show up at the desktop login.
# Release Notes: Initial Release
#
# Custom Fields:
#  New Account Password Custom Field: A secure custom field that stores the password for the new user account.
#  Optional Authentication Account Username Custom Field: A secure custom field that stores the username of the admin account that has secure token already on the device.
#
# Parameters:
#  username: Username to grant secure token access to
#  password: Password of user to grant secure token access to
#  adminuser: (Optional) Secure token Admin username - leave blank to prompt local user
#  adminpassword: (Optional) Secure token Admin password - leave blank to prompt local user
#
# Usage: ./Create-SecureTokenAccount.sh <-u|--username <arg>> <-p|--password <arg>> [-a|--adminuser <arg>] [-d|--adminpassword <arg>]
# <> are required
# [] are optional
# Example: ./Create-SecureTokenAccount.sh --username test --password Password1 --adminuser admin --adminpassword Password2
#
# Notes:
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#
#

die() {
    local _ret="${2:-1}"
    test "${_PRINT_HELP:-no}" = yes && print_help >&2
    echo "$1" >&2
    exit "${_ret}"
}

begins_with_short_option() {
    local first_option all_short_options='upadvh'
    first_option="${1:0:1}"
    test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}

GetCustomField() {
    customfieldName=$1
    dataPath=$(printenv | grep -i NINJA_DATA_PATH | awk -F = '{print $2}')
    value=""
    if [ -e "${dataPath}/ninjarmm-cli" ]; then
        value=$("${dataPath}"/ninjarmm-cli get "$customfieldName")
    else
        value=$(/Applications/NinjaRMMAgent/programdata/ninjarmm-cli get "$customfieldName")
    fi
    if [[ "${value}" == *"Unable to find the specified field"* ]]; then
        echo ""
        return 1
    else
        echo "$value"
    fi
}

# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_username=
_arg_password=
_arg_adminuser=
_arg_adminpassword=

print_help() {
    printf '%s\n' "Grants secure token access to an account. Account will be created if it doesn't exist."
    printf 'Usage: %s <-u|--username <arg>> <-p|--password <arg>> [-a|--adminuser <arg>] [-d|--adminpassword <arg>] [-h|--help]\n' "$0"
    printf '\t%s\n' "-u, --username: Username to grant secure token access to. (Required)"
    printf '\t%s\n' "-p, --password: Password of user to grant secure token access to. (Required)"
    printf '\t%s\n' "-a, --adminuser: (Optional) Secure token Admin username. (Leave blank to prompt local user)"
    printf '\t%s\n' "-d, --adminpassword: (Optional) Secure token Admin password. (Leave blank to prompt local user)"
    printf '\t%s\n' "-h, --help: Prints help"
}

parse_commandline() {
    while test $# -gt 0; do
        _key="$1"
        case "$_key" in
        -u | --username)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_username="$2"
            shift
            ;;
        --username=*)
            _arg_username="${_key##--username=}"
            ;;
        -u*)
            _arg_username="${_key##-u}"
            ;;
        -p | --password)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_password="$2"
            shift
            ;;
        --password=*)
            _arg_password="${_key##--password=}"
            ;;
        -p*)
            _arg_password="${_key##-p}"
            ;;
        -a | --adminuser)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_adminuser="$2"
            shift
            ;;
        --adminuser=*)
            _arg_adminuser="${_key##--adminuser=}"
            ;;
        -a*)
            _arg_adminuser="${_key##-a}"
            ;;
        -d | --adminpassword)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_adminpassword="$2"
            shift
            ;;
        --adminpassword=*)
            _arg_adminpassword="${_key##--adminpassword=}"
            ;;
        -d*)
            _arg_adminpassword="${_key##-d}"
            ;;
        -h | --help)
            print_help
            exit 0
            ;;
        -h*)
            print_help
            exit 0
            ;;
        *)
            _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1
            ;;
        esac
        shift
    done
}

parse_commandline "$@"

# Get Script Variables and override parameters
if [[ -n $(printenv | grep -i newAccountUsername | awk -F = '{print $2}') ]]; then
    _arg_username=$(printenv | grep -i newAccountUsername | awk -F = '{print $2}')
fi
if [[ -n $(printenv | grep -i newAccountPasswordCustomField | awk -F = '{print $2}') ]]; then
    # Get the password from the custom field
    if ! _arg_password=$(GetCustomField "$(printenv | grep -i newAccountPasswordCustomField | awk -F = '{print $2}')"); then
        # Exit if the custom field is empty
        if [[ -z "${_arg_password}" ]]; then
            echo "[Error] Custom Field ($(printenv | grep -i newAccountPasswordCustomField | awk -F = '{print $2}')) was not found. Please check that the custom field contains a password."
            exit 1
        fi
        # Exit if the custom field is not found
        echo "[Error] Custom Field ($(printenv | grep -i newAccountPasswordCustomField | awk -F = '{print $2}')) was not found. Please check the custom field name."
        exit 1
    fi
fi
if [[ -n $(printenv | grep -i optionalAuthenticationAccountUsername | awk -F = '{print $2}') ]]; then
    _arg_adminuser=$(printenv | grep -i optionalAuthenticationAccountUsername | awk -F = '{print $2}')
fi
if [[ -n $(printenv | grep -i optionalAuthenticationAccountPasswordCustomField | awk -F = '{print $2}') ]]; then
    # Get the password from the custom field
    if ! _arg_adminpassword=$(GetCustomField "$(printenv | grep -i optionalAuthenticationAccountPasswordCustomField | awk -F = '{print $2}')"); then
        # Exit if the custom field is empty
        if [[ -z "${_arg_adminpassword}" ]]; then
            echo "[Error] Custom Field ($(printenv | grep -i optionalAuthenticationAccountPasswordCustomField | awk -F = '{print $2}')) was not found. Please check that the custom field contains a password."
            exit 1
        fi
        # Exit if the custom field is not found
        echo "[Error] Custom Field ($(printenv | grep -i optionalAuthenticationAccountPasswordCustomField | awk -F = '{print $2}')) was not found. Please check the custom field name."
        exit 1
    fi
fi

# If both username and password are empty
if [[ -z "${_arg_username}" ]]; then
    echo "[Error] User Name is required."
    if [[ -z "${_arg_password}" ]]; then
        echo "[Error] Password is required, please set the password in the secure custom field."
    fi
    exit 1
fi

# If username is not empty and password is empty
if [[ -n "${_arg_username}" ]] && [[ -z "${_arg_password}" ]]; then
    echo "[Error] Password is required, please set the password in the secure custom field."
    exit 1
fi

# If username is not empty and password is empty
if [[ -n "${_arg_adminuser}" ]] && [[ -z "${_arg_adminpassword}" ]]; then
    echo "[Error] Password is required, please set the password in the secure custom field."
    exit 1
fi

UserAccount=$_arg_username
UserPass=$_arg_password
UserFullName="ServiceAccount"
secureTokenAdmin=$_arg_adminuser
secureTokenAdminPass=$_arg_adminpassword
macOSVersionMajor=$(sw_vers -productVersion | awk -F . '{print $1}')
macOSVersionMinor=$(sw_vers -productVersion | awk -F . '{print $2}')
macOSVersionBuild=$(sw_vers -productVersion | awk -F . '{print $3}')

# Check script prerequisites.

# Exits if macOS version predates the use of SecureToken functionality.
# Exit if macOS < 10.
if [ "$macOSVersionMajor" -lt 10 ]; then
    echo "[Warn] macOS version ${macOSVersionMajor} predates the use of SecureToken functionality, no action required."
    exit 0
# Exit if macOS 10 < 10.13.4.
elif [ "$macOSVersionMajor" -eq 10 ]; then
    if [ "$macOSVersionMinor" -lt 13 ]; then
        echo "[Warn] macOS version ${macOSVersionMajor}.${macOSVersionMinor} predates the use of SecureToken functionality, no action required."
        exit 0
    elif [ "$macOSVersionMinor" -eq 13 ] && [ "$macOSVersionBuild" -lt 4 ]; then
        echo "[Warn] macOS version ${macOSVersionMajor}.${macOSVersionMinor}.${macOSVersionBuild} predates the use of SecureToken functionality, no action required."
        exit 0
    fi
fi

# Exits if $UserAccount already has SecureToken.
if sysadminctl -secureTokenStatus "$UserAccount" 2>&1 | grep -q "ENABLED"; then
    echo "${UserAccount} already has a SecureToken. No action required."
    exit 0
fi

# Exits with error if $secureTokenAdmin does not have SecureToken
# (unless running macOS 10.15 or later, in which case exit with explanation).

if [ -n "$secureTokenAdmin" ]; then
    if sysadminctl -secureTokenStatus "$secureTokenAdmin" 2>&1 | grep -q "DISABLED"; then
        if [ "$macOSVersionMajor" -gt 10 ] || [ "$macOSVersionMajor" -eq 10 ] && [ "$macOSVersionMinor" -gt 14 ]; then
            echo "[Warn] Neither ${secureTokenAdmin} nor ${UserAccount} has a SecureToken, but in macOS 10.15 or later, a SecureToken is automatically granted to the first user to enable FileVault (if no other users have SecureToken), so this may not be necessary. Try enabling FileVault for ${UserAccount}. If that fails, see what other user on the system has SecureToken, and use its credentials to grant SecureToken to ${UserAccount}."
            exit 0
        else
            echo "[Error] ${secureTokenAdmin} does not have a valid SecureToken, unable to proceed. Please update to another admin user with SecureToken."
            exit 1
        fi
    else
        echo "[Info] Verified ${secureTokenAdmin} has SecureToken."
    fi
fi

# Creates a new user account.
create_user() {
    # Check if the user account exists
    if id "$1" >/dev/null 2>&1; then
        echo "[Info] Found existing user account $1."
    else
        echo "[Warn] Account $1 doesn't exist. Attempting to create..."
        # Create a new user
        dscl . -create /Users/"$1"
        # Add the display name of the User
        dscl . -create /Users/"$1" RealName "$3"
        # Replace password_here with your desired password to set the password for this user
        dscl . -passwd /Users/"$1" "$2"
        # Set the Unique ID for the New user. Replace with a number that is not already taken.
        LastID=$(dscl . -list /Users UniqueID | sort -nr -k 2 | head -1 | grep -oE '[0-9]+$')
        NextID=$((LastID + 1))
        dscl . -create /Users/"$1" UniqueID $NextID
        # Set the group ID for the user
        dscl . -create /Users/"$1" PrimaryGroupID 20
        # Append the User with admin privilege. If this line is not included the user will be set as standard user.
        # sudo dscl . -append /Groups/admin GroupMembership "$1"
        echo "[Info] Account $1 created."
    fi
}
# Adds SecureToken to target user.
securetoken_add() {
    if [ -n "$3" ]; then
        # Admin user name was given. Do not prompt the user.
        sysadminctl \
            -secureTokenOn "$1" \
            -password "$2" \
            -adminUser "$3" \
            -adminPassword "$4"
    else
        # Admin user name was not given. Prompt the local user.
        currentUser=$(stat -f%Su /dev/console)
        currentUserUID=$(id -u "$currentUser")
        launchctl asuser "$currentUserUID" sudo -iu "$currentUser" \
            sysadminctl \
            -secureTokenOn "$1" \
            -password "$2" \
            interactive
    fi
    # Verify successful SecureToken add.
    secureTokenCheck=$(sysadminctl -secureTokenStatus "${1}" 2>&1)
    if echo "$secureTokenCheck" | grep -q "DISABLED"; then
        echo "[Error] Failed to add SecureToken to ${1}. Please rerun policy; if issue persists, a manual SecureToken add will be required to continue."
        exit 126
    elif echo "$secureTokenCheck" | grep -q "ENABLED"; then
        echo "[Info] Successfully added SecureToken to ${1}."
    else
        echo "[Error] Unexpected result, unable to proceed. Please rerun policy; if issue persists, a manual SecureToken add will be required to continue."
        exit 1
    fi
}

# Create new user if it doesn't already exist.
create_user "$UserAccount" "$UserPass" "$UserFullName"
# Add SecureToken using provided credentials.
securetoken_add "$UserAccount" "$UserPass" "$secureTokenAdmin" "$secureTokenAdminPass"

 

Description détaillée

Vue d’ensemble du script

Le script en question est conçu pour accorder un accès sécurisé à un compte d’utilisateur sur macOS, avec la possibilité de créer le compte s’il n’existe pas encore. Voici une description détaillée, étape par étape, du fonctionnement du script :

  1. Analyse des paramètres: Le script commence par définir une fonction die pour gérer les erreurs et une fonction print_help pour afficher les informations d’utilisation. Il analyse ensuite les arguments de la ligne de commande pour extraire le nom d’utilisateur, le mot de passe et, éventuellement, le nom d’utilisateur et le mot de passe de l’administrateur.
  2. Variables d’environnement: Il vérifie la présence de variables d’environnement susceptibles de remplacer les paramètres de la ligne de commande. Si des variables d’environnement spécifiques sont définies, le script récupère leurs valeurs pour les utiliser comme paramètres.
  3. vérification de la version de macOS: Le script vérifie la version de macOS pour s’assurer qu’elle prend en charge la fonctionnalité des jetons sécurisés. Il s’arrête si la version de macOS est trop ancienne pour utiliser des jetons sécurisés.
  4. Vérification de l’état du jeton sécurisé: Il vérifie si le compte d’utilisateur spécifié dispose déjà d’un jeton sécurisé. Si le compte d’utilisateur possède déjà un jeton sécurisé, le script se termine, car aucune autre action n’est nécessaire.
  5. Vérification du jeton de l’utilisateur Admin : Si un nom d’utilisateur administrateur est fourni, le script vérifie que cet utilisateur dispose d’un jeton sécurisé. Si ce n’est pas le cas, il se termine par une erreur, sauf si la version de macOS est la 10.15 ou une version ultérieure, où il est recommandé d’utiliser un autre processus.
  6. Création d’un compte utilisateur: Le script comprend une fonction permettant de créer un nouveau compte utilisateur s’il n’existe pas déjà. Il attribue un identifiant unique, définit un mot de passe et configure d’autres attributs nécessaires.
  7. Octroi d’un jeton sécurisé: Le script tente d’accorder un jeton sécurisé au compte d’utilisateur spécifié à l’aide des informations d’identification fournies. Si le nom d’utilisateur de l’administrateur est fourni, il utilise ces informations d’identification ; sinon, il demande à l’utilisateur local de s’authentifier.

Cas d’utilisation potentiels

Imaginez un professionnel de l’informatique nommé Alex qui gère un parc d’appareils macOS pour le compte d’une grande entreprise. Alex doit s’assurer que tous les comptes utilisateurs sur ces appareils disposent de jetons sécurisés pour le chiffrement FileVault. La vérification et l’octroi manuels de jetons sécurisés sur chaque appareil prendraient énormément de temps.

En déployant ce script à l’aide d’un outil de gestion centralisé, Alex peut automatiser le processus et s’assurer que tous les comptes d’utilisateurs de l’entreprise disposent des jetons sécurisés nécessaires, ce qui permet de maintenir la conformité avec les politiques de sécurité de l’entreprise.

Comparaisons

Les autres méthodes d’octroi de jetons sécurisés impliquent généralement une intervention manuelle dans les préférences système de macOS ou l’utilisation de commandes sysadminctl pour chaque utilisateur. Bien que ces méthodes fonctionnent, elles ne permettent pas de gérer un grand nombre d’appareils. Le script automatise ces étapes, ce qui les rend plus efficaces et réduit la probabilité d’une erreur humaine.

FAQ

  • Que se passe-t-il si le compte d’utilisateur existe déjà ?

    Le script vérifie l’existence du compte d’utilisateur et saute l’étape de création s’il existe déjà.

  • Puis-je utiliser ce script sur des versions plus anciennes de macOS ?

    Le script inclut des vérifications pour s’assurer qu’il ne s’exécute que sur les versions de macOS qui prennent en charge les jetons sécurisés, à savoir macOS 10.13.4 et les versions ultérieures.

  • Que se passe-t-il si l’utilisateur administrateur n’a pas de jeton sécurisé ?

    Le script se termine par une erreur si l’utilisateur admin n’a pas de jeton sécurisé, sauf sous macOS 10.15 ou plus récent, où un processus alternatif est suggéré.

Implications

L’attribution de jetons sécurisés aux comptes d’utilisateurs est essentielle pour activer FileVault et effectuer des tâches administratives en toute sécurité. L’automatisation de ce processus permet de maintenir des normes de sécurité élevées, de garantir la conformité avec les politiques de l’entreprise et de réduire le risque d’accès non autorisé.

Recommandations

  • Mettre régulièrement à jour le script: Veiller à ce que le script soit tenu à jour des dernières modifications apportées à macOS et des pratiques de sécurité.
  • Champs personnalisés sécurisés: Utilisez des champs personnalisés sécurisés pour stocker des informations sensibles telles que les mots de passe.
  • Gestion centralisée: Déployer le script à l’aide d’un outil de gestion centralisé afin de garantir la cohérence entre tous les appareils.

Conclusion

L’automatisation du processus d’octroi de jetons sécurisés à l’aide de ce script améliore considérablement l’efficacité et la sécurité de la gestion des appareils macOS. Pour les professionnels de l’informatique et les MSP, ce script est un outil précieux pour maintenir des pratiques de sécurité solides.

NinjaOne propose des solutions complètes qui s’intègrent parfaitement à ces scripts, offrant ainsi une approche complète de la gestion et de la sécurité informatique. En tirant parti de NinjaOne, vous pouvez optimiser vos flux de travail et vous assurer que tous vos appareils sont sécurisés et conformes aux politiques de votre entreprise.

Pour aller plus loin

Pour créer une équipe informatique efficace et performante, il est essentiel d'avoir une solution centralisée qui joue le rôle de nœud principal pour vos services. NinjaOne permet aux équipes informatiques de surveiller, gérer, sécuriser et prendre en charge tous les appareils, où qu'ils soient, sans avoir besoin d'une infrastructure complexe sur site. Pour en savoir plus sur NinjaOne Endpoint Management, participez à une visite guidée, ou profitez d'un essai gratuit de la plateforme NinjaOne.

Catégories :

Vous pourriez aussi aimer

×

Voir NinjaOne en action !

En soumettant ce formulaire, j'accepte la politique de confidentialité de NinjaOne.

Termes et conditions NinjaOne

En cliquant sur le bouton “J’accepte” ci-dessous, vous indiquez que vous acceptez les termes juridiques suivants ainsi que nos conditions d’utilisation:

  • Droits de propriété: NinjaOne possède et continuera de posséder tous les droits, titres et intérêts relatifs au script (y compris les droits d’auteur). NinjaOne vous accorde une licence limitée pour l’utilisation du script conformément à ces conditions légales.
  • Limitation de l’utilisation: Les scripts ne peuvent être utilisés qu’à des fins personnelles ou professionnelles internes légitimes et ne peuvent être partagés avec d’autres entités.
  • Interdiction de publication: Vous n’êtes en aucun cas autorisé à publier le script dans une bibliothèque de scripts appartenant à, ou sous le contrôle d’un autre fournisseur de logiciels.
  • Clause de non-responsabilité: Le texte est fourni “tel quel” et “tel que disponible”, sans garantie d’aucune sorte. NinjaOne ne promet ni ne garantit que le script sera exempt de défauts ou qu’il répondra à vos besoins ou attentes particulières.
  • Acceptation des risques: L’utilisation du script est sous votre propre responsabilité. Vous reconnaissez qu’il existe certains risques inhérents à l’utilisation du script, et vous comprenez et assumez chacun de ces risques.
  • Renonciation et exonération de responsabilité: Vous ne tiendrez pas NinjaOne pour responsable des conséquences négatives ou involontaires résultant de votre utilisation du script, et vous renoncez à tout droit ou recours légal ou équitable que vous pourriez avoir contre NinjaOne en rapport avec votre utilisation du script.
  • EULA: Si vous êtes un client de NinjaOne, votre utilisation du script est soumise au contrat de licence d’utilisateur final qui vous est applicable (End User License Agreement (EULA)).