#!/usr/bin/bash # author: Rénich Bon Ćirić # description: Server takeover and bootstrap script for Fedora and Enterprise Linux set -euo pipefail IFS=$'\n\t' readonly TargetUser="renich" readonly SshPubkey="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILWo3RJ88qk1RS+P6b8U+rFJ1GpIxKvWW7AGrgiCx8dK renich@desktop" if [[ ${EUID} -ne 0 ]]; then echo "Error: This script must be run as root." >&2 exit 1 fi if [[ ! -f /etc/os-release ]]; then echo "Error: /etc/os-release not found. Unsupported distribution." >&2 exit 1 fi # shellcheck source=/dev/null source /etc/os-release echo "==> Detected OS: ${NAME:-Linux} (ID: ${ID:-unknown}, Version: ${VERSION_ID:-unknown})" major_ver="${VERSION_ID%%.*}" is_centos_stream_10_plus=false if [[ "${ID:-}" == "centos" ]] || [[ "${NAME:-}" =~ "CentOS Stream" ]]; then if [[ "${major_ver}" =~ ^[0-9]+$ ]] && [[ "${major_ver}" -ge 10 ]]; then is_centos_stream_10_plus=true fi fi tmux_status_bg="blue" case "${ID}" in fedora) echo "==> Configuring Fedora repositories..." ;; centos) if [[ "${is_centos_stream_10_plus}" == true ]]; then echo "==> Configuring CentOS Stream ${major_ver}+ optimizations and repositories..." tmux_status_bg="purple" # Faster DNF downloads if [[ -f /etc/dnf/dnf.conf ]] && ! grep -q 'max_parallel_downloads' /etc/dnf/dnf.conf; then printf '\n# my configs\nmax_parallel_downloads=10\n' >> /etc/dnf/dnf.conf fi # Install EPEL and dnf-plugins-core if ! rpm -q epel-release &>/dev/null; then dnf -y install epel-release dnf-plugins-core || true fi # Enable all standard enterprise repos echo "==> Enabling CRB, HighAvailability, NFV, ResilientStorage, and RT repos..." for repo in crb highavailability nfv resilientstorage rt; do dnf config-manager --enable "${repo}" 2>/dev/null || \ dnf config-manager --set-enabled "${repo}" 2>/dev/null || \ dnf config-manager setopt "${repo}.enabled=1" 2>/dev/null || true done else echo "==> Configuring legacy CentOS repositories..." if ! rpm -q epel-release &>/dev/null; then dnf -y install epel-release dnf-plugins-core || true fi if [[ "${major_ver}" -ge 9 ]]; then dnf config-manager --set-enabled crb 2>/dev/null || dnf config-manager --enable crb 2>/dev/null || true elif [[ "${major_ver}" -eq 8 ]]; then dnf config-manager --set-enabled powertools 2>/dev/null || dnf config-manager --enable powertools 2>/dev/null || true fi fi ;; rhel|rocky|almalinux) echo "==> Configuring Enterprise Linux repositories (EPEL + CRB)..." if ! rpm -q epel-release &>/dev/null; then dnf -y install epel-release dnf-plugins-core || true fi if [[ "${major_ver}" -ge 9 ]]; then dnf config-manager --set-enabled crb 2>/dev/null || dnf config-manager --enable crb 2>/dev/null || true elif [[ "${major_ver}" -eq 8 ]]; then dnf config-manager --set-enabled powertools 2>/dev/null || dnf config-manager --enable powertools 2>/dev/null || true fi ;; *) echo "==> Proceeding with generic RPM/DNF package management..." ;; esac wanted_pkgs=( bash-completion bind-utils curl editorconfig git htop iftop iotop jq python3-policycoreutils rpmconf rsync setools-console tar tmux tmux-powerline vim-enhanced vim-powerline wireshark-cli ) echo "==> Installing essential packages..." dnf -y install --skip-broken "${wanted_pkgs[@]}" echo "==> Configuring /etc/skel dotfiles..." cat << 'EOF' > /etc/skel/.vimrc " General filetype indent on filetype on filetype plugin on set modeline set mouse=c set nocompatible set nolist set ruler syntax on " Colors set t_Co=256 colorscheme koehler " Indentation set autoindent set nocopyindent set nowrap set shiftwidth=4 set showmatch set smartindent set smarttab set tabstop=4 set textwidth=132 " Search set incsearch set smartcase " Statusline set laststatus=2 " Shortcuts set pastetoggle= nmap 1G-G imap 1G=Ga map :set spell! spelllang=en_us " Commands command! Hsort call setline('.', join( sort( split( getline('.'), '\s\+') ), ' ') ) command! -nargs=0 RemoveComments g/\v^(#|[[:space:]].+#|$)/d " Remove trailing white space on save autocmd BufWritePre * :%s@\s\+$@@e EOF chmod 0644 /etc/skel/.vimrc cat << EOF > /etc/skel/.tmux.conf # terminal colors set -g default-terminal "screen-256color" # history size set -g history-limit 20000 # status color set -g status-bg ${tmux_status_bg} # resize setw -g aggressive-resize on # mouse set -g mouse off # navigation setw -g mode-keys vi # tmux-powerline (guarded load) if-shell '[ -f /usr/share/tmux/powerline.conf ]' 'source /usr/share/tmux/powerline.conf' EOF chmod 0644 /etc/skel/.tmux.conf # Populate root dotfiles install -m 0644 /etc/skel/.vimrc /root/.vimrc install -m 0644 /etc/skel/.tmux.conf /root/.tmux.conf # Configure history if CentOS Stream 10+ if [[ "${is_centos_stream_10_plus}" == true ]]; then echo "==> Configuring infinite history for CentOS Stream 10+..." cat << 'EOF' > /etc/profile.d/history.bash export HISTCONTROL=erasedups:ignoredups export HISTSIZE=-1 export HISTTIMEFORMAT='%F %T ' EOF chmod 0644 /etc/profile.d/history.bash ln -sf history.bash /etc/profile.d/history.sh fi echo "==> Provisioning user '${TargetUser}' (no sudo/wheel)..." if ! id -u "${TargetUser}" &>/dev/null; then useradd -m -s /usr/bin/bash "${TargetUser}" else # Ensure shell is bash; do NOT add to wheel usermod -s /usr/bin/bash "${TargetUser}" fi target_home=$(getent passwd "${TargetUser}" | cut -d: -f6) install -m 0644 -o "${TargetUser}" -g "${TargetUser}" /etc/skel/.vimrc "${target_home}/.vimrc" install -m 0644 -o "${TargetUser}" -g "${TargetUser}" /etc/skel/.tmux.conf "${target_home}/.tmux.conf" inject_ssh_key() { local user="$1" local home_dir="$2" local ssh_dir="${home_dir}/.ssh" local auth_keys="${ssh_dir}/authorized_keys" install -d -m 0700 -o "${user}" -g "${user}" "${ssh_dir}" touch "${auth_keys}" chown "${user}:${user}" "${auth_keys}" chmod 0600 "${auth_keys}" if ! grep -qxF "${SshPubkey}" "${auth_keys}"; then echo "${SshPubkey}" >> "${auth_keys}" echo "--> Injected SSH key for ${user}." else echo "--> SSH key already present for ${user}." fi } echo "==> Injecting SSH keys..." inject_ssh_key "root" "/root" inject_ssh_key "${TargetUser}" "${target_home}" echo "==> Configuring SSH daemon for key-based root login..." if [[ -d /etc/ssh/sshd_config.d ]]; then cat << 'EOF' > /etc/ssh/sshd_config.d/99-root-access.conf # Enforce SSH key-based access for root PermitRootLogin prohibit-password PubkeyAuthentication yes EOF chmod 0600 /etc/ssh/sshd_config.d/99-root-access.conf fi if systemctl is-active sshd &>/dev/null; then systemctl reload sshd || systemctl restart sshd || true fi if command -v restorecon &>/dev/null && selinuxenabled 2>/dev/null; then echo "==> Restoring SELinux contexts..." restorecon -R /root/.ssh "${target_home}/.ssh" /etc/skel /root/.vimrc /root/.tmux.conf "${target_home}/.vimrc" "${target_home}/.tmux.conf" 2>/dev/null || true if [[ -d /etc/ssh/sshd_config.d ]]; then restorecon -R /etc/ssh/sshd_config.d 2>/dev/null || true fi if [[ -f /etc/profile.d/history.bash ]]; then restorecon -v /etc/profile.d/history.bash /etc/profile.d/history.sh 2>/dev/null || true fi fi cat << EOF ========================================================== Takeover complete. - Key-based SSH access enabled for root and ${TargetUser}. - No sudo configured (disfavored). - You may now set your root password manually via: passwd ========================================================== EOF