Skip to content

Commit

Permalink
Check remote user on install task
Browse files Browse the repository at this point in the history
- On install task, warn if the remote user on the target host is not the
  current local user. The intention of this check is to make sure the
  user is aware that their remote login user is not the current local
  user, which usually means the nixos-anywhere login after installation
  will fail.
- Provide a helper script `add-remote-user.sh` to make it easy to add
  the current local user as a remote user on the target host.

Signed-off-by: Henri Rosten <[email protected]>
  • Loading branch information
henrirosten committed Nov 20, 2023
1 parent 3b8a253 commit bde9e05
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 2 deletions.
30 changes: 28 additions & 2 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,17 +321,43 @@ def install(c: Any, alias) -> None:
if ask != "y":
return

# Check ssh and remote user
try:
remote_user = h.run(cmd="whoami", stdout=subprocess.PIPE).stdout.strip()
local_user = exec_cmd("whoami").stdout.strip()
if remote_user and local_user and remote_user != local_user:
LOG.warning(
"Remote user '%s' is not your current local user. "
"You will likely not be able to login to the remote host '%s' "
"after nixos-anywhere installation. Consider adding your local "
"user to the remote host and make sure user '%s' "
"also has access to remote host after nixos-anywhere installation "
"by adding your local user as a user to nixos configuration '%s'. "
"Hint: you might want to try the helper script at "
"'terraform/scripts/add-remote-user.sh' to add your current local "
"user to the remote host.",
remote_user,
_get_target(alias).hostname,
local_user,
_get_target(alias).nixosconfig,
)
ask = input("Still continue? [y/N] ")
if ask != "y":
sys.exit(1)
except subprocess.CalledProcessError:
LOG.fatal("No ssh access to the remote host")
sys.exit(1)
# Check sudo nopasswd
try:
h.run("sudo -nv", become_root=True)
h.run("sudo -n true", become_root=True)
except subprocess.CalledProcessError:
LOG.warning(
"sudo on '%s' needs password: installation will likely fail", h.host
)
ask = input("Still continue? [y/N] ")
if ask != "y":
sys.exit(1)
# Check static ip
# Check dynamic ip
try:
h.run("ip a | grep dynamic")
except subprocess.CalledProcessError:
Expand Down
119 changes: 119 additions & 0 deletions terraform/scripts/add-remote-user.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env bash

# SPDX-FileCopyrightText: 2023 Technology Innovation Institute (TII)
#
# SPDX-License-Identifier: Apache-2.0

################################################################################

MYNAME=$(basename "$0")
usage () {
echo "Usage: $MYNAME [-u USER] -s SSH_OPTS -k PUB_KEY_PATH"
echo ""
echo "Add a USER to the remote host using SSH_OPTS for the initial login, adding "
echo "public key PUB_KEY_PATH to the USER's authorized_keys on the remote host."
echo ""
echo "Options:"
echo " -h Print this help message"
echo " -u Username to be added to the remote host (default=\$USER)"
echo " -s SSH options used for the initial login to the remote host"
echo " -k Path to the public key that will be added to remote USER's authorized_keys"
echo ""
echo "Example:"
echo ""
echo " Following command adds user new_user to host remote_host allowing "
echo " new_user ssh login to remote_host with key that matches the public "
echo " key ~/.ssh/id_new_user.pub. For the initial login, the command uses "
echo " admin@remote_host -i admin_key:"
echo ""
echo " $MYNAME -s 'admin@remote_host -i admin_key' -u new_user -k ~/.ssh/id_new_user.pub"
echo ""
}

################################################################################

OPTIND=1; OPT_u=""; OPT_s=""; OPT_k=""
while getopts "hu:s:k:" copt; do
case "${copt}" in
h)
usage; exit 0 ;;
u)
OPT_u="$OPTARG" ;;
s)
OPT_s="$OPTARG" ;;
k)
OPT_k="$OPTARG" ;;
*)
echo "Error: unrecognized option"; usage; exit 1 ;;
esac
done
shift $((OPTIND-1))
if [ -n "$*" ]; then
echo "Error: unsupported positional argument(s): '$*'"; exit 1
fi
if [ -z "$OPT_s" ] || [ -z "$OPT_k" ]; then
echo "Error: missing mandatory option(s)"; usage; exit 1
fi
if [ -z "$OPT_u" ]; then
if [ -z "$USER" ]; then
echo "Error: '-u USER' not defined and missing environment variable \$USER"
exit 1;
fi
OPT_u="$USER"
fi

################################################################################

exit_unless_file_exists () {
if ! [ -f "$1" ]; then
echo "Error: File not found: \"$1\""
exit 1
fi
}

test_remote_sudo () {
# shellcheck disable=SC2086 # intented word splitting of $OPT_s
if ! ssh -o ConnectTimeout=5 $OPT_s "sudo -n true"; then
echo "Error: sudo on remote host failed"
exit 1
fi
}

# shellcheck disable=SC2086 # intented word splitting of $OPT_s
# shellcheck disable=SC2029 # intented client side expansion of $OPT_u
add_remote_user () {
if ! ssh $OPT_s "\
sudo useradd -m -d /home/$OPT_u $OPT_u; \
sudo grep -q '$OPT_u ALL=(ALL) NOPASSWD: ALL' /etc/sudoers || \
sudo sh -c \"printf '$OPT_u ALL=(ALL) NOPASSWD: ALL\n' >>/etc/sudoers\"; \
sudo mkdir -p /home/$OPT_u/.ssh; \
sudo touch /home/$OPT_u/.ssh/authorized_keys; \
sudo chown -R $OPT_u:$OPT_u /home/$OPT_u/.ssh; \
sudo chmod 700 /home/$OPT_u/.ssh; \
sudo chmod 600 /home/$OPT_u/.ssh/authorized_keys; \
sudo tee -a /home/$OPT_u/.ssh/authorized_keys; \
" < "$OPT_k";
then
echo "Error: failed adding user to remote host"
exit 1
fi
if ! ssh $OPT_s "\
sudo sort -u /home/$OPT_u/.ssh/authorized_keys -o /home/$OPT_u/.ssh/authorized_keys;";
then
echo "Warning: failed removing duplicates from remote authorized_keys"
fi
}

################################################################################

main () {
exit_unless_file_exists "$OPT_k"
test_remote_sudo
add_remote_user
echo ""
echo "You can now login to remote host as user '$OPT_u' with key '$OPT_k'"
}

main "$@"

################################################################################

0 comments on commit bde9e05

Please sign in to comment.