From 48fcf25fa3c1947b4171cf384400410bbaf9d2c7 Mon Sep 17 00:00:00 2001 From: Paulo Nonato Date: Sat, 18 Apr 2026 23:31:20 -0300 Subject: [PATCH] Add scripts/linux_user_bootstrap.sh --- scripts/linux_user_bootstrap.sh | 110 ++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 scripts/linux_user_bootstrap.sh diff --git a/scripts/linux_user_bootstrap.sh b/scripts/linux_user_bootstrap.sh new file mode 100644 index 0000000..51660a5 --- /dev/null +++ b/scripts/linux_user_bootstrap.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash +# +# Create a Linux user and install an SSH public key. +# +# This script is designed for repeatable server onboarding. It creates the user +# if missing, prepares ~/.ssh, writes the authorized key, and can optionally add +# the user to a sudo-capable group. +# +# Usage: +# sudo bash linux_user_bootstrap.sh --user deploy --ssh-key "ssh-ed25519 AAAA..." +# sudo bash linux_user_bootstrap.sh --user deploy --ssh-key-file ./deploy.pub --sudo +# +# Options: +# --user NAME Linux username to create or update. +# --ssh-key KEY Public SSH key content. +# --ssh-key-file FILE File containing the public SSH key. +# --sudo Add the user to sudo or wheel group. +# --help Show this help message. + +set -Eeuo pipefail + +target_user="" +ssh_key="" +ssh_key_file="" +grant_sudo=false + +usage() { + sed -n '2,21p' "$0" | sed 's/^# \{0,1\}//' +} + +log() { + printf '[%s] %s\n' "$(date -Is)" "$*" +} + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --user) + target_user="${2:-}" + shift 2 + ;; + --ssh-key) + ssh_key="${2:-}" + shift 2 + ;; + --ssh-key-file) + ssh_key_file="${2:-}" + shift 2 + ;; + --sudo) + grant_sudo=true + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + printf 'ERROR: unknown option: %s\n' "$1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +[[ "$(id -u)" -eq 0 ]] || { printf 'ERROR: this script must run as root.\n' >&2; exit 1; } +[[ "$target_user" =~ ^[a-z_][a-z0-9_-]*[$]?$ ]] || { printf 'ERROR: invalid Linux username: %s\n' "$target_user" >&2; exit 1; } + +if [[ -n "$ssh_key_file" ]]; then + [[ -f "$ssh_key_file" ]] || { printf 'ERROR: SSH key file not found: %s\n' "$ssh_key_file" >&2; exit 1; } + ssh_key="$(< "$ssh_key_file")" +fi + +[[ "$ssh_key" == ssh-* || "$ssh_key" == ecdsa-* ]] || { printf 'ERROR: a valid public SSH key is required.\n' >&2; exit 1; } + +if id "$target_user" >/dev/null 2>&1; then + log "User already exists: ${target_user}" +else + log "Creating user: ${target_user}" + useradd --create-home --shell /bin/bash "$target_user" +fi + +home_dir="$(getent passwd "$target_user" | cut -d: -f6)" +ssh_dir="${home_dir}/.ssh" +authorized_keys="${ssh_dir}/authorized_keys" + +install -d -m 700 -o "$target_user" -g "$target_user" "$ssh_dir" +touch "$authorized_keys" +chmod 600 "$authorized_keys" +chown "$target_user:$target_user" "$authorized_keys" + +if ! grep -qxF "$ssh_key" "$authorized_keys"; then + log "Installing SSH public key for ${target_user}" + printf '%s\n' "$ssh_key" >> "$authorized_keys" +fi + +if [[ "$grant_sudo" == true ]]; then + if getent group sudo >/dev/null 2>&1; then + usermod -aG sudo "$target_user" + log "Added ${target_user} to sudo group." + elif getent group wheel >/dev/null 2>&1; then + usermod -aG wheel "$target_user" + log "Added ${target_user} to wheel group." + else + printf 'ERROR: no sudo or wheel group found.\n' >&2 + exit 1 + fi +fi + +log "User bootstrap completed successfully." +