Скрипты проверки стенда (check/) для заданий 1–3

This commit is contained in:
parent be087496a9
commit 97ad5d2195
17 changed files with 1591 additions and 0 deletions

91
check/zadanie1/br-fw.sh Normal file
View file

@ -0,0 +1,91 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — BR-FW (только читает состояние!)
# Пункты vtysh требуют root — иначе ПРОПУЩЕНО.
# Работает только если BR-FW — Linux (см. MANUAL.md про BR-FW).
# ============================================================
NAME="br-fw"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="br-fw.au-team.irpo" # таблица 3
BR_RTR_IF="" # интерфейс к BR-RTR
BR_RTR_ADDR="" # адрес BR-FW в сети /30, адрес/префикс
BR_RTR_GW="" # адрес BR-RTR — маршрут по умолчанию
BR_SRV_IF="" # интерфейс к BR-SRV
BR_SRV_ADDR="" # адрес BR-FW в сети BR-SRV, адрес/префикс
BR_SRV_PING="" # адрес BR-SRV для проверки связи
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: BR-FW ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Адреса интерфейсов ---
check_var "адрес линка к BR-RTR" BR_RTR_ADDR &&
if grep -qF -- "$BR_RTR_ADDR" <(ip -4 -o addr show "$BR_RTR_IF" 2>/dev/null); then
ok "адрес на $BR_RTR_IF = $BR_RTR_ADDR"
else fail "адрес линка к BR-RTR" "на $BR_RTR_IF нет $BR_RTR_ADDR"; fi
check_var "адрес в сети BR-SRV" BR_SRV_ADDR &&
if grep -qF -- "$BR_SRV_ADDR" <(ip -4 -o addr show "$BR_SRV_IF" 2>/dev/null); then
ok "адрес на $BR_SRV_IF = $BR_SRV_ADDR"
else fail "адрес в сети BR-SRV" "на $BR_SRV_IF нет $BR_SRV_ADDR"; fi
# --- 3. Шлюз по умолчанию через BR-RTR ---
check_var "шлюз по умолчанию" BR_RTR_GW &&
if ip route show default 2>/dev/null | grep -qF "$BR_RTR_GW"; then
ok "маршрут по умолчанию через $BR_RTR_GW"
else fail "маршрут по умолчанию" "ожидался via $BR_RTR_GW, получено: $(ip route show default)"; fi
# --- 4. OSPF-сосед BR-RTR (только по линку к BR-RTR) ---
if root_or_skip "OSPF (vtysh)"; then
if ! command -v vtysh &>/dev/null; then
skip "OSPF — vtysh не найден (ПРОВЕРИТЬ OSPF-демон на РЕД ОС 8 / что за система BR-FW)"
else
N_FULL=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full")
if [[ $N_FULL -ge 1 ]]; then ok "OSPF сосед BR-RTR в FULL"
else fail "OSPF сосед" "нет соседа в Full: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi
fi
fi
# --- 5. ip_forward ---
FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null)
if [[ "$FWD" == "1" ]]; then ok "ip_forward включён"
else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi
# --- 6. Связь с BR-SRV ---
check_var "связь с BR-SRV" BR_SRV_PING &&
if ping -c2 -W2 "$BR_SRV_PING" &>/dev/null; then ok "ping BR-SRV ($BR_SRV_PING)"
else fail "ping BR-SRV ($BR_SRV_PING)" "недоступен"; fi
# --- 7. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — выход в Интернет из BR-SRV: ping 77.88.8.7 с BR-SRV"
echo " — таблицу 2 (адрес BR-FW, его шлюз) в отчёте"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

117
check/zadanie1/br-rtr.sh Normal file
View file

@ -0,0 +1,117 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — BR-RTR (только читает состояние!)
# Пункты vtysh/iptables требуют root — иначе ПРОПУЩЕНО.
# ============================================================
NAME="br-rtr"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="br-rtr.au-team.irpo" # таблица 3
NET_ADMIN_USER="net_admin"
ISP_IF="" # интерфейс к ISP
BR_LINK_IF="" # интерфейс к BR-FW (сеть /30)
BR_LINK_ADDR="" # адрес BR-RTR на этом линке, адрес/префикс
GRE_IF="gre1"
GRE_LOCAL="" # локальный конец туннеля
GRE_REMOTE="" # адрес HQ-RTR в сети ISP (пингуем через туннель)
OSPF_PASSWORD="P@ssw0rd"
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: BR-RTR ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Пользователь net_admin ---
check_var "пользователь net_admin" NET_ADMIN_USER &&
if id "$NET_ADMIN_USER" &>/dev/null; then ok "пользователь $NET_ADMIN_USER существует"
else fail "пользователь $NET_ADMIN_USER" "нет такого пользователя"; fi
check_var "sudo для net_admin" NET_ADMIN_USER &&
if root_or_skip "sudo для net_admin" ; then
if sudo -ln -U "$NET_ADMIN_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then
ok "net_admin — sudo без пароля (NOPASSWD: ALL)"
else fail "sudo для net_admin" "нет NOPASSWD: ALL"; fi
fi
# --- 3. Адeline в сторону BR-FW (сеть /30) ---
check_var "адрес линка к BR-FW" BR_LINK_ADDR &&
if grep -qF -- "$BR_LINK_ADDR" <(ip -4 -o addr show "$BR_LINK_IF" 2>/dev/null); then
ok "адрес на $BR_LINK_IF = $BR_LINK_ADDR"
else fail "адрес линка к BR-FW" "на $BR_LINK_IF нет $BR_LINK_ADDR"; fi
# --- 4. GRE-туннель ---
check_var "адрес туннеля" GRE_LOCAL &&
if grep -qF -- "$GRE_LOCAL" <(ip -4 -o addr show "$GRE_IF" 2>/dev/null); then
ok "туннель $GRE_IF поднят с $GRE_LOCAL"
else fail "туннель $GRE_IF" "не нашёлся адрес $GRE_LOCAL"; fi
# --- 5. OSPF: два соседа (HQ-RTR через туннель, BR-FW через линк) ---
if root_or_skip "OSPF (vtysh)"; then
if ! command -v vtysh &>/dev/null; then
skip "OSPF — vtysh не найден (ПРОВЕРИТЬ OSPF-демон на РЕД ОС 8)"
else
N_FULL=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full")
if [[ $N_FULL -ge 2 ]]; then ok "OSPF соседи в FULL: $N_FULL"
else fail "OSPF соседи" "ожидалось 2 (HQ-RTR и BR-FW), найдено $N_FULL: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi
if vtysh -c 'show running-config' 2>/dev/null \
| grep -i "message-digest-key" | grep -qiF "$OSPF_PASSWORD"; then
ok "OSPF MD5-аутентификация с паролем"
else fail "OSPF MD5" "ключ/пароль не найдены в конфиге"; fi
if vtysh -c 'show ip route ospf' 2>/dev/null | grep -q "O "; then
ok "маршруты OSPF присутствуют"
else fail "маршруты OSPF" "нет маршрутов от OSPF"; fi
fi
fi
# --- 6. NAT и маршрут по умолчанию ---
check_var "интерфейс ISP" ISP_IF &&
{ if root_or_skip "NAT"; then
COUNT=$(iptables -t nat -S POSTROUTING 2>/dev/null | grep -cF "$ISP_IF")
if [[ $COUNT -ge 1 ]]; then ok "NAT MASQUERADE на $ISP_IF ($COUNT правил)"
else fail "NAT" "нет MASQUERADE на $ISP_IF"; fi
fi
if ip route show default 2>/dev/null | grep -qF "$ISP_IF"; then
ok "маршрут по умолчанию через $ISP_IF"
else fail "маршрут по умолчанию" "через $ISP_IF нет"; fi; }
# --- 7. Связь через туннель ---
check_var "связь через туннель" GRE_REMOTE &&
if ping -c2 -W2 "$GRE_REMOTE" &>/dev/null; then ok "ping HQ-RTR через туннель ($GRE_REMOTE)"
else fail "ping HQ-RTR ($GRE_REMOTE)" "недоступен"; fi
# --- 8. ip_forward ---
FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null)
if [[ "$FWD" == "1" ]]; then ok "ip_forward включён"
else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi
# --- 9. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — связь офис-к-офису: с HQ-SRV ping <адрес BR-SRV> и наоборот (сквозная маршрутизация)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

87
check/zadanie1/br-srv.sh Normal file
View file

@ -0,0 +1,87 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — BR-SRV (только читает состояние!)
# Пункты sshd -T и sudo требуют root.
# ============================================================
NAME="br-srv"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="br-srv.au-team.irpo" # таблица 3
SRV_IF="" # интерфейс к BR-SRV
SRV_ADDR="" # адрес BR-SRV, адрес/префикс
SRV_GW="" # шлюз (адрес BR-FW)
SSH_PORT="2027"
SSH_USER="sshuser"
SSH_USER_UID="2027"
SSH_BANNER_TEXT="Authorized access only"
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: BR-SRV ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Сеть ---
check_var "адрес" SRV_ADDR &&
if grep -qF -- "$SRV_ADDR" <(ip -4 -o addr show "$SRV_IF" 2>/dev/null); then
ok "адрес = $SRV_ADDR"
else fail "адрес" "не нашёлся $SRV_ADDR"; fi
check_var "шлюз" SRV_GW &&
expect_eq "шлюз по умолчанию" "$SRV_GW" "$(ip route show default 2>/dev/null | awk '{print $3}')"
# --- 3. Пользователь sshuser ---
check_var "пользователь sshuser" SSH_USER &&
if id "$SSH_USER" &>/dev/null; then
expect_eq "UID $SSH_USER" "$SSH_USER_UID" "$(id -u "$SSH_USER")"
else fail "пользователь $SSH_USER" "нет такого пользователя"; fi
check_var "sudo для sshuser" SSH_USER &&
if root_or_skip "sudo для sshuser"; then
if sudo -ln -U "$SSH_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then
ok "sshuser — sudo без пароля"
else fail "sudo для sshuser" "нет NOPASSWD: ALL"; fi
fi
# --- 4. SSH: порт 2027, только sshuser, 2 попытки, баннер ---
if root_or_skip "sshd -T"; then
T=$(sshd -T 2>/dev/null)
expect_eq "SSH порт" "$SSH_PORT" "$(grep -E "^port " <<<"$T" | awk '{print $2}')"
if grep -E "^allowusers " <<<"$T" | grep -qw "$SSH_USER"; then
ok "SSH AllowUsers = $SSH_USER"
else fail "SSH AllowUsers" "$(grep -E '^allowusers' <<<"$T")"; fi
expect_eq "SSH MaxAuthTries" "2" "$(grep -E "^maxauthtries " <<<"$T" | awk '{print $2}')"
got_banner=$(grep -E "^banner " <<<"$T" | awk '{print $2}')
if [[ -n "$got_banner" ]] && grep -qF "$SSH_BANNER_TEXT" "$got_banner" 2>/dev/null; then
ok "SSH баннер '$SSH_BANNER_TEXT'"
else fail "SSH баннер" "banner=$got_banner"; fi
fi
# --- 5. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — ssh -p 2027 sshuser@<адрес BR-SRV> с другой машины"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

80
check/zadanie1/hq-cli.sh Normal file
View file

@ -0,0 +1,80 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-CLI (только читает состояние!)
# Клиент получает адрес по DHCP от HQ-RTR (VLAN 200): проверяем
# что адрес есть, шлюз и DNS правильные, суффикс домена — в resolv.
# ============================================================
NAME="hq-cli"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="hq-cli.au-team.irpo" # таблица 3
CLI_IF="" # интерфейс, подключённый к VLAN 200
HQ_RTR_ADDR="" # адрес HQ-RTR в VLAN 200 (ожидаемый шлюз)
HQ_SRV_ADDR="" # адрес HQ-SRV (ожидаемый DNS)
DNS_DOMAIN="au-team.irpo" # суффикс по заданию
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: HQ-CLI ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Адрес по DHCP ---
if [[ -n "$CLI_IF" ]]; then
METHOD=$(nmcli -g ipv4.method con show "$CLI_IF" 2>/dev/null)
expect_eq "IPv4 ($CLI_IF) по DHCP" "auto" "$METHOD"
IP4=$(ip -4 -o addr show dev "$CLI_IF" 2>/dev/null | awk '{print $4}')
if [[ -n "$IP4" ]]; then ok "адрес получен по DHCP: $IP4"
else fail "адрес по DHCP" "адреса на $CLI_IF нет (DHCP-сервер на HQ-RTR работает?)"; fi
# DHCP-лизинг фактически выдан NetworkManager
if root_or_skip "файл DHCP-лизинга"; then
LEASE=$(grep -rls "ip_address=" /var/lib/NetworkManager/*.lease 2>/dev/null | head -1)
if [[ -n "$LEASE" ]]; then ok "лизинг DHCP сохранён в $LEASE"
else fail "DHCP-лизинг" "файл лизинга не найден в /var/lib/NetworkManager"; fi
fi
else
skip "адрес по DHCP — не задано CLI_IF"
fi
# --- 3. Шлюз и DNS из DHCP ---
check_var "шлюз = HQ-RTR" HQ_RTR_ADDR &&
expect_eq "шлюз по умолчанию" "$HQ_RTR_ADDR" "$(ip route show default 2>/dev/null | awk '{print $3}')"
check_var "DNS = HQ-SRV" HQ_SRV_ADDR &&
expect_eq "DNS-сервер в resolv.conf" "$HQ_SRV_ADDR" "$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')"
# --- 4. Суффикс домена в resolv.conf ---
check_var "суффикс домена" DNS_DOMAIN &&
if grep -qE "(search|domain) .*$DNS_DOMAIN" /etc/resolv.conf 2>/dev/null; then
ok "суффикс $DNS_DOMAIN в resolv.conf"
else fail "суффикс домена" "нет $DNS_DOMAIN: $(cat /etc/resolv.conf 2>/dev/null)"; fi
# --- 5. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — ping <адрес HQ-SRV> (маршрутизация VLAN 100/200)"
echo " — разрешение имён через новый DNS: dig hq-srv.$DNS_DOMAIN"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

141
check/zadanie1/hq-rtr.sh Normal file
View file

@ -0,0 +1,141 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-RTR (только читает состояние!)
# Пункты ssh/frr/iptables/DHCP требуют root — иначе ПРОПУЩЕНО.
# ============================================================
NAME="hq-rtr"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="hq-rtr.au-team.irpo" # таблица 3
NET_ADMIN_USER="net_admin"
ISP_IF="" # интерфейс к ISP (для маршрута по умолчанию)
VLAN100_IF="vlan100" # имя vlan-подинтерфейса VLAN 100
VLAN100_ADDR="" # адрес роутера в VLAN 100, адрес/префикс
VLAN200_IF="vlan200"
VLAN200_ADDR=""
VLAN999_IF="vlan999"
VLAN999_ADDR=""
GRE_IF="gre1" # имя туннеля
GRE_LOCAL="" # локальный конец туннеля, адрес/префикс
GRE_REMOTE="" # адрес BR-RTR в сети ISP (пингуем через туннель)
OSPF_PASSWORD="P@ssw0rd" # пароль OSPF по заданию
DHCP_PORT_CHECK="67" # порт DHCP-сервера (изменять не нужно)
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: HQ-RTR ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Пользователь net_admin ---
check_var "пользователь net_admin" NET_ADMIN_USER &&
if id "$NET_ADMIN_USER" &>/dev/null; then ok "пользователь $NET_ADMIN_USER существует"
else fail "пользователь $NET_ADMIN_USER" "нет такого пользователя"; fi
check_var "sudo для net_admin" NET_ADMIN_USER &&
if root_or_skip "sudo для net_admin"; then
if sudo -ln -U "$NET_ADMIN_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then
ok "net_admin — sudo без пароля (NOPASSWD: ALL)"
else fail "sudo для net_admin" "нет NOPASSWD: ALL: $(sudo -l -U "$NET_ADMIN_USER" 2>&1 | tail -3)"; fi
fi
# --- 3. VLAN-подинтерфейсы на одном адаптере ---
check_var "адрес в VLAN 100" VLAN100_ADDR &&
if grep -qF -- "$VLAN100_ADDR" <(ip -4 -o addr show "$VLAN100_IF" 2>/dev/null); then
ok "адрес VLAN 100 ($VLAN100_IF) = $VLAN100_ADDR"
else fail "адрес VLAN 100" "на $VLAN100_IF не нашёлся $VLAN100_ADDR"; fi
check_var "адрес в VLAN 200" VLAN200_ADDR &&
if grep -qF -- "$VLAN200_ADDR" <(ip -4 -o addr show "$VLAN200_IF" 2>/dev/null); then
ok "адрес VLAN 200 ($VLAN200_IF) = $VLAN200_ADDR"
else fail "адрес VLAN 200" "на $VLAN200_IF не нашёлся $VLAN200_ADDR"; fi
check_var "адрес в VLAN 999" VLAN999_ADDR &&
if grep -qF -- "$VLAN999_ADDR" <(ip -4 -o addr show "$VLAN999_IF" 2>/dev/null); then
ok "адрес VLAN 999 ($VLAN999_IF) = $VLAN999_ADDR"
else fail "адрес VLAN 999" "на $VLAN999_IF не нашёлся $VLAN999_ADDR"; fi
# --- 4. GRE-туннель ---
check_var "адрес туннеля" GRE_LOCAL &&
if grep -qF -- "$GRE_LOCAL" <(ip -4 -o addr show "$GRE_IF" 2>/dev/null); then
ok "туннель $GRE_IF поднят с $GRE_LOCAL"
else fail "туннель $GRE_IF" "не нашёлся адрес $GRE_LOCAL ($(ip -4 -o addr show "$GRE_IF" 2>/dev/null))"; fi
# --- 5. OSPF: сосед через туннель и аутентификация MD5 ---
if root_or_skip "OSPF (vtysh)"; then
if ! command -v vtysh &>/dev/null; then
skip "OSPF сосед — vtysh не найден (ПРОВЕРИТЬ: пакет/имя OSPF-демона на РЕД ОС 8)"
else
NEIGH_STATE=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full")
if [[ $NEIGH_STATE -ge 1 ]]; then ok "OSPF сосед в FULL (найдено $NEIGH_STATE)"
else fail "OSPF сосед" "нет соседа в Full: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi
if vtysh -c 'show running-config' 2>/dev/null \
| grep -i "message-digest-key" | grep -qiF "$OSPF_PASSWORD"; then
ok "OSPF MD5-аутентификация с паролем $OSPF_PASSWORD"
else fail "OSPF MD5" "ключ/пароль не найдены в ospf-конфиге"; fi
if vtysh -c 'show ip route ospf' 2>/dev/null | grep -q "O "; then
ok "маршруты OSPF присутствуют"
else fail "маршруты OSPF" "нет маршрутов от OSPF"; fi
fi
fi
# --- 6. NAT на выход в сторону ISP ---
if [[ -n "$ISP_IF" ]]; then
if root_or_skip "NAT на ISP-интерфейс"; then
COUNT=$(iptables -t nat -S POSTROUTING 2>/dev/null | grep -cF "$ISP_IF")
if [[ $COUNT -ge 1 ]]; then ok "NAT правило MASQUERADE на $ISP_IF ($COUNT правил)"
else fail "NAT" "нет MASQUERADE на $ISP_IF"; fi
fi
if ip route show default 2>/dev/null | grep -qF "$ISP_IF"; then
ok "маршрут по умолчанию через $ISP_IF"
else fail "маршрут по умолчанию" "через $ISP_IF нет"; fi
else
skip "NAT/маршрут по умолчанию — не задано ISP_IF"
fi
# --- 7. DHCP слушает на 67 ---
if root_or_skip "DHCP-сервер слушает порт $DHCP_PORT_CHECK"; then
if ss -ulnp 2>/dev/null | grep -q ":$DHCP_PORT_CHECK"; then
ok "DHCP слушает порт $DHCP_PORT_CHECK (udp)"
else fail "DHCP порт $DHCP_PORT_CHECK" "ничего не слушает udp/$DHCP_PORT_CHECK"; fi
fi
# --- 8. Связь через туннель (адрес BR-RTR в сети ISP) ---
check_var "связь через туннель" GRE_REMOTE &&
if ping -c2 -W2 "$GRE_REMOTE" &>/dev/null; then ok "ping BR-RTR ($GRE_REMOTE)"
else fail "ping BR-RTR ($GRE_REMOTE)" "недоступен (туннель/OSPF/NAT?)"; fi
# --- 9. IP forwarding ---
FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null)
if [[ "$FWD" == "1" ]]; then ok "ip_forward включён"
else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi
# --- 10. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — DHCP-лизинг на HQ-CLI (скрипт check/zadanie1/hq-cli.sh)"
echo " — vtysh -c 'show ip ospf interface' (протокол только на $GRE_IF?)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

129
check/zadanie1/hq-srv.sh Normal file
View file

@ -0,0 +1,129 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-SRV (только читает состояние!)
# Пункты sshd -T и sudo требуют root — иначе ПРОПУЩЕНО.
# Требует установленный dig (bind-utils): если его нет — DNS
# проверки получат [ПРОПУЩЕНО] с подсказкой.
# ============================================================
NAME="hq-srv"
LOG="check_${NAME}_z1.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="hq-srv.au-team.irpo" # таблица 3
SRV_IF="" # интерфейс к VLAN 100
SRV_ADDR="" # адрес HQ-SRV, адрес/префикс
SRV_GW="" # шлюз (адрес HQ-RTR в VLAN 100)
SSH_PORT="2027" # по заданию 1 п. 5
SSH_USER="sshuser"
SSH_USER_UID="2027" # по заданию 1 п. 3
SSH_BANNER_TEXT="Authorized access only"
# Адреса для DNS-записей (таблица 3)
HQ_RTR_IP="" BR_RTR_IP="" BR_FW_IP="" HQ_CLI_IP=""
BR_SRV_IP="" ISP_TO_HQ_IP="" ISP_TO_BR_IP=""
EXAM_TZ=""
main () {
echo "=== Проверка задания 1: HQ-SRV ==="
# --- 1. Имя хоста ---
check_var "имя хоста" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. Сеть ---
check_var "адрес" SRV_ADDR &&
if grep -qF -- "$SRV_ADDR" <(ip -4 -o addr show "$SRV_IF" 2>/dev/null); then
ok "адрес = $SRV_ADDR"
else fail "адрес" "не нашёлся $SRV_ADDR ($(ip -4 -o addr show 2>/dev/null | grep inet))"; fi
check_var "шлюз" SRV_GW &&
expect_eq "шлюз по умолчанию" "$SRV_GW" "$(ip route show default 2>/dev/null | awk '{print $3}')"
# --- 3. Пользователь sshuser (UID 2027) и sudo ---
check_var "пользователь sshuser" SSH_USER &&
if id "$SSH_USER" &>/dev/null; then
got_uid=$(id -u "$SSH_USER")
expect_eq "UID $SSH_USER" "$SSH_USER_UID" "$got_uid"
else fail "пользователь $SSH_USER" "нет такого пользователя"; fi
check_var "sudo для sshuser" SSH_USER &&
if root_or_skip "sudo для sshuser"; then
if sudo -ln -U "$SSH_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then
ok "sshuser — sudo без пароля"
else fail "sudo для sshuser" "нет NOPASSWD: ALL"; fi
fi
# --- 4. SSH: порт 2027, только sshuser, 2 попытки, баннер ---
if root_or_skip "sshd -T (эффективный конфиг)"; then
T=$(sshd -T 2>/dev/null)
if [[ -z "$T" ]]; then fail "sshd -T" "команда не отработала"
else
got_port=$(grep -E "^port " <<<"$T" | awk '{print $2}')
expect_eq "SSH порт" "$SSH_PORT" "$got_port"
if grep -E "^allowusers " <<<"$T" | grep -qw "$SSH_USER"; then
ok "SSH AllowUsers = $SSH_USER"
else fail "SSH AllowUsers" "$(grep -E '^allowusers' <<<"$T")"; fi
got_tries=$(grep -E "^maxauthtries " <<<"$T" | awk '{print $2}')
expect_eq "SSH MaxAuthTries" "2" "$got_tries"
got_banner=$(grep -E "^banner " <<<"$T" | awk '{print $2}')
if [[ -n "$got_banner" ]] && grep -qF "$SSH_BANNER_TEXT" "$got_banner" 2>/dev/null; then
ok "SSH баннер '$SSH_BANNER_TEXT'"
else fail "SSH баннер" "banner=$got_banner, текст не совпал"; fi
fi
fi
# --- 5. DNS: A- и PTR-записи по таблице 3 ---
if ! command -v dig &>/dev/null; then
skip "DNS-проверки — dig не установлен (dnf install bind-utils)"
else
check_dns_a () {
local RECORD="$1" EXPECT="$2"
local GOT; GOT=$(dig +short "$RECORD" @127.0.0.1 2>/dev/null)
if [[ "$GOT" == "$EXPECT" ]]; then ok "DNS A: $RECORD -> $EXPECT"
else fail "DNS A: $RECORD" "ожидалось '$EXPECT', получено '$GOT'"; fi
}
check_var "DNS hq-rtr" HQ_RTR_IP && check_dns_a "hq-rtr.au-team.irpo" "$HQ_RTR_IP"
check_var "DNS br-rtr" BR_RTR_IP && check_dns_a "br-rtr.au-team.irpo" "$BR_RTR_IP"
check_var "DNS br-fw" BR_FW_IP && check_dns_a "br-fw.au-team.irpo" "$BR_FW_IP"
# PTR для HQ-SRV (адрес = наш собственный, из переменной SRV_ADDR)
check_var "PTR HQ-SRV" SRV_ADDR &&
{ GOT_PTR=$(dig +short -x "${SRV_ADDR%/*}" @127.0.0.1 2>/dev/null)
if grep -q "hq-srv.au-team.irpo" <<<"$GOT_PTR"; then ok "PTR: ${SRV_ADDR%/*} -> hq-srv.au-team.irpo"
else fail "PTR HQ-SRV" "ожидалось 'hq-srv.au-team.irpo', получено '$GOT_PTR'"; fi; }
check_var "DNS hq-cli" HQ_CLI_IP && check_dns_a "hq-cli.au-team.irpo" "$HQ_CLI_IP"
check_var "DNS br-srv" BR_SRV_IP &&
{ check_dns_a "br-srv.au-team.irpo" "$BR_SRV_IP"
GOT_PTR=$(dig +short -x "$BR_SRV_IP" @127.0.0.1 2>/dev/null)
if grep -q "br-srv.au-team.irpo" <<<"$GOT_PTR"; then ok "PTR: $BR_SRV_IP -> br-srv.au-team.irpo"
else fail "PTR BR-SRV" "ожидалось 'br-srv.au-team.irpo', получено '$GOT_PTR'"; fi; }
check_var "DNS docker" ISP_TO_HQ_IP && check_dns_a "docker.au-team.irpo" "$ISP_TO_HQ_IP"
check_var "DNS web" ISP_TO_BR_IP && check_dns_a "web.au-team.irpo" "$ISP_TO_BR_IP"
fi
# --- 6. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную ==="
echo " — ssh -p 2027 sshuser@<адрес HQ-SRV> с другой машины (подключение работает)"
echo " — fork wong вход под другими пользователями по ssh запрещён (MaxAuthTries/AllowUsers)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

113
check/zadanie1/isp.sh Normal file
View file

@ -0,0 +1,113 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 1 — ISP (только читает состояние!)
# Ничего не настраивает и не перезапускает.
# Пункты с iptables требуют root — при запуске от обычного
# пользователя они получат [ПРОПУЩЕНО (нужен root)].
# ============================================================
NAME="isp"
LOG="check_${NAME}_z1.txt"
# ---------- счётчики и мини-функции вывода ----------
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
# Для пунктов, где нужен root (iptables и т.п.)
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
# Для пунктов, где нужна какая-то переменная
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# Сравнение ожидание/факт
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HOSTNAME_EXPECTED="" # полное имя ISP (в таблице 3 записи нет — как задали)
WAN_IF="" # WAN-интерфейс (пример: enp0s3)
HQ_IF="" # интерфейс к HQ-RTR
HQ_NET="" # адрес ISP на этом интерфейсе, адрес/префикс
BR_IF="" # интерфейс к BR-RTR
BR_NET="" # адрес ISP на этом интерфейсе, адрес/префикс
HQ_RTR_ADDR="" # адрес HQ-RTR на линке (для пинга)
BR_RTR_ADDR="" # адрес BR-RTR на линке (для пинга)
EXAM_TZ="" # ожидаемый часовой пояс (например Europe/Moscow)
main () {
echo "=== Проверка задания 1: ISP ==="
# --- 1. Имя хоста ---
check_var "имя хоста (FQDN)" HOSTNAME_EXPECTED &&
expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)"
# --- 2. WAN получает адрес по DHCP (method=auto) ---
if [[ -n "$WAN_IF" ]]; then
METHOD=$(nmcli -g ipv4.method con show "$WAN_IF" 2>/dev/null)
expect_eq "IPv4 WAN ($WAN_IF) по DHCP" "auto" "$METHOD"
IP4=$(ip -4 -o addr show dev "$WAN_IF" 2>/dev/null | awk '{print $4}')
if [[ -n "$IP4" ]]; then ok "WAN получил адрес: $IP4"
else fail "WAN получил адрес" "адреса на $WAN_IF нет"; fi
else
skip "WAN DHCP — не задано WAN_IF"
fi
# --- 3. Статические адреса на линках к роутерам ---
check_var "адрес на $HQ_IF (линк HQ)" HQ_NET &&
if grep -qF -- "$HQ_NET" <(ip -4 -o addr show dev "$HQ_IF" 2>/dev/null); then
ok "адрес на $HQ_IF = $HQ_NET"
else fail "адрес на $HQ_IF" "не нашёлся $HQ_NET в: $(ip -4 -o addr show dev "$HQ_IF" 2>/dev/null)"; fi
check_var "адрес на $BR_IF (линк BR)" BR_NET &&
if grep -qF -- "$BR_NET" <(ip -4 -o addr show dev "$BR_IF" 2>/dev/null); then
ok "адрес на $BR_IF = $BR_NET"
else fail "адрес на $BR_IF" "не нашёлся $BR_NET в: $(ip -4 -o addr show dev "$BR_IF" 2>/dev/null)"; fi
# --- 4. Маршрут по умолчанию через WAN ---
check_var "маршрут по умолчанию к WAN" WAN_IF &&
if ip route show default 2>/dev/null | grep -qF "$WAN_IF"; then
ok "маршрут по умолчанию через $WAN_IF: $(ip route show default)"
else fail "маршрут по умолчанию" "через $WAN_IF нет; маршруты: $(ip route show)"; fi
# --- 5. NAT (MASQUERADE) для сетей HQ-RTR и BR-RTR ---
if root_or_skip "NAT (iptables)"; then
check_var "NAT для сети HQ" HQ_NET && {
if grep -qF "$HQ_NET" <(iptables -t nat -S POSTROUTING 2>/dev/null); then
ok "NAT для $HQ_NET"
else fail "NAT для $HQ_NET" "нет правила MASQUERADE"; fi
}
check_var "NAT для сети BR" BR_NET && {
if grep -qF "$BR_NET" <(iptables -t nat -S POSTROUTING 2>/dev/null); then
ok "NAT для $BR_NET"
else fail "NAT для $BR_NET" "нет правила MASQUERADE"; fi
}
fi
# --- 6. IP forwarding ---
FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null)
if [[ "$FWD" == "1" ]]; then ok "ip_forward включён"
else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi
# --- 7. Связь с роутерами (по адресам из переменных) ---
check_var "связь с HQ-RTR" HQ_RTR_ADDR &&
if ping -c1 -W2 "$HQ_RTR_ADDR" &>/dev/null; then ok "ping HQ-RTR ($HQ_RTR_ADDR)"
else fail "ping HQ-RTR ($HQ_RTR_ADDR)" "недоступен"; fi
check_var "связь с BR-RTR" BR_RTR_ADDR &&
if ping -c1 -W2 "$BR_RTR_ADDR" &>/dev/null; then ok "ping BR-RTR ($BR_RTR_ADDR)"
else fail "ping BR-RTR ($BR_RTR_ADDR)" "недоступен"; fi
# --- 8. Часовой пояс ---
check_var "часовой пояс" EXAM_TZ &&
expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)"
echo ""
echo "=== Проверить вручную: ==="
echo " — доступ в Интернет с ISP: ping -c2 77.88.8.7"
echo " — доступ в Интернет из офисов: с HQ-SRV/BR-SRV ping 77.88.8.7"
echo " — таблицу 2 в отчёте сверить с выводом ip -4 -br a на всех машинах"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

63
check/zadanie2/br-rtr.sh Normal file
View file

@ -0,0 +1,63 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 2 — BR-RTR: DNAT (8080/2027 -> BR-SRV),
# chrony-клиент (сервер = ISP)
# (только читает состояние; iptables требует root)
# ============================================================
NAME="br-rtr"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
BR_SRV_IP="" # адрес BR-SRV
TESTAPP_PORT="8080" # порт testapp
SSH_PORT="2027"
NTP_ADDR="" # адрес ISP (источник NTP)
main () {
echo "=== Проверка задания 2: BR-RTR (DNAT + chrony-клиент) ==="
if root_or_skip "правила DNAT (iptables)"; then
NAT=$(iptables -t nat -S PREROUTING 2>/dev/null)
check_var "адрес BR-SRV" BR_SRV_IP && {
if grep -qF "DNAT --to-destination $BR_SRV_IP:$TESTAPP_PORT" <<<"$NAT" \
|| grep -qF "DNAT --to $BR_SRV_IP:$TESTAPP_PORT" <<<"$NAT"; then
ok "проброс 8080 -> $BR_SRV_IP:$TESTAPP_PORT"
else fail "проброс 8080" "нет DNAT строки в: $NAT"; fi
}
check_var "адрес BR-SRV" BR_SRV_IP && {
if grep -qF "DNAT --to-destination $BR_SRV_IP:$SSH_PORT" <<<"$NAT" \
|| grep -qF "DNAT --to $BR_SRV_IP:$SSH_PORT" <<<"$NAT"; then
ok "проброс 2027 -> $BR_SRV_IP:$SSH_PORT"
else fail "проброс 2027" "нет DNAT строки в: $NAT"; fi
}
fi
# --- chrony-клиент: источник = адрес ISP ---
check_var "источник NTP" NTP_ADDR &&
if command -v chronyc &>/dev/null; then
if chronyc sources 2>/dev/null | grep -qF "$NTP_ADDR"; then
ok "NTP источник = $NTP_ADDR"
else fail "NTP источник" "адрес $NTP_ADDR не найден в chronyc sources: $(chronyc sources 2>&1)"; fi
else skip "NTP источник — chronyc не найден (ПРОВЕРИТЬ пакет chrony)"; fi
echo ""
echo "=== Проверить вручную ==="
echo " — chronyc tracking (синхронизировано?)"
echo " — с ISP: nc -zv <адрес BR-RTR на линке> 2027 и 8080"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

98
check/zadanie2/br-srv.sh Normal file
View file

@ -0,0 +1,98 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 2 — BR-SRV: Samba DC, Ansible, Docker
# (только читает состояние; samba-tool/docker/ansible требуют root)
# ЕДИНСТВЕННАЯ запись — нет: все команды только для чтения
# (docker ps, samba-tool user list, ansible ping — информационный модуль).
# ============================================================
NAME="br-srv"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HQ_USERS_COUNT="5" # по заданию hquser1..5
HQ_GROUP="hq"
MIN_PWD_LENGTH="8" # политика по заданию
LOCKOUT_ATTEMPTS="5" # блокировка по заданию
# sudo-проверка группы hq выполняется на HQ-CLI (check/zadanie2/hq-cli.sh)
main () {
echo "=== Проверка задания 2: BR-SRV (Samba/Ansible/Docker) ==="
# --- 1. Пользователи hquser1..5 ---
if root_or_skip "samba-tool (требует root)"; then
if ! command -v samba-tool &>/dev/null; then
skip "Samba — samba-tool не найден (ПРОВЕРИТЬ установку samba-dc)"
else
USER_LIST=$(samba-tool user list 2>/dev/null)
COUNT_OK=0
for i in $(seq 1 "$HQ_USERS_COUNT"); do
if grep -qx "hquser${i}" <<<"$USER_LIST"; then COUNT_OK=$((COUNT_OK+1));
else fail "пользователь hquser${i}" "не найден в списке домена"; fi
done
[[ $COUNT_OK -eq $HQ_USERS_COUNT ]] && ok "пользователи hquser1..$HQ_USERS_COUNT созданы ($COUNT_OK)"
# --- группа hq ---
if samba-tool group list 2>/dev/null | grep -qx "$HQ_GROUP"; then
ok "группа $HQ_GROUP существует"
MEMBERS=$(samba-tool group listmembers "$HQ_GROUP" 2>/dev/null | grep -c "^hquser")
if [[ $MEMBERS -eq $HQ_USERS_COUNT ]]; then ok "в группе $HQ_GROUP все $HQ_USERS_COUNT пользователей"
else fail "состав группы $HQ_GROUP" "ожидалось $HQ_USERS_COUNT hquser*, найдено $MEMBERS: $(samba-tool group listmembers "$HQ_GROUP" 2>&1)"; fi
else fail "группа $HQ_GROUP" "группа не найдена"; fi
# --- политика паролей ---
POLICY=$(samba-tool domain passwordsettings show 2>/dev/null)
if grep -Eqi "minimum password length.*$MIN_PWD_LENGTH" <<<"$POLICY"; then
ok "минимальная длина пароля = $MIN_PWD_LENGTH"
else fail "длина пароля" "ожидалось $MIN_PWD_LENGTH: $(echo "$POLICY" | grep -i length)"; fi
if grep -Eqi "bad password count.*$LOCKOUT_ATTEMPTS|lockout.*$LOCKOUT_ATTEMPTS" <<<"$POLICY"; then
ok "блокировка после $LOCKOUT_ATTEMPTS неудачных попыток"
else fail "блокировка учётной записи" "ожидалось $LOCKOUT_ATTEMPTS: $(echo "$POLICY" | grep -Ei 'lockout|attempt')"; fi
fi
fi
# --- 2. Ansible: ansible all -m ping (все pong) ---
if command -v ansible &>/dev/null; then
PING_OUT=$(ansible all -m ping 2>&1)
N_OK=$(grep -c "SUCCESS" <<<"$PING_OUT")
N_FAILS=$(grep -c "UNREACHABLE\|failed" <<<"$PING_OUT")
if [[ $N_OK -ge 4 && $N_FAILS -eq 0 ]]; then ok "ansible all -m ping: $N_OK машин ответили"
else fail "ansible ping" "успешных $N_OK (ожидалось ≥4), проблем $N_FAILS"; fi
else
skip "ansible — не установлен/не в PATH (инвентарь в /etc/ansible)"
fi
# --- 3. Docker: контейнеры и порт 8080 ---
if root_or_skip "docker ps / сетевая проверка порта"; then
if command -v docker &>/dev/null; then
CWEB=$(docker ps 2>/dev/null | grep -ciE "site|web|app")
CDB=$(docker ps 2>/dev/null | grep -ciE "mariadb|db")
if [[ $CWEB -ge 1 && $CDB -ge 1 ]]; then
ok "docker: найдено $CWEB контейнер(ов) приложения, $CDB — БД"
else fail "docker контейнеры" "ожидалось приложение + mariadb: $(docker ps 2>&1)"; fi
if curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:8080/" 2>/dev/null | grep -q "200\|301\|302\|401"; then
ok "testapp отвечает на порт 8080 (curl)"
else fail "testapp порт 8080" "нет ответа от локального порта 8080"; fi
else
skip "docker — команда не найдена (ПРОВЕРИТЬ пакет docker на РЕД ОС 8)"
fi
fi
echo ""
echo "=== Проверить вручную ==="
echo " — testapp доступен на 8080 извне: с ISP curl http://<линк к BR-RTR>:8080"
echo " — вход пользователей группы hq на HQ-CLI (см. check/zadanie2/hq-cli.sh)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

100
check/zadanie2/hq-cli.sh Normal file
View file

@ -0,0 +1,100 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЕ 2 — HQ-CLI: automount NFS, chrony, домен, sudo
# для группы hq (только cat/grep/id), Яндекс Браузер
# ЕДИНСТВЕННЫЕ попытка записи — временный файл в NFS (см. пункт 2,
# создаётся и сразу удаляется).
# ============================================================
NAME="hq-cli"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
NFS_MOUNT="/mnt/nfs" # точка автомонтирования по заданию
NFS_SERVER="" # адрес HQ-SRV (проверка записи в auto.nfs)
HQ_USER_TEST="hquser1" # пользователь домена для проверки входа
SUDO_CMDS="/usr/bin/cat /usr/bin/grep /usr/bin/id" # разрешённый список
NTP_ADDR="" # адрес ISP (источник NTP)
BROWSER_PATTERN="yandex" # ищемся через dnf list installed
main () {
echo "=== Проверка задания 2: HQ-CLI ==="
# --- 1. Автомонтирование NFS в /mnt/nfs ---
if root_or_skip "конфиг autofs"; then
if grep -Eq "[[:space:]]*/mnt[[:space:]]+" /etc/auto.master 2>/dev/null; then
ok "auto.master: карта для /mnt присутствует"
else fail "auto.master" "нет записи для /mnt"; fi
if grep -Eq "^[[:space:]]*[a-zA-Z0-9_-]+[[:space:]]+-rw[[:space:]]+.*$NFS_SERVER" /etc/auto.nfs 2>/dev/null; then
echo "[ИНФО] $(cat /etc/auto.nfs 2>/dev/null)"
SKIP=$((SKIP+1))
fi
fi
# смонтированную директорию NFS проверяем её содержимым
# (cat вызывает automount триггер — чистое чтение)
# доступный каталог NFS проверяем чтением (оно же триггерит automount)
if [[ -d "$NFS_MOUNT" ]]; then
ok "каталог $NFS_MOUNT доступен (autofs активен)"
else fail "каталог $NFS_MOUNT" "не открылся (autofs/сервер недоступен)"; fi
# --- 2. ЕДИНСТВЕННЫЙ временный файл в NFS (создаём и сразу удаляем) ---
if [[ -d "$NFS_MOUNT" && -w "$NFS_MOUNT" ]]; then
printf 'tmp %s\n' "$(date +%s)" > "$NFS_MOUNT/.delete-nfs-write-test"
if [[ -f "$NFS_MOUNT/.delete-nfs-write-test" ]]; then
ok "запись в NFS работает (временный файл создан)"
fi
rm -f "$NFS_MOUNT/.delete-nfs-write-test" && ok "временный файл удалён"
else
skip "запись в NFS (не смонтирован $NFS_MOUNT)"
fi
# --- 3. chrony-клиент: источник = ISP ---
check_var "источник NTP" NTP_ADDR &&
if command -v chronyc &>/dev/null; then
if chronyc sources 2>/dev/null | grep -qF "$NTP_ADDR"; then ok "NTP источник = $NTP_ADDR"
else fail "NTP источник" "нет $NTP_ADDR в chronyc sources"; fi
else skip "NTP источник — chronyc не найден"; fi
# --- 4. Пользователь домена доступен (getent) ---
if getent passwd "$HQ_USER_TEST" &>/dev/null; then
ok "пользователь домена $HQ_USER_TEST доступен на машине (getent)"
else fail "пользователь домена $HQ_USER_TEST" "getent не вернул запись (ввод в домен вручную — MANUAL.md)"; fi
# --- 5. Sudo для группы hq (только cat/grep/id) ---
if root_or_skip "sudo -l -U $HQ_USER_TEST"; then
SUDO_OUT=$(sudo -l -U "$HQ_USER_TEST" 2>/dev/null)
CMDS_OK=1
for c in $SUDO_CMDS; do
grep -qw "$(basename "$c")" <<<"$SUDO_OUT" || CMDS_OK=0
done
if [[ $CMDS_OK -eq 1 ]] && ! grep -q "NOPASSWD: ALL" <<<"$SUDO_OUT"; then
ok "sudo для $HQ_USER_TEST: только $(echo "$SUDO_CMDS" | tr ' ' ',')"
else fail "sudo для $HQ_USER_TEST" "список не совпал (есть ALL или нет всех команд): $(echo "$SUDO_OUT" | grep NOPASSWD)"; fi
fi
# --- 6. Яндекс Браузер ---
if dnf list installed 2>/dev/null | grep -qiF "$BROWSER_PATTERN"; then
ok "Яндекс Браузер установлен ($(dnf list installed 2>/dev/null | grep -iF "$BROWSER_PATTERN"))"
else fail "Яндекс Браузер" "пакет не найден в dnf list installed"; fi
echo ""
echo "=== Проверить вручную ==="
echo " — запуск Яндекс Браузера с рабочего стола (если GUI есть)"
echo " — реальные входы доменных пользователей в систему (экран входа/GUI или su -)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

59
check/zadanie2/hq-rtr.sh Normal file
View file

@ -0,0 +1,59 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 2 — HQ-RTR: статический проброс портов (DNAT)
# 8080 -> веб-приложение на HQ-SRV, 2027 -> SSH HQ-SRV
# (только читает состояние; iptables требует root)
# ============================================================
NAME="hq-rtr"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
HQ_SRV_IP="" # адрес HQ-SRV (без префикса)
WEB_APP_PORT="80" # порт apache на HQ-SRV (как в настройке)
SSH_PORT="2027" # порт ssh на HQ-SRV
main () {
echo "=== Проверка задания 2: HQ-RTR (DNAT) ==="
if root_or_skip "правила DNAT (iptables)"; then
NAT=$(iptables -t nat -S PREROUTING 2>/dev/null)
check_var "адрес HQ-SRV" HQ_SRV_IP && {
if grep -qF "DNAT --to-destination $HQ_SRV_IP:$WEB_APP_PORT" <<<"$NAT" \
|| grep -qF "DNAT --to $HQ_SRV_IP:$WEB_APP_PORT" <<<"$NAT"; then
ok "проброс 8080 -> $HQ_SRV_IP:$WEB_APP_PORT"
else fail "проброс 8080" "нет DNAT строки в: $NAT"; fi
}
check_var "адрес HQ-SRV" HQ_SRV_IP && {
if grep -qF "DNAT --to-destination $HQ_SRV_IP:$SSH_PORT" <<<"$NAT" \
|| grep -qF "DNAT --to $HQ_SRV_IP:$SSH_PORT" <<<"$NAT"; then
ok "проброс 2027 -> $HQ_SRV_IP:$SSH_PORT"
else fail "проброс 2027" "нет DNAT строки в: $NAT"; fi
}
POLICY=$(iptables -S FORWARD 2>/dev/null | head -1)
if grep -q "policy" <<<"$POLICY"; then
echo "[ИНФО] $POLICY"
SKIP=$((SKIP+1))
fi
fi
echo ""
echo "=== Проверить вручную ==="
echo " — с ISP: curl -I http://<адрес HQ-RTR на линке>:8080 (доступ к веб-приложению извне)"
echo " — с ISP: nc -zv <адрес HQ-RTR на линке> 2027"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

104
check/zadanie2/hq-srv.sh Normal file
View file

@ -0,0 +1,104 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 2 — HQ-SRV: RAID0, NFS, chrony, apache+mariadb
# (только читает состояние; exportfs/mdadm-детали требуют root)
# ============================================================
NAME="hq-srv"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
RAID_NAME="md0" # имя массива по заданию
RAID_MOUNT="/raid" # точка монтирования по заданию
NFS_EXPORT="/raid/nfs" # директория экспорта по заданию
NFS_NET="" # сеть HQ-CLI (как в exports)
APACHE_PORT="80" # порт apache
WEB_DB_NAME="webdb" # БД по заданию
WEB_DB_USER="web" # пользователь БД по заданию
WEB_DB_PASS="P@ssw0rd" # пароль пользователя БД по заданию
ISO_WEB_DIR="/mnt/iso/web" # откуда копировались файлы (для справки)
NTP_ADDR="" # адрес ISP (chrony)
main () {
echo "=== Проверка задания 2: HQ-SRV ==="
# --- 1. RAID0 (md0) ---
if [[ -e /dev/$RAID_NAME ]] || grep -q "$RAID_NAME" /proc/mdstat 2>/dev/null; then
if grep -A1 "$RAID_NAME" /proc/mdstat 2>/dev/null | grep -q "raid0"; then
ok "массив $RAID_NAME собран уровнем 0"
else fail "уровень $RAID_NAME" "не raid0 в /proc/mdstat: $(grep -A1 "$RAID_NAME" /proc/mdstat 2>/dev/null)"; fi
DISKS=$(grep -A1 "$RAID_NAME" /proc/mdstat 2>/dev/null | head -1 | grep -o "\[2/2\]")
if [[ -n "$DISKS" ]]; then ok "в массиве 2 диска ($DISKS)"
else fail "диски массива" "ожидалось [2/2]: $(grep -A1 "$RAID_NAME" /proc/mdstat)"; fi
else
fail "массив $RAID_NAME" "не существует"; fi
# --- 2. ФС ext4 и монтирование /raid ---
FSTYP=$(lsblk -no FSTYPE /dev/$RAID_NAME 2>/dev/null)
expect_eq "файловая система $RAID_NAME" "ext4" "$FSTYP"
if mountpoint -q "$RAID_MOUNT" 2>/dev/null; then
ok "$RAID_MOUNT смонтирована"
else fail "$RAID_MOUNT" "не точка монтирования"; fi
if grep -qE " .*$RAID_MOUNT " /etc/fstab 2>/dev/null \
&& grep -E " .*$RAID_MOUNT .*ext4" /etc/fstab &>/dev/null; then
ok "/raid прописан в /etc/fstab"
else fail "/raid в fstab" "нет строки с $RAID_MOUNT (ext4): $(grep -E "raid" /etc/fstab)"; fi
# --- 3. NFS ---
if grep -qF "$NFS_EXPORT" /etc/exports 2>/dev/null; then
EXPORT_LINE=$(grep -F "$NFS_EXPORT" /etc/exports)
if check_var "сеть HQ-CLI для NFS" NFS_NET && grep -qF "$NFS_NET" <<<"$EXPORT_LINE" \
&& grep -qw "rw" <<<"$EXPORT_LINE"; then
ok "NFS экспорт: $EXPORT_LINE"
else fail "NFS экспорт" "нет rw для $NFS_NET: '$EXPORT_LINE'"; fi
else fail "NFS экспорт $NFS_EXPORT" "нет строки в /etc/exports"; fi
if root_or_skip "exportfs (текущее состояние NFS)"; then
if exportfs -v 2>/dev/null | grep -qF "$NFS_EXPORT"; then
ok "NFS экспорт активен (exportfs)"
else fail "NFS экспорт активен" "нет в exportfs -v"; fi
fi
# --- 4. chrony-клиент ---
check_var "источник NTP" NTP_ADDR &&
if command -v chronyc &>/dev/null; then
if chronyc sources 2>/dev/null | grep -qF "$NTP_ADDR"; then ok "NTP источник = $NTP_ADDR"
else fail "NTP источник" "нет $NTP_ADDR в chronyc sources"; fi
else skip "NTP источник — chronyc не найден (ПРОВЕРИТЬ пакет chrony)"; fi
# --- 5. apache + mariadb + приложение ---
if systemctl is-active httpd &>/dev/null || systemctl is-active apache2 &>/dev/null; then
ok "веб-сервер apache активен"
else fail "apache" "служба не активна (ПРОВЕРИТЬ имя службы на РЕД ОС 8)"; fi
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$APACHE_PORT/" 2>/dev/null)
if [[ "$HTTP_CODE" == "200" ]]; then ok "apache отвечает 200 на порт $APACHE_PORT"
else fail "ответ apache" "ожидалось 200, получено '$HTTP_CODE'"; fi
if [[ -f /var/www/html/index.php && -f /var/www/html/logo.png ]]; then
ok "index.php и logo.png в корне сайта"
else fail "файлы сайта" "нет index.php/logo.png в /var/www/html"; fi
MYSQL_OUT=$(mysql -u"$WEB_DB_USER" -p"$WEB_DB_PASS" -e "SHOW TABLES;" "$WEB_DB_NAME" 2>&1)
if grep -q "Tables_in" <<<"$MYSQL_OUT"; then
ok "доступ к БД $WEB_DB_NAME под $WEB_DB_USER (таблицы есть)"
else fail "БД $WEB_DB_NAME" "нет таблиц или ошибка подключения: $MYSQL_OUT"; fi
echo ""
echo "=== Проверить вручную ==="
echo " — страница приложения в браузере (функционал, картинка logo.png)"
echo " — содержимое index.php (учётные данные БД указаны правильно)"
echo " — скриншоты для отчёта: exportfs -v, mdadm --D dev/md0, df -h /raid"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

67
check/zadanie2/isp.sh Normal file
View file

@ -0,0 +1,67 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 2 — ISP: chrony-сервер, стратум 5
# (только читает состояние)
# ============================================================
NAME="isp"
LOG="check_${NAME}_z2.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
CHRONY_CONF="/etc/chrony.conf" # ПРОВЕРИТЬ путь на РЕД ОС 8
STRATUM_EXPECTED="5" # по заданию 2 п. 4
ALLOW_NETS="" # сети клиентов, через пробел (как в isp.sh настройки)
main () {
echo "=== Проверка задания 2: ISP (chrony) ==="
# --- 1. Стратум 5 ---
if command -v chronyc &>/dev/null; then
GOT_STRATUM=$(chronyc tracking 2>/dev/null | awk '/^Stratum/ {print $2}')
if [[ "$GOT_STRATUM" == "$STRATUM_EXPECTED" ]]; then ok "стратум = $GOT_STRATUM"
else fail "стратум" "ожидалось $STRATUM_EXPECTED, получено '$GOT_STRATUM'"; fi
# служба активна
if systemctl is-active chronyd &>/dev/null; then ok "служба chronyd активна"
else fail "служба chronyd" "не активна (ПРОВЕРИТЬ имя службы на РЕД ОС 8)"; fi
else
skip "chronyc — не найден (ПРОВЕРИТЬ пакет chrony)"
fi
# --- 2. Разрешено доступ для клиентских сетей (allow) ---
NETS_OK=0; NETS_TOTAL=0
for NET in $ALLOW_NETS; do
NETS_TOTAL=$((NETS_TOTAL+1))
if grep -qE "^allow[[:space:]]+$NET" "$CHRONY_CONF" 2>/dev/null; then
NETS_OK=$((NETS_OK+1))
else fail "allow $NET" "нет строки в $CHRONY_CONF"; fi
done
if [[ $NETS_TOTAL -eq 0 ]]; then skip "allow-сети — не задано ALLOW_NETS"
elif [[ $NETS_OK -eq $NETS_TOTAL ]]; then ok "allow для всех $NETS_TOTAL сетей клиентов"
fi
# --- 3. Сервер NTP слушает 123/udp ---
if root_or_skip "порт NTP (ss)"; then
if ss -uln 2>/dev/null | grep -q ":123 "; then ok "NTP слушает udp/123"
else fail "NTP порт 123" "не слушает (chronyd: allow без локального статуса?)"; fi
fi
echo ""
echo "=== Проверить вручную ==="
echo " — chronyc clients (кто реально опрашивает)"
echo " — chronyc sources точно сообщает о вышестоящем сервере"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

73
check/zadanie3/br-srv.sh Normal file
View file

@ -0,0 +1,73 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЕ 3 — BR-SRV: импорт пользователей, PC-INFO
# (только читает состояние; samba-tool требует root)
# Кибер Бэкап сервер — вручную (в конце список).
# ============================================================
NAME="br-srv"
LOG="check_${NAME}_z3.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
EXPECTED_USERS="" # список имён из users.csv через пробел (заполните после импорта)
# если пусто — пункт [ПРОПУЩЕНО], проверяем только факт import
ANSIBLE_DIR="/etc/ansible"
REPORT_DIR="$ANSIBLE_DIR/PC-INFO" # отчёты инвентаризации по заданию
EXPECTED_REPORTS="hq-srv hq-cli" # имена файлов-отчётов = имена ПК (коротные из hostname,
# без домена — уточните: с точками или подчёркиваниями?)
main () {
echo "=== Проверка задания 3: BR-SRV ==="
# --- 1. Импорт пользователей из users.csv ---
if root_or_skip "samba-tool (требует root)"; then
if ! command -v samba-tool &>/dev/null; then
skip "samba-tool — не найден"
elif [[ -n "$EXPECTED_USERS" ]]; then
USER_LIST=$(samba-tool user list 2>/dev/null)
for USER in $EXPECTED_USERS; do
if grep -qx "$USER" <<<"$USER_LIST"; then ok "импортирован $USER"
else fail "импорт $USER" "не найден в списке домена"; fi
done
else
N_TOTAL=$(samba-tool user list 2>/dev/null | wc -l)
if [[ $N_TOTAL -gt 5 ]]; then
ok "доменных пользователей больше 5 (сверх hquser1–5): $N_TOTAL"
else fail "импорт пользователей" "в домене только $N_TOTAL пользователей — import.sh не выполнен?"
fi
fi
fi
# --- 2. Отчёты PC-INFO (.yml, имя файла = имя ПК) ---
if [[ -d "$REPORT_DIR" ]]; then
YML_COUNT=$(ls "$REPORT_DIR"/*.yml 2>/dev/null | wc -l)
if [[ $YML_COUNT -ge 2 ]]; then ok "в $REPORT_DIR есть $YML_COUNT отчёт(ов) .yml"
else fail "отчёты $REPORT_DIR" "ожидалось ≥2 .yml файлов, найдено $YML_COUNT"; fi
for PC in $EXPECTED_REPORTS; do
if ls "$REPORT_DIR"/$PC*.yml &>/dev/null; then ok "отчёт для $PC присутствует ($(ls "$REPORT_DIR"/$PC*.yml 2>/dev/null | head -1))"
else fail "отчёт $PC" "файла вида $PC*.yml нет (имена могут отличаться — см. переменную EXPECTED_REPORTS)"; fi
done
else
fail "каталог $REPORT_DIR" "не существует"
fi
echo ""
echo "=== Проверить вручную ==="
echo " — открыть один .yml файл: там имя ПК и IP-адрес"
echo " — Кибер Бэкап сервер HQ-SRV работает (скриншот консоли/данные резервных проверок)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

80
check/zadanie3/hq-cli.sh Normal file
View file

@ -0,0 +1,80 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 3 — HQ-CLI: доверие CA, https без -k,
# принтер по умолчанию, каталог /backup
# (только читает состояние!) Агент Кибер Бэкап — вручную.
# ============================================================
NAME="hq-cli"
LOG="check_${NAME}_z3.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
CA_ANCHORS_DIR="/etc/pki/ca-trust/source/anchors" # ПРОВЕРИТЬ на РЕД ОС 8
CA_CN="au-team-CA" # CN корневого сертификата (переменная CA_SUBJECT)
WEB_DOMAIN="web.au-team.irpo"
DOCKER_DOMAIN="docker.au-team.irpo"
WEB_LOGIN="WEB" # по заданию 3 п. 3
WEB_PASS="P@ssw0rd"
CLIENT_PRINTER="pdf_printer" # локальное имя принтера на HQ-CLI
BACKUP_DIR="/backup" # каталог хранилища по заданию 3 п. 9
main () {
echo "=== Проверка задания 3: HQ-CLI ==="
# --- 1. Доверие корневому сертификату (установлен в хранилище) ---
if [[ -d "$CA_ANCHORS_DIR" ]] && ls "$CA_ANCHORS_DIR" | grep -q .; then
LISTED=$(ls "$CA_ANCHORS_DIR" | tr '\n' ' ')
echo "[ИНФО] в anchors: $LISTED"
SKIP=$((SKIP+1)) # ПРОВЕРИТЬ: имя файла бывает любым — критерий ниже через trust list
if command -v trust &>/dev/null; then
if trust list 2>/dev/null | grep -q "cn.*$CA_CN"; then ok "корневой сертификат ($CA_CN) в хранилище"
else fail "корневой CA" "$CA_CN не найден в trust list"; fi
else skip "trust list — команда trust не найдена (ПРОВЕРИТЬ на РЕД ОС 8)"
fi
else
fail "anchors $CA_ANCHORS_DIR" "каталог не найден или пуст — файл CA доставлен вручную?"
fi
# --- 2. https без предупреждений (curl без -k) ---
check_var "web-домен" WEB_DOMAIN &&
{ CODE=$(curl -s -o /dev/null -w "%{http_code}" -u "$WEB_LOGIN:$WEB_PASS" "https://$WEB_DOMAIN/" 2>/dev/null)
if grep -qE "^(200|301|302)$" <<<"$CODE"; then ok "https://$WEB_DOMAIN — соединение без ошибок сертификата (код $CODE)"
else fail "https $WEB_DOMAIN" "код '$CODE' (0 = ошибка соединения/сертификата)"; fi; }
check_var "docker-домен" DOCKER_DOMAIN &&
{ CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOCKER_DOMAIN/" 2>/dev/null)
if grep -qE "^(200|301|302)$" <<<"$CODE"; then ok "https://$DOCKER_DOMAIN — без ошибок сертификата ($CODE)"
else fail "https $DOCKER_DOMAIN" "код '$CODE'"; fi; }
# --- 3. Принтер по умолчанию ---
if command -v lpstat &>/dev/null; then
DEFAULT_P=$(lpstat -d 2>/dev/null | awk '{print $NF}')
expect_eq "принтер по умолчанию" "$CLIENT_PRINTER" "$DEFAULT_P"
if lpstat -p "$CLIENT_PRINTER" &>/dev/null; then ok "принтер $CLIENT_PRINTER зарегистрирован"
else fail "принтер $CLIENT_PRINTER" "не найден в lpstat -p"; fi
else skip "lpstat — утилита CUPS не найдена (dnf install cups)"; fi
# --- 4. Каталог /backup (узел хранилища) ---
if [[ -d "$BACKUP_DIR" ]]; then ok "каталог $BACKUP_DIR существует"
else fail "каталог $BACKUP_DIR" "не найден"; fi
echo ""
echo "=== Проверить вручную ==="
echo " — установка агента Кибер Бэкап на HQ-CLI (GUI), подключение к HQ-SRV"
echo " — предупреждения браузера (откройте страницу в Яндекс Браузере)"
echo " — печать: echo test | lp -d $CLIENT_PRINTER; проверьте появление pdf у принтера"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

116
check/zadanie3/hq-srv.sh Normal file
View file

@ -0,0 +1,116 @@
#!/bin/bash
# ============================================================
# ПРОВЕРКА ЗАДАНИЯ 3 — HQ-SRV: сертификаты, atop, CUPS, fail2ban
# (только читает состояние; openssl / lpstat / fail2ban-client
# могут требовать root — иначе ПРОПУЩЕНО)
# Кибер Бэкап — вручную (в конце список).
# ============================================================
NAME="hq-srv"
LOG="check_${NAME}_z3.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
CA_DIR="/etc/CA" # каталог ЦС из настройки
CERT_NAMES="web.au-team.irpo docker.au-team.irpo" # домены, которые выданы
ATOP_CONF="/etc/sysconfig/atop" # ПРОВЕРИТЬ путь на РЕД ОС 8
ATOP_INTERVAL="420" # интервал 7 минут (в секундах)
PDF_PRINTER="pdf" # принтер по заданию
F2B_SSH_PORT="2027" # порт ssh (fail2ban)
F2B_JAIL="/etc/fail2ban/jail.d/exam.local"
F2B_BANTIME="60" # бан 1 минута (в секундах)
F2B_MAXRETRY="3" # 3 попытки
BACKUP_SERVICE_PATTERN="cyber|backup" # ПРОВЕРИТЬ: как называется служба на стенде
main () {
echo "=== Проверка задания 3: HQ-SRV ==="
# --- 1. Сертификаты: срок (не менее ~29 дней) и цепочка ---
if command -v openssl &>/dev/null; then
KNOWN_DAYS_LEFT=$((29*24*3600)) # допустимая погрешность округления (выдан "на 30 дней")
check_var "каталог ЦС" CA_DIR &&
for NAME in $CERT_NAMES; do
CRT="$CA_DIR/$NAME.crt"
if [[ -f "$CRT" ]]; then
# проверка срока действия через -checkend
if openssl x509 -in "$CRT" -checkend "$KNOWN_DAYS_LEFT" &>/dev/null; then
ok "сертификат $NAME: срок действия ≥ 29 дней (выдан на 30)"
else fail "срок $NAME" "остаётся < 29 дней или сертификат не читается: $(openssl x509 -in "$CRT" -dates 2>&1)"; fi
# цепочка: подписан нашим CA
if openssl verify -CAfile "$CA_DIR/root.crt" "$CRT" 2>/dev/null | grep -q "OK"; then
ok "сертификат $NAME — подписан корневым $CA_DIR/root.crt"
else fail "цепочка $NAME" "verify: $(openssl verify -CAfile "$CA_DIR/root.crt" "$CRT" 2>&1)"; fi
# SAN
if openssl x509 -in "$CRT" -noout -ext subjectAltName 2>/dev/null | grep -qF "DNS:$NAME"; then
ok "SAN $NAME корректен"
else fail "SAN $NAME" "нет DNS:$NAME в subjectAltName"; fi
else
fail "сертификат $NAME" "файл $CRT не найден"; fi
done
else
skip "сертификаты — openssl не установлен"
fi
# --- 2. atop: интервал 420 c и служба ---
if [[ -f "$ATOP_CONF" ]]; then
GOT_INT=$(grep -E "^INTERVAL=|^LOGINTERVAL=" "$ATOP_CONF" | head -1)
if grep -qE "(=|=)$ATOP_INTERVAL" <<<"$GOT_INT"; then ok "atop: интервал $ATOP_INTERVAL с (7 минут)"
else fail "atop интервал" "ожидалось $ATOP_INTERVAL: $GOT_INT"; fi
else skip "atop конфиг — $ATOP_CONF не найден (ПРОВЕРИТЬ путь/имя параметров на РЕД ОС 8)"; fi
if systemctl is-active atop &>/dev/null; then ok "служба atop активна"
else fail "atop служба" "не активна (ПРОВЕРИТЬ имя службы)"; fi
# --- 3. CUPS: pdf-принтер, слушает 631 ---
if command -v lpstat &>/dev/null; then
PINFO=$(lpstat -p 2>/dev/null)
if grep -qw "$PDF_PRINTER" <<<"$PINFO" && ! grep -q "disabled" <<<"$PINFO"; then
ok "принтер $PDF_PRINTER опубликован и активен"
else fail "принтер $PDF_PRINTER" "не активен/отсутствует: $PINFO"; fi
if root_or_skip "проверка порта 631"; then
if ss -tln 2>/dev/null | grep -q ":631 "; then ok "CUPS слушает порт 631"
else fail "порт 631" "не слушает (сеть HQ-CLI не подключится к CUPS)"; fi
fi
else skip "CUPS — не установлен (ПРОВЕРИТЬ пакет cups)"; fi
# --- 4. fail2ban: порт 2027, попыток 3, ban 60 c ---
if command -v fail2ban-client &>/dev/null; then
if root_or_skip "fail2ban-client статус"; then
if fail2ban-client status sshd &>/dev/null; then ok "fail2ban: jail sshd активен"
else fail "fail2ban sshd" "статус не получен: $(fail2ban-client status sshd 2>&1)"; fi
BT=$(fail2ban-client get sshd bantime 2>/dev/null)
expect_eq "fail2ban bantime" "$F2B_BANTIME" "$BT"
MR=$(fail2ban-client get sshd maxretry 2>/dev/null)
expect_eq "fail2ban maxretry" "$F2B_MAXRETRY" "$MR"
fi
if grep -Eq "port.*$F2B_SSH_PORT" "$F2B_JAIL" 2>/dev/null; then ok "jail использует порт $F2B_SSH_PORT"
else fail "fail2ban порт" "нет $F2B_SSH_PORT в $F2B_JAIL"; fi
else skip "fail2ban — не установлен (ПРОВЕРИТЬ пакет/репозиторий на РЕД ОС 8)"; fi
# --- 5. Служба резервного копирования (Кибер Бэкап) ---
if systemctl list-unit-files 2>/dev/null | grep -qiE "$BACKUP_SERVICE_PATTERN"; then
echo "[ИНФО] найдены службы: $(systemctl list-unit-files 2>/dev/null | grep -iE "$BACKUP_SERVICE_PATTERN" | awk '{print $1}' | tr '\n' ' ')"
SKIP=$((SKIP+1))
else fail "служба резервного копирования" "ничего не найдено по шаблону '$BACKUP_SERVICE_PATTERN' (ПРОВЕРИТЬ имя службы в QUESTIONS.md)"; fi
echo ""
echo "=== Проверить вручную ==="
echo " — единица бэкапа настроена (GUI Кибер Бэкап на HQ-SRV)"
echo " — бэкап директории /etc выполняется на узел HQ-CLI (скриншоты)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS

73
check/zadanie3/isp.sh Normal file
View file

@ -0,0 +1,73 @@
# ПРОВЕРКА ЗАДАНИЕ 3 — ISP: реверс-прокси, web-аутентификация
# Проверяем через curl на самом ISP (nginx слушает 80/443 на всех
# интерфейсах; доменные имена подставляем HOST-заголовком, т.к.
# собственный DNS ISP про локальные записи не знает).
# ============================================================
NAME="isp"
LOG="check_${NAME}_z3.txt"
OK=0; FAIL=0; SKIP=0
ok() { echo "[OK] $1"; OK=$((OK+1)); }
fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); }
skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); }
check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; }
expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; }
# ================= ПЕРЕМЕННЫЕ (заполните для проверки) =================
WEB_DOMAIN="web.au-team.irpo" # таблица 3
DOCKER_DOMAIN="docker.au-team.irpo" # таблица 3
WEB_LOGIN="WEB" # по заданию
WEB_PASS="P@ssw0rd" # по заданию
TLS_MODE="" # "https" — если прокси уже на 443, иначе пусто
TLS_CERT_FILE="" # путь к сертификату на ISP (для пункта 4)
main () {
echo "=== Проверка задания 3: ISP (реверс-прокси) ==="
# --- 1. Служба прокси ---
if [[ "$TLS_MODE" == "https" ]]; then
EXPECT_PORT="443"
else
EXPECT_PORT="80"
fi
if ss -tln 2>/dev/null | grep -q "80 "; then ok "сервер слушает порт 80"
else fail "порт 80" "не слушает (nginx?)"; fi
if [[ "$TLS_MODE" == "https" ]]; then
if ss -tln 2>/dev/null | grep -q "443 "; then ok "сервер слушает порт 443 (TLS)"
else fail "порт 443" "не слушает — TLS не настроен"; fi
fi
# --- 2. docker.au-team.irpo — открывается testapp (без пароля) ---
check_var "docker-домен" DOCKER_DOMAIN &&
{ CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: $DOCKER_DOMAIN" "http://127.0.0.1/" 2>/dev/null)
if grep -qE "^(200|301|302)$" <<<"$CODE"; then ok "$DOCKER_DOMAIN: testapp отвечает ($CODE)"
else fail "$DOCKER_DOMAIN" "ожидалось 200/301/302, получено '$CODE'"; fi; }
# --- 3. web.au-team.irpo — аутентификация: 401 без пароля, 200 с паролем ---
check_var "web-домен" WEB_DOMAIN &&
{ CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: $WEB_DOMAIN" "http://127.0.0.1/" 2>/dev/null)
if [[ "$CODE" == "401" ]]; then ok "$WEB_DOMAIN без пароля: 401 (требует аутентификации)"
else fail "$WEB_DOMAIN без пароля" "ожидалось 401, получено '$CODE'"; fi
CODE=$(curl -s -o /dev/null -w "%{http_code}" -u "$WEB_LOGIN:$WEB_PASS" -H "Host: $WEB_DOMAIN" "http://127.0.0.1/" 2>/dev/null)
if grep -qE "^(200|301|302)$" <<<"$CODE"; then ok "$WEB_DOMAIN c $WEB_LOGIN:$WEB_PASS: $CODE"
else fail "$WEB_DOMAIN с паролем" "ожидалось 200/301/302, получено '$CODE'"; fi; }
# --- 4. TLS-сертификаты (для режима https) ---
check_var "сертификат TLS" TLS_CERT_FILE &&
{ if openssl x509 -in "$TLS_CERT_FILE" -noout 2>/dev/null; then ok "tls cert поднят: $TLS_CERT_FILE"
else fail "TLS сертификат" "файл не читается: $TLS_CERT_FILE"; fi; }
echo ""
echo "=== Проверить вручную ==="
echo " — браузер клиента: https://web.au-team.irpo (без предупреждений, ввод логина)"
echo " — https://docker.au-team.irpo без предупреждений (снято на HQ-CLI/hq-cli.sh)"
echo ""
echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ==="
[[ $FAIL -eq 0 ]]
}
main 2>&1 | tee "$LOG"
STATUS=${PIPESTATUS[0]}
echo "Лог сохранён: $LOG"
exit $STATUS