We’re enforcing Azure Entra authentication across all Linux VMs, so we’ll disable all local accounts via a custom script. The script will also create a single "break-glass" user with a randomly generated password that remains unknown. If anyone ever needs to use local credentials, they must use the password-reset tool from VM help section to set a new password for that account before logging in.
I’m using the script below, and in my testing it’s worked exactly as intended with no unexpected behavior. Since I’m not a Linux expert, I’d appreciate any feedback on potential issues or best practices I should consider.
I intend to block all local authentication, permitting password-based access solely for the break-glass user.
#!/usr/bin/env bash
set -euo pipefail
# Configuration
CFG="/etc/ssh/sshd_config"
BAK="${CFG}.bak"
BKP_USER="breakglassuser"
NOLOGIN="$(command -v nologin || echo '/sbin/nologin')"
# 1) Create (or unlock) the break‐glass user with a bash shell
if ! id -u "$BKP_USER" &>/dev/null; then
PW="$(openssl rand -base64 32)"
useradd -m -s /bin/bash "$BKP_USER"
echo "$BKP_USER:$PW" | chpasswd
fi
usermod -U "$BKP_USER"
usermod -s /bin/bash "$BKP_USER"
# 2) Backup sshd_config (only once)
if [ ! -f "$BAK" ]; then
cp "$CFG" "$BAK"
fi
# 3) Disable password & challenge-response authentication globally
if grep -qE '^[[:space:]]*#?[[:space:]]*PasswordAuthentication' "$CFG"; then
sed -i -E 's@^[[:space:]]*#?[[:space:]]*PasswordAuthentication.*@PasswordAuthentication no@' "$CFG"
else
echo 'PasswordAuthentication no' >> "$CFG"
fi
if grep -qE '^[[:space:]]*#?[[:space:]]*ChallengeResponseAuthentication' "$CFG"; then
sed -i -E 's@^[[:space:]]*#?[[:space:]]*ChallengeResponseAuthentication.*@ChallengeResponseAuthentication no@' "$CFG"
else
echo 'ChallengeResponseAuthentication no' >> "$CFG"
fi
# 4) Ensure only bkupadmin can use password auth
# Remove any old exception block and append the new one
sed -i '/^Match User bkupadmin/,$d' "$CFG"
cat >> "$CFG" <<EOF
Match User $BKP_USER
PasswordAuthentication yes
EOF
# 5) Restart SSH to apply changes
if command -v systemctl &>/dev/null; then
systemctl restart sshd || systemctl restart ssh
else
service ssh restart || service sshd restart
fi
# 6) Lock & nologin all other local accounts (UID 1000–59999) except bkupadmin
awk -F: -v skip="$BKP_USER" '(3ドル>=1000 && 3ドル<60000 && 1ドル!=skip){print 1ドル}' /etc/passwd | while read -r user; do
passwd -l "$user"
usermod -s "$NOLOGIN" "$user"
done
echo "✅ Done. All local accounts are locked with shell=nologin, except $BKP_USER (bash & password enabled)."
2 Answers 2
- Don't use
set -euo pipefail
, see Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?. - Don't use all upper case for non-exported variable names, see correct-bash-and-shell-script-variable-capitalization.
- Everything from
# 3)
to the line before# 5)
could be a single awk script instead of multiple calls to grep, sed, etc. e.g. using GNU awk for "inplace" editing and\s
shorthand for[[:space:]]
(untested since no sample input/output provided in the question):
awk -i inplace -v bkp_user="$BKP_USER" '
BEGIN {
pwDflt = "PasswordAuthentication no"
crDflt = "ChallengeResponseAuthentication no"
}
/^\s*#?\s*PasswordAuthentication/ {
0ドル = pwDflt
pwDflt = ""
}
/^\s*#?\s*ChallengeResponseAuthentication/ {
0ドル = crDflt
crDflt = ""
}
/^Match User bkupadmin/ {
exit
}
{ print }
END {
if ( pwDflt != "" ) print pwDflt
if ( crDflt != "" ) print crDflt
printf "\nMatch User %s\n PasswordAuthentication yes\n", bkp_user
}
' "$CFG"
Here are some general coding style suggestions.
Documentation
Add some comments at the top of the code to summarize its purpose. You can use text similar to the description in the question.
Comments
The comments in the code are helpful. You could consider removing the numbering since it will be hard to maintain if you need to add or remove steps.
Layout
It is hard to understand indentation of only 2 spaces. It is more common to use 4 spaces:
if ! id -u "$BKP_USER" &>/dev/null; then
PW="$(openssl rand -base64 32)"
useradd -m -s /bin/bash "$BKP_USER"
echo "$BKP_USER:$PW" | chpasswd
fi
DRY
The text PasswordAuthentication
is repeated several times in the code.
You could set it to a variable to eliminate some repetition:
KEYWORD="PasswordAuthentication"
if grep -qE "^[[:space:]]*#?[[:space:]]*$KEYWORD" "$CFG"; then
sed -i -E "s@^[[:space:]]*#?[[:space:]]*$KEYWORD.*@$KEYWORD no@" "$CFG"
else
echo "$KEYWORD no" >> "$CFG"
fi
This has the side benefit of making the lines shorter and easier to read.
The same can be done for ChallengeResponseAuthentication
. You may be
able to eliminate more repetition using a function.
Portability
I'm not a big fan of fancy unicode characters in source code. Sometimes they don't render well in editors, and other times they don't render well in output generated by the code.
The 1)
comment has a strange dash after the word break
. This is better:
# 1) Create (or unlock) the break-glass user with a bash shell
The last echo
command has the check mark.
Explore related questions
See similar questions with these tags.