setup-sudo-user.sh
Skript pre kapitolu Sudo user — preč od root prihlasovania
Veľkosť: 15440 B
Upravené: 2026-05-16 06:55 UTC
SHA256: 034c240c163b…
1#!/usr/bin/env bash
2# =============================================================================
3# VCS Akadémia — Level 1 / Chapter 2: Sudo user setup
4# -----------------------------------------------------------------------------
5# Web: https://vcs-akademia.net/kurz/level-1/sudo-user
6# GitHub: github.com/virtucybersecurity/vcs-akademia
7#
8# Usage (run on the VPS, as root):
9# curl -O https://vcs-akademia.net/script/level-1/sudo-user/setup-sudo-user.sh
10# bash setup-sudo-user.sh
11#
12# =============================================================================
13# PREČO TENTO SKRIPT EXISTUJE
14# =============================================================================
15#
16# Root login je bezpečnostné riziko z troch konkrétnych dôvodov:
17#
18# 1. Žiadny audit trail.
19# Logy zobrazujú "root logged in", "root ran command X" — bez
20# informácie o tom, kto reálne za týmto bol. Pri incidente
21# forenzná analýza prakticky nemožná.
22#
23# 2. Univerzálny cieľ botnetov.
24# 90% pokusov o brute-force SSH login mieri na 'root'. Premenovať
25# sa nedá, ale prihlasovanie ako root sa dá vypnúť (CH 4).
26#
27# 3. Katastrofické chyby.
28# 'rm -rf /tmp/cache' ako root pri preklepe = celý filesystem.
29# Sudo vyžaduje vedomé povolenie pred deštruktívnymi operáciami.
30#
31# Tento skript rieši všetky tri:
32# - Vytvorí non-root používateľa s vlastným menom a heslom
33# - Pridá ho do sudo skupiny
34# - Otestuje, že sudo funguje pre nový účet
35# - Aktualizuje baseline dokumentáciu
36#
37# Skript NEVYPÍNA root SSH login — to robí CH 4 (SSH hardening),
38# kde sa to dá robiť bezpečne so záložným plánom.
39#
40# =============================================================================
41# AKO TO TENTO SKRIPT ROBÍ
42# =============================================================================
43#
44# Skript beží PRIAMO NA VPS ako root. V 4 krokoch:
45#
46# 1. Overenie — bežíme ako root? Existuje balík sudo?
47# 2. Vytvorenie používateľa cez adduser (interaktívne, pýta heslo).
48# 3. Pridanie do sudo skupiny cez usermod -aG sudo (append, nie replace).
49# 4. Test sudo z nového účtu (overí, že sudo skutočne funguje).
50#
51# Po úspešnom dokončení skript aktualizuje /root/server-baseline.txt
52# o informáciu o novom používateľovi a vypíše ďalšie kroky.
53#
54# =============================================================================
55
56set -u
57set -o pipefail
58
59# -----------------------------------------------------------------------------
60# Colors (ANSI escape codes)
61# -----------------------------------------------------------------------------
62RED='\033[0;31m'
63GREEN='\033[0;32m'
64YELLOW='\033[1;33m'
65BLUE='\033[0;34m'
66NC='\033[0m'
67
68# -----------------------------------------------------------------------------
69# Output helpers
70# -----------------------------------------------------------------------------
71print_info() { printf "${BLUE}[INFO]${NC} %s\n" "$*"; }
72print_success() { printf "${GREEN}[OK]${NC} %s\n" "$*"; }
73print_warning() { printf "${YELLOW}[VAROVANIE]${NC} %s\n" "$*" >&2; }
74print_error() { printf "${RED}[CHYBA]${NC} %s\n" "$*" >&2; }
75print_fatal() { print_error "$*"; cleanup_on_exit; exit 1; }
76
77# -----------------------------------------------------------------------------
78# Cleanup — remove the script file when we're done (success or failure).
79# -----------------------------------------------------------------------------
80SCRIPT_SOURCE="${BASH_SOURCE[0]:-$0}"
81
82cleanup_on_exit() {
83 [ -f "$SCRIPT_SOURCE" ] || return 0
84
85 local script_dir script_name script_path
86 script_dir="$(cd "$(dirname "$SCRIPT_SOURCE")" 2>/dev/null && pwd)" || return 0
87 script_name="$(basename "$SCRIPT_SOURCE")"
88 script_path="${script_dir}/${script_name}"
89
90 case "$script_name" in
91 setup-sudo-user.sh) ;;
92 *) return 0 ;;
93 esac
94
95 case "$script_path" in
96 /|/bin/*|/sbin/*|/usr/*|/etc/*|/var/*|/lib/*|/lib64/*|/boot/*)
97 return 0 ;;
98 esac
99
100 [ -f "$script_path" ] && rm -f "$script_path" 2>/dev/null && \
101 print_info "Skript bol odstránený: $script_path"
102 return 0
103}
104
105trap cleanup_on_exit EXIT
106
107# -----------------------------------------------------------------------------
108# Pre-flight checks
109# -----------------------------------------------------------------------------
110preflight() {
111 # Must be Linux
112 if [ "$(uname -s)" != "Linux" ]; then
113 print_fatal "Tento skript sa spúšťa NA serveri (Linux), nie lokálne."
114 fi
115
116 # Must be root (we create users and modify groups)
117 if [ "$(id -u)" -ne 0 ]; then
118 print_fatal "Tento skript musí byť spustený ako root.
119
120Ak si na serveri ako bežný používateľ, prepni sa:
121 sudo bash setup-sudo-user.sh
122
123Ak si stratil root prístup, využi rescue mode poskytovateľa."
124 fi
125
126 # Must be Debian/Ubuntu based (uses adduser, apt)
127 if ! command -v adduser >/dev/null 2>&1; then
128 print_fatal "Tento skript podporuje len Debian/Ubuntu (adduser). Pre iné distribúcie použi ručný postup z kapitoly."
129 fi
130
131 # Check sudo is installed
132 if ! command -v sudo >/dev/null 2>&1; then
133 print_warning "Balík 'sudo' nie je nainštalovaný."
134 print_info "Inštalujem ho..."
135 if ! apt update >/dev/null 2>&1 || ! apt install -y sudo >/dev/null 2>&1; then
136 print_fatal "Nepodarilo sa nainštalovať sudo. Skontroluj sieť alebo apt."
137 fi
138 print_success "Balík sudo nainštalovaný."
139 fi
140}
141
142# -----------------------------------------------------------------------------
143# Confirmation prompt
144# -----------------------------------------------------------------------------
145confirm() {
146 local prompt="${1:-Pokračovať?}"
147 local reply
148 printf "${YELLOW}%s [y/N]:${NC} " "$prompt"
149 read -r reply </dev/tty
150 case "$reply" in
151 y|Y|yes|YES|ano|ANO) return 0 ;;
152 *) printf "${BLUE}[INFO]${NC} Zrušené.\n"; exit 0 ;;
153 esac
154}
155
156# -----------------------------------------------------------------------------
157# Ask for user input with optional default and validation
158# -----------------------------------------------------------------------------
159ask() {
160 local prompt="$1"
161 local default="${2:-}"
162 local reply
163 if [ -n "$default" ]; then
164 printf "%s [%s]: " "$prompt" "$default" >&2
165 else
166 printf "%s: " "$prompt" >&2
167 fi
168 read -r reply </dev/tty
169 if [ -z "$reply" ]; then
170 echo "$default"
171 else
172 echo "$reply"
173 fi
174}
175
176# -----------------------------------------------------------------------------
177# Validate username
178# Linux username conventions: lowercase, alphanumeric + hyphens, start with letter
179# -----------------------------------------------------------------------------
180validate_username() {
181 local name="$1"
182
183 # Check length (1-32 chars)
184 if [ -z "$name" ] || [ ${#name} -gt 32 ]; then
185 echo "Meno musí mať 1–32 znakov."
186 return 1
187 fi
188
189 # Check pattern: starts with lowercase letter, then alphanumeric/hyphen/underscore
190 if ! echo "$name" | grep -qE '^[a-z][a-z0-9_-]*$'; then
191 echo "Meno musí začínať malým písmenom a obsahovať len malé písmená, čísla, '_' a '-'."
192 return 1
193 fi
194
195 # Reject obvious bad names
196 case "$name" in
197 root|admin|administrator|superuser|god|toor|sudo)
198 echo "Meno '$name' je zlá voľba — provokuješ útočníkov. Použi tvoje skutočné meno."
199 return 1
200 ;;
201 esac
202
203 # Check if user already exists
204 if id "$name" >/dev/null 2>&1; then
205 echo "Používateľ '$name' už existuje."
206 return 1
207 fi
208
209 return 0
210}
211
212# -----------------------------------------------------------------------------
213# Create the new user (interactive — adduser asks for password)
214# -----------------------------------------------------------------------------
215create_user() {
216 local username="$1"
217
218 print_info "Vytváram používateľa '$username' cez adduser..."
219 print_info "adduser sa ťa opýta na heslo a pár nepovinných polí."
220 echo
221
222 # adduser is interactive — handles password prompt, home dir, default files
223 if ! adduser --gecos "" "$username"; then
224 print_fatal "adduser zlyhal."
225 fi
226
227 print_success "Používateľ '$username' vytvorený."
228}
229
230# -----------------------------------------------------------------------------
231# Add user to sudo group
232# -----------------------------------------------------------------------------
233add_to_sudo_group() {
234 local username="$1"
235
236 print_info "Pridávam '$username' do sudo skupiny..."
237
238 # -aG: append (a) to group(s) (G). Without -a, would replace all groups.
239 if ! usermod -aG sudo "$username"; then
240 print_fatal "usermod zlyhal."
241 fi
242
243 # Verify
244 if ! groups "$username" | grep -q '\bsudo\b'; then
245 print_fatal "Pridanie do sudo skupiny zlyhalo — '$username' nie je v skupine sudo."
246 fi
247
248 print_success "'$username' je teraz v skupine sudo."
249 print_info "Skupiny: $(groups "$username" | cut -d: -f2 | xargs)"
250}
251
252# -----------------------------------------------------------------------------
253# Test sudo functionality for new user
254# This is critical — we want to verify sudo actually works before celebrating.
255# -----------------------------------------------------------------------------
256test_sudo() {
257 local username="$1"
258
259 print_info "Testujem sudo z účtu '$username'..."
260 print_info "(Krátky príkaz, ktorý vyžaduje root práva.)"
261 echo
262
263 # Run 'true' (no-op) as the user via sudo. This forces password prompt.
264 # We capture output so we can interpret the result.
265 print_info "Zadaj heslo pre '$username' (nie root heslo):"
266
267 if su - "$username" -c 'sudo -k; sudo -p "[sudo] heslo pre %u: " true' 2>&1; then
268 print_success "Sudo funguje pre '$username'."
269 return 0
270 else
271 print_error "Sudo test zlyhal."
272 print_warning "Možné príčiny:"
273 print_warning " - Nesprávne heslo (skús ešte raz spustením skriptu)"
274 print_warning " - '$username' nie je v sudo skupine (overiť: 'groups $username')"
275 print_warning " - Konfigurácia sudo zakazuje skupinu (overiť: '/etc/sudoers')"
276 return 1
277 fi
278}
279
280# -----------------------------------------------------------------------------
281# Update baseline document (if it exists)
282# -----------------------------------------------------------------------------
283update_baseline() {
284 local username="$1"
285 local baseline="/root/server-baseline.txt"
286
287 if [ ! -f "$baseline" ]; then
288 print_info "Baseline dokument neexistuje ($baseline)."
289 print_info "Ak si CH 1 ešte nedotiahol, môžeš ho pridať neskôr."
290 return 0
291 fi
292
293 print_info "Aktualizujem baseline ($baseline)..."
294
295 {
296 echo ""
297 echo "=== Sudo používateľ ==="
298 echo "Pridaný: $(date +%Y-%m-%d)"
299 echo "Meno: $username"
300 echo "UID: $(id -u "$username")"
301 echo "GID: $(id -g "$username")"
302 echo "Skupiny: $(groups "$username" | cut -d: -f2 | xargs)"
303 echo "Domov: $(getent passwd "$username" | cut -d: -f6)"
304 } >> "$baseline"
305
306 print_success "Baseline aktualizovaný."
307}
308
309# -----------------------------------------------------------------------------
310# Final summary
311# -----------------------------------------------------------------------------
312print_summary() {
313 local username="$1"
314
315 echo
316 printf "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
317 printf "${GREEN} Sudo používateľ pripravený: HOTOVO${NC}\n"
318 printf "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
319 echo
320 printf " Nový účet: ${BLUE}%s${NC}\n" "$username"
321 printf " Domovský adresár: %s\n" "$(getent passwd "$username" | cut -d: -f6)"
322 printf " Prístup k sudo: ${GREEN}Áno${NC}\n"
323 echo
324 printf "${YELLOW} ČO ROBIŤ TERAZ:${NC}\n"
325 echo
326 printf " 1. Odhlás sa z root účtu:\n"
327 printf " ${BLUE}exit${NC}\n"
328 echo
329 printf " 2. Prihlás sa z lokálneho počítača ako '%s':\n" "$username"
330 printf " ${BLUE}ssh %s@TVOJA_IP${NC}\n" "$username"
331 echo
332 printf " 3. Otestuj sudo z novej session:\n"
333 printf " ${BLUE}sudo whoami${NC}\n"
334 printf " (mal by si dostať 'root')\n"
335 echo
336 printf "${YELLOW} Ďalej:${NC} CH 3 — SSH key authentication\n"
337 printf " Pridáme SSH kľúč pre nový non-root účet, aby si sa\n"
338 printf " prihlasoval bez hesla.\n"
339 printf " https://vcs-akademia.net/kurz/level-1/ssh-key\n"
340 echo
341 print_warning "ZATIAĽ NEVYPÍNAJ root SSH login!"
342 print_warning "To robí CH 4 — bezpečne, so záložným plánom."
343 echo
344}
345
346# -----------------------------------------------------------------------------
347# MAIN
348# -----------------------------------------------------------------------------
349main() {
350 printf "\n${BLUE}=== VCS Akadémia — CH 2: Sudo používateľ ===${NC}\n\n"
351
352 cat <<EOF
353Tento skript urobí 4 kroky:
354 1. Overí, že bežíme ako root a máme nainštalovaný 'sudo'.
355 2. Vytvorí nového non-root používateľa (pýta meno + heslo).
356 3. Pridá ho do sudo skupiny.
357 4. Otestuje, že sudo z nového účtu skutočne funguje.
358
359BEZPEČNOSTNÁ POZNÁMKA:
360 Skript NEVYPÍNA root SSH login. Root účet zostane funkčný.
361 Vypnutie root SSH je obsahom CH 4 (SSH hardening), kde sa
362 to robí bezpečne, s testovaním pred vypnutím.
363
364EOF
365
366 confirm "Chceš pokračovať?"
367
368 printf "\n${BLUE}-- Pre-flight kontrola --${NC}\n"
369 preflight
370 print_success "Pripravený na vytvorenie používateľa."
371
372 printf "\n${BLUE}-- Krok 1/4 — Voľba mena --${NC}\n"
373 print_info "Konvencia pre meno používateľa:"
374 print_info " - 1–32 znakov, len malé písmená, čísla, '_' a '-'"
375 print_info " - Začína malým písmenom"
376 print_info " - Rozumné: 'peter', 'mike', 'admin1', 'deploy-bot'"
377 print_info " - Vyhni sa: 'root2', 'superuser', 'admin' (provokácia útočníkov)"
378 echo
379
380 local username
381 local validation_error
382 while true; do
383 username=$(ask "Meno nového používateľa" "")
384 validation_error=$(validate_username "$username")
385 if [ $? -eq 0 ]; then
386 break
387 fi
388 print_warning "$validation_error"
389 if ! confirm "Skúsiť znova?"; then
390 print_fatal "Zrušené."
391 fi
392 done
393
394 echo
395 print_info "Použijem meno: $username"
396 confirm "Pokračovať?"
397
398 printf "\n${BLUE}-- Krok 2/4 — Vytvorenie účtu --${NC}\n"
399 create_user "$username"
400
401 printf "\n${BLUE}-- Krok 3/4 — Sudo skupina --${NC}\n"
402 add_to_sudo_group "$username"
403
404 printf "\n${BLUE}-- Krok 4/4 — Test sudo --${NC}\n"
405 if ! test_sudo "$username"; then
406 print_warning "Sudo test zlyhal, ale účet '$username' bol vytvorený a pridaný do sudo skupiny."
407 print_warning "Skús sa prihlásiť ako '$username' manuálne a otestuj 'sudo whoami'."
408 # Don't fatal — user account exists, just couldn't verify
409 fi
410
411 # Update baseline (non-fatal if missing)
412 echo
413 update_baseline "$username"
414
415 print_summary "$username"
416}
417
418main "$@"