8
\$\begingroup\$

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)."
toolic
15.1k5 gold badges29 silver badges211 bronze badges
asked May 23 at 18:39
\$\endgroup\$

2 Answers 2

6
\$\begingroup\$
  1. Don't use set -euo pipefail, see Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?.
  2. Don't use all upper case for non-exported variable names, see correct-bash-and-shell-script-variable-capitalization.
  3. 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"
answered May 24 at 0:01
\$\endgroup\$
5
\$\begingroup\$

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.

answered May 23 at 19:52
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.