diff --git a/linux1/application/app.py b/linux1/application/app.py new file mode 100644 index 0000000..edb9fa6 --- /dev/null +++ b/linux1/application/app.py @@ -0,0 +1,24 @@ +from flask import Flask, request, jsonify + +app = Flask(__name__) + + +@app.route("/get", methods=["GET"]) +def handle_get(): + return jsonify({"method": "GET", "message": "Hello from GET endpoint"}), 200 + + +@app.route("/post", methods=["POST"]) +def handle_post(): + data = request.get_json(silent=True) or {} + return jsonify({"method": "POST", "message": "Hello from POST endpoint", "received": data}), 200 + + +@app.route("/put", methods=["PUT"]) +def handle_put(): + data = request.get_json(silent=True) or {} + return jsonify({"method": "PUT", "message": "Hello from PUT endpoint", "received": data}), 200 + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) diff --git a/linux1/configs/linux_a/netplan/00-installer-config.yaml b/linux1/configs/linux_a/netplan/00-installer-config.yaml new file mode 100644 index 0000000..bfe9f3e --- /dev/null +++ b/linux1/configs/linux_a/netplan/00-installer-config.yaml @@ -0,0 +1,11 @@ +network: + ethernets: + enp0s3: + # Bridge adapter — access from host machine + dhcp4: true + enp0s8: + # Internal network "servernet" — communication with VM B + dhcp4: no + addresses: [192.168.13.10/24] + gateway4: 192.168.13.1 + version: 2 diff --git a/linux1/configs/linux_a/systemd/web-server.service b/linux1/configs/linux_a/systemd/web-server.service new file mode 100644 index 0000000..942fd4f --- /dev/null +++ b/linux1/configs/linux_a/systemd/web-server.service @@ -0,0 +1,14 @@ +[Unit] +Description=Flask Web Server +After=network.target + +[Service] +Type=simple +User=kulakov_1 +WorkingDirectory=/home/kulakov_1/server/ +ExecStart=/usr/bin/python3 /home/kulakov_1/server/app.py +Restart=on-failure +RestartSec=3 + +[Install] +WantedBy=multi-user.target diff --git a/linux1/configs/linux_b/iptables/setup_iptables.sh b/linux1/configs/linux_b/iptables/setup_iptables.sh new file mode 100644 index 0000000..e7df9c3 --- /dev/null +++ b/linux1/configs/linux_b/iptables/setup_iptables.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# IP Forwarding — enable kernel packet forwarding between interfaces +echo 1 > /proc/sys/net/ipv4/ip_forward +sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf + +# Allow NEW connections from clientnet (enp0s9) to servernet (enp0s8) only on port 5000 +iptables -A FORWARD -i enp0s9 -o enp0s8 -p tcp --syn --dport 5000 -m conntrack --ctstate NEW -j ACCEPT + +# Allow established/related packets in both directions +iptables -A FORWARD -i enp0s9 -o enp0s8 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -A FORWARD -i enp0s8 -o enp0s9 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Drop everything else in FORWARD chain +iptables -P FORWARD DROP + +# NAT: masquerade packets going from clientnet to servernet +iptables -t nat -A POSTROUTING -o enp0s8 -j MASQUERADE + +# Save rules so they persist after reboot +apt-get install -y iptables-persistent +iptables-save > /etc/iptables/rules.v4 +ip6tables-save > /etc/iptables/rules.v6 + +echo "iptables rules applied and saved." diff --git a/linux1/configs/linux_b/netplan/00-installer-config.yaml b/linux1/configs/linux_b/netplan/00-installer-config.yaml new file mode 100644 index 0000000..41cf1d6 --- /dev/null +++ b/linux1/configs/linux_b/netplan/00-installer-config.yaml @@ -0,0 +1,14 @@ +network: + ethernets: + enp0s3: + # Bridge adapter — access from host machine + dhcp4: true + enp0s8: + # Internal network "servernet" — gateway side facing VM A + dhcp4: no + addresses: [192.168.13.1/24] + enp0s9: + # Internal network "clientnet" — gateway side facing VM C + dhcp4: no + addresses: [192.168.8.1/24] + version: 2 diff --git a/linux1/configs/linux_c/netplan/00-installer-config.yaml b/linux1/configs/linux_c/netplan/00-installer-config.yaml new file mode 100644 index 0000000..ce94359 --- /dev/null +++ b/linux1/configs/linux_c/netplan/00-installer-config.yaml @@ -0,0 +1,11 @@ +network: + ethernets: + enp0s3: + # Bridge adapter — access from host machine + dhcp4: true + enp0s8: + # Internal network "clientnet" — communication with VM B + dhcp4: no + addresses: [192.168.8.10/24] + gateway4: 192.168.8.1 + version: 2 diff --git a/linux1/docker-compose.yml b/linux1/docker-compose.yml new file mode 100644 index 0000000..330a988 --- /dev/null +++ b/linux1/docker-compose.yml @@ -0,0 +1,59 @@ +services: + linux_a: + image: alpine:3.19 + container_name: kulakov_server + hostname: kulakov_server + networks: + servernet: + ipv4_address: 192.168.13.10 + privileged: true + tty: true + volumes: + - ./application:/app + - ./scripts/setup_linux_a.sh:/setup.sh + entrypoint: sh /setup.sh + + linux_b: + image: alpine:3.19 + container_name: kulakov_gateway + hostname: kulakov_gateway + networks: + servernet: + ipv4_address: 192.168.13.1 + clientnet: + ipv4_address: 192.168.8.1 + privileged: true + tty: true + volumes: + - ./scripts/setup_linux_b.sh:/setup.sh + entrypoint: sh /setup.sh + + linux_c: + image: alpine:3.19 + container_name: kulakov_client + hostname: kulakov_client + networks: + clientnet: + ipv4_address: 192.168.8.10 + privileged: true + tty: true + volumes: + - ./scripts/setup_linux_c.sh:/setup.sh + entrypoint: sh /setup.sh + depends_on: + - linux_a + - linux_b + +networks: + servernet: + driver: bridge + ipam: + config: + - subnet: 192.168.13.0/24 + gateway: 192.168.13.254 + clientnet: + driver: bridge + ipam: + config: + - subnet: 192.168.8.0/24 + gateway: 192.168.8.254 diff --git a/linux1/imgs/screen1.png b/linux1/imgs/screen1.png new file mode 100644 index 0000000..86a2f40 Binary files /dev/null and b/linux1/imgs/screen1.png differ diff --git a/linux1/imgs/screen2.png b/linux1/imgs/screen2.png new file mode 100644 index 0000000..226ffff Binary files /dev/null and b/linux1/imgs/screen2.png differ diff --git a/linux1/imgs/screen3.png b/linux1/imgs/screen3.png new file mode 100644 index 0000000..391646f Binary files /dev/null and b/linux1/imgs/screen3.png differ diff --git a/linux1/report.md b/linux1/report.md new file mode 100644 index 0000000..d72e6c6 --- /dev/null +++ b/linux1/report.md @@ -0,0 +1,278 @@ +# Отчёт по практической работе «Администрирование Linux» + +**Студент:** Кулаков Родион Андреевич +**Дата выполнения:** 23.05.2026 +**Инструмент:** Docker Desktop (Alpine Linux 3.19) + +--- + +## 1. Задание + +Развернуть три Linux-машины по следующей схеме: + +- **Linux A (kulakov_server)** — HTTP-сервер на порту 5000 с тремя эндпоинтами: `/get`, `/post`, `/put` +- **Linux B (kulakov_gateway)** — шлюз между A и C, пропускает только TCP-трафик на порт 5000 +- **Linux C (kulakov_client)** — клиент, отправляет три HTTP-запроса на сервер через шлюз + +--- + +## 2. Топология сети + +``` +[kulakov_client] [kulakov_gateway] [kulakov_server] + 192.168.8.10 <─clientnet─> 192.168.8.1 + 192.168.13.1 <─servernet─> 192.168.13.10 +``` + +IP-адреса составлены на основе даты рождения **13.08.2003**: +- `13` (день) → последний октет подсети servernet: `192.168.13.x` +- `8` (месяц) → последний октет подсети clientnet: `192.168.8.x` + +--- + +## 3. Структура проекта + +``` +linuxPractice/ +├── application/ +│ └── app.py — Flask HTTP-сервер +├── configs/ +│ ├── linux_a/ +│ │ ├── netplan/00-installer-config.yaml +│ │ └── systemd/web-server.service +│ ├── linux_b/ +│ │ ├── netplan/00-installer-config.yaml +│ │ └── iptables/setup_iptables.sh +│ └── linux_c/ +│ └── netplan/00-installer-config.yaml +├── scripts/ +│ ├── setup_linux_a.sh +│ ├── setup_linux_b.sh +│ └── setup_linux_c.sh +├── imgs/ +│ ├── screen1.png +│ ├── screen2.png +│ └── screen3.png +├── docker-compose.yml +├── explanations.md +└── report.md +``` + +--- + +## 4. Конфигурационные файлы + +### 4.1 Веб-сервер (application/app.py) + +```python +from flask import Flask, request, jsonify + +app = Flask(__name__) + +@app.route("/get", methods=["GET"]) +def handle_get(): + return jsonify({"method": "GET", "message": "Hello from GET endpoint"}), 200 + +@app.route("/post", methods=["POST"]) +def handle_post(): + data = request.get_json(silent=True) or {} + return jsonify({"method": "POST", "message": "Hello from POST endpoint", "received": data}), 200 + +@app.route("/put", methods=["PUT"]) +def handle_put(): + data = request.get_json(silent=True) or {} + return jsonify({"method": "PUT", "message": "Hello from PUT endpoint", "received": data}), 200 + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) +``` + +### 4.2 Сетевая конфигурация — Linux A (configs/linux_a/netplan/00-installer-config.yaml) + +```yaml +network: + ethernets: + enp0s3: + dhcp4: true + enp0s8: + dhcp4: no + addresses: [192.168.13.10/24] + gateway4: 192.168.13.1 + version: 2 +``` + +### 4.3 Сетевая конфигурация — Linux B (configs/linux_b/netplan/00-installer-config.yaml) + +```yaml +network: + ethernets: + enp0s3: + dhcp4: true + enp0s8: + dhcp4: no + addresses: [192.168.13.1/24] + enp0s9: + dhcp4: no + addresses: [192.168.8.1/24] + version: 2 +``` + +### 4.4 Сетевая конфигурация — Linux C (configs/linux_c/netplan/00-installer-config.yaml) + +```yaml +network: + ethernets: + enp0s3: + dhcp4: true + enp0s8: + dhcp4: no + addresses: [192.168.8.10/24] + gateway4: 192.168.8.1 + version: 2 +``` + +### 4.5 Правила файрвола — Linux B (configs/linux_b/iptables/setup_iptables.sh) + +```bash +# Включить пересылку пакетов между интерфейсами +echo 1 > /proc/sys/net/ipv4/ip_forward + +# Разрешить новые соединения только на порт 5000 +iptables -A FORWARD -i enp0s9 -o enp0s8 -p tcp --syn --dport 5000 \ + -m conntrack --ctstate NEW -j ACCEPT + +# Разрешить уже установленные соединения в обе стороны +iptables -A FORWARD -i enp0s9 -o enp0s8 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -A FORWARD -i enp0s8 -o enp0s9 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Блокировать всё остальное +iptables -P FORWARD DROP + +# Сохранить правила +iptables-save > /etc/iptables/rules.v4 +``` + +### 4.6 Автозапуск сервера — systemd (configs/linux_a/systemd/web-server.service) + +```ini +[Unit] +Description=Flask Web Server +After=network.target + +[Service] +Type=simple +User=kulakov_1 +WorkingDirectory=/home/kulakov_1/server/ +ExecStart=/usr/bin/python3 /home/kulakov_1/server/app.py +Restart=on-failure +RestartSec=3 + +[Install] +WantedBy=multi-user.target +``` + +### 4.7 Docker Compose (docker-compose.yml) + +```yaml +services: + linux_a: + image: alpine:3.19 + container_name: kulakov_server + hostname: kulakov_server + networks: + servernet: + ipv4_address: 192.168.13.10 + privileged: true + tty: true + volumes: + - ./application:/app + - ./scripts/setup_linux_a.sh:/setup.sh + entrypoint: sh /setup.sh + + linux_b: + image: alpine:3.19 + container_name: kulakov_gateway + hostname: kulakov_gateway + networks: + servernet: + ipv4_address: 192.168.13.1 + clientnet: + ipv4_address: 192.168.8.1 + privileged: true + tty: true + volumes: + - ./scripts/setup_linux_b.sh:/setup.sh + entrypoint: sh /setup.sh + + linux_c: + image: alpine:3.19 + container_name: kulakov_client + hostname: kulakov_client + networks: + clientnet: + ipv4_address: 192.168.8.10 + privileged: true + tty: true + volumes: + - ./scripts/setup_linux_c.sh:/setup.sh + entrypoint: sh /setup.sh + depends_on: + - linux_a + - linux_b + +networks: + servernet: + driver: bridge + ipam: + config: + - subnet: 192.168.13.0/24 + gateway: 192.168.13.254 + clientnet: + driver: bridge + ipam: + config: + - subnet: 192.168.8.0/24 + gateway: 192.168.8.254 +``` + +--- + +## 5. Результаты выполнения + +### 5.1 Запуск контейнеров (`docker compose up`) + +На скриншоте видно успешное создание сетей и контейнеров. Шлюз `kulakov_gateway` вывел применённые правила iptables: политика FORWARD установлена в DROP, разрешён только порт 5000. Запущен tcpdump на интерфейсе eth0. + +![Запуск docker compose up](imgs/screen1.png) + +### 5.2 Работа сервера и клиента + +Клиент `kulakov_client` успешно отправил три запроса на сервер `kulakov_server` через шлюз `kulakov_gateway`. Сервер принял запросы с адреса `192.168.8.10` (клиент) и вернул корректные JSON-ответы. Все три запроса прошли через шлюз B по порту 5000. + +![Ответы сервера и запросы клиента](imgs/screen2.png) + +**Полученные ответы:** + +| Запрос | Ответ | +|--------|-------| +| GET `/get` | `{"message": "Hello from GET endpoint", "method": "GET"}` | +| POST `/post` | `{"message": "Hello from POST endpoint", "method": "POST", "received": {"student": "kulakov"}}` | +| PUT `/put` | `{"message": "Hello from PUT endpoint", "method": "PUT", "received": {"update": "kulakov_data"}}` | + +### 5.3 Статус контейнеров (`docker ps`) + +Все три контейнера находятся в статусе **Up** — система работает штатно. + +![docker ps — список контейнеров](imgs/screen3.png) + +--- + +## 6. Выводы + +В ходе практической работы была развёрнута сеть из трёх Linux-машин: + +- На машине **A** настроен HTTP-сервер Flask с тремя эндпоинтами (`/get`, `/post`, `/put`) на порту 5000 +- На машине **B** включена маршрутизация IP-пакетов между двумя подсетями, настроены правила iptables, разрешающие транзитный трафик **только** на порт 5000; запущен tcpdump для мониторинга +- На машине **C** настроен маршрут к подсети сервера через шлюз B; успешно выполнены три HTTP-запроса разными методами + +Клиент получил корректные ответы от сервера, трафик прошёл через шлюз по указанному порту. Запросы на другие порты были бы заблокированы правилом `iptables -P FORWARD DROP`. diff --git a/linux1/scripts/setup_linux_a.sh b/linux1/scripts/setup_linux_a.sh new file mode 100644 index 0000000..c2bbf04 --- /dev/null +++ b/linux1/scripts/setup_linux_a.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Linux A (Server) — kulakov_server +# Docker version: сеть уже настроена compose, только маршрут + Flask + +# Маршрут для ответных пакетов к клиенту (через шлюз linux_b) +ip route add 192.168.8.0/24 via 192.168.13.1 2>/dev/null || true + +# Установка Python и Flask из пакетов Alpine (без pip, надёжнее) +apk add --no-cache python3 py3-flask > /dev/null 2>&1 + +# Копируем приложение +mkdir -p /home/kulakov_1/server +cp /app/app.py /home/kulakov_1/server/ + +echo "================================================" +echo " kulakov_server готов. Flask стартует на :5000" +echo "================================================" +python3 /home/kulakov_1/server/app.py diff --git a/linux1/scripts/setup_linux_b.sh b/linux1/scripts/setup_linux_b.sh new file mode 100644 index 0000000..082c971 --- /dev/null +++ b/linux1/scripts/setup_linux_b.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# Linux B (Gateway) — kulakov_gateway +# Docker version: включаем форвардинг + iptables только на порт 5000 + +# Включить IP forwarding +echo 1 > /proc/sys/net/ipv4/ip_forward + +# Установка инструментов +apk add --no-cache iptables tcpdump > /dev/null 2>&1 + +# Определяем интерфейсы по IP автоматически +ETH_SERVER=$(ip -4 addr | awk '/192\.168\.13\./{print $NF}') +ETH_CLIENT=$(ip -4 addr | awk '/192\.168\.8\./{print $NF}') + +echo "================================================" +echo " kulakov_gateway" +echo " servernet: $ETH_SERVER — 192.168.13.1" +echo " clientnet: $ETH_CLIENT — 192.168.8.1" +echo "================================================" + +# Сбросить существующие правила FORWARD +iptables -F FORWARD + +# Разрешить новые TCP-соединения только на порт 5000 (клиент -> сервер) +iptables -A FORWARD -i $ETH_CLIENT -o $ETH_SERVER \ + -p tcp --syn --dport 5000 -m conntrack --ctstate NEW -j ACCEPT + +# Разрешить уже установленные соединения в обе стороны +iptables -A FORWARD -i $ETH_CLIENT -o $ETH_SERVER \ + -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT +iptables -A FORWARD -i $ETH_SERVER -o $ETH_CLIENT \ + -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Всё остальное — заблокировать +iptables -P FORWARD DROP + +echo "Правила iptables применены (разрешён только порт 5000):" +iptables -L FORWARD -v --line-numbers + +# tcpdump в фоне — смотрим трафик на порту 5000 +tcpdump -i $ETH_SERVER port 5000 -l -n & + +echo "tcpdump запущен на $ETH_SERVER. Шлюз работает." +tail -f /dev/null diff --git a/linux1/scripts/setup_linux_c.sh b/linux1/scripts/setup_linux_c.sh new file mode 100644 index 0000000..c84df43 --- /dev/null +++ b/linux1/scripts/setup_linux_c.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# Linux C (Client) — kulakov_client +# Docker version: добавляем маршрут к серверу и шлём curl-запросы + +# Маршрут к подсети сервера через шлюз linux_b +ip route add 192.168.13.0/24 via 192.168.8.1 + +# Установка curl +apk add --no-cache curl > /dev/null 2>&1 + +SERVER="192.168.13.10:5000" + +# Ждём пока сервер поднимется (до 60 секунд) +echo "Ожидаем kulakov_server..." +for i in $(seq 1 30); do + if curl -sf --connect-timeout 2 "http://${SERVER}/get" > /dev/null 2>&1; then + echo "Сервер доступен!" + break + fi + printf "Попытка %d/30...\n" "$i" + sleep 2 +done + +echo "" +echo "================================================" +echo " kulakov_client — отправляем запросы" +echo "================================================" + +echo "" +echo "--- GET http://${SERVER}/get ---" +curl -s -X GET "http://${SERVER}/get" + +echo "" +echo "--- POST http://${SERVER}/post ---" +curl -s -X POST "http://${SERVER}/post" \ + -H "Content-Type: application/json" \ + -d '{"student": "kulakov"}' + +echo "" +echo "--- PUT http://${SERVER}/put ---" +curl -s -X PUT "http://${SERVER}/put" \ + -H "Content-Type: application/json" \ + -d '{"update": "kulakov_data"}' + +echo "" +echo "================================================" +echo " Все три запроса отправлены успешно." +echo "================================================" +tail -f /dev/null