Files
Test1/README.md
T

16 KiB

Портал администрирования: HAProxy + Django + AD → Backend admin panels

Установка на виртуальную машину (без Docker)

Единая точка входа для администраторов: логин через Active Directory, персональный список доступных ресурсов по AD-группам, переход в нужную админку по адресу https://<FQDN>/<adminusergroup>/<resource>/....

Все компоненты устанавливаются как обычные пакеты/systemd-сервисы непосредственно на одну ВМ (Ubuntu 22.04/24.04 или Debian 12).

1. Состав решения

admin-portal-vm/
├── README.md                    — этот файл
├── .env.example                  — шаблон переменных окружения
├── haproxy/
│   ├── haproxy.cfg                — полный конфиг HAProxy (-> /etc/haproxy/haproxy.cfg)
│   └── group_map.cfg              — карта "путь -> backend" (-> /etc/haproxy/group_map.cfg)
├── systemd/
│   └── admin-portal.service       — юнит Gunicorn (Django-приложение)
├── django_app/                    — код портала (Django)
│   ├── manage.py
│   ├── requirements.txt
│   ├── config/                     — settings.py, urls.py, wsgi.py
│   ├── portal/                     — модели, вью, шаблоны, LDAP-логика
│   └── resources.example.yaml      — пример декларативного каталога ресурсов
├── backend_demo/                  — 2 демо-админки (Nginx) для проверки маршрутизации
│   ├── resource1/{index.html,nginx.conf}
│   └── resource2/{index.html,nginx.conf}
├── scripts/
│   ├── install.sh                  — автоматизация шагов 3–9 (см. ниже)
│   └── generate_secrets.sh         — генерация DJANGO_SECRET_KEY / RESOURCE_TOKEN_SECRET
└── docs/
    └── architecture.md             — полное описание архитектуры и решений

2. Архитектура (кратко)

Браузер админа
     │  HTTPS (443)
     ▼
 HAProxy (systemd-сервис haproxy) ── TLS termination, ACL-роутинг по пути
     │
     ├── путь портала / нет валидного resource_token ──► Gunicorn (127.0.0.1:8000)
     │                                                     └─ Django frontend
     │                                                          ├─ django-auth-ldap -> AD
     │                                                          ├─ PostgreSQL (localhost)
     │                                                          └─ Redis (localhost, сессии)
     │
     └── путь /{adminusergroup}/{resource}/... + resource_token
                    │
                    ▼
        backend_<группа> — Nginx на 127.0.0.1:808x (демо) или
                            реальная админка на другом хосте сети

Полное описание потоков, модели данных и вопросов безопасности — в docs/architecture.md.

3. Требования к ВМ

  • Ubuntu 22.04/24.04 LTS или Debian 12, root/sudo-доступ
  • 2 vCPU / 2 GB RAM достаточно для старта (PostgreSQL, Redis, Gunicorn, HAProxy, Nginx — все на одной машине)
  • Сетевой доступ до контроллера домена AD (LDAP/LDAPS, порт 389/636)
  • Технический пользователь AD с правом bind + поиска (service account), без прав записи
  • Валидный TLS-сертификат на FQDN портала (или self-signed для теста)
  • DNS-запись FQDN, указывающая на эту ВМ
  • Порты 80/443 открыты снаружи; всё остальное (5432, 6379, 8000, 808x) — только на loopback, наружу не публикуется

4. Установка — автоматически (рекомендуемый способ)

# 1. Скопировать архив решения на ВМ и распаковать
unzip admin-portal-vm.zip
cd admin-portal-vm

# 2. Подготовить .env
cp .env.example .env
bash scripts/generate_secrets.sh      # подставить значения ключей в .env вручную
nano .env                             # заполнить AD_*, POSTGRES_PASSWORD и т.д.

# 3. Запустить установку (пакеты, БД, Redis, venv, миграции, systemd, HAProxy, Nginx)
sudo bash scripts/install.sh ./.env

Скрипт последовательно:

  1. ставит haproxy, nginx, postgresql, redis-server, Python и dev-библиотеки для сборки python-ldap;
  2. создаёт системного пользователя adminportal без права логина;
  3. копирует django_app/ в /opt/admin-portal/django_app;
  4. создаёт venv и ставит зависимости из requirements.txt;
  5. кладёт .env в /etc/admin-portal/admin-portal.env (права 640, владелец root:adminportal);
  6. создаёт роль и базу PostgreSQL по значениям из .env, включает PostgreSQL и Redis;
  7. прогоняет migrate и collectstatic от имени adminportal;
  8. устанавливает и включает systemd-юнит admin-portal.service (Gunicorn на 127.0.0.1:8000);
  9. раскладывает haproxy.cfg/group_map.cfg, поднимает 2 демо-бэкенда через Nginx на 127.0.0.1:8081/8082, открывает 80/443 в ufw.

После скрипта останутся 3 ручных шага (секреты и сертификат сознательно не автоматизированы):

# TLS-сертификат
cat fullchain.pem privkey.pem > /etc/haproxy/certs/fqdn.pem
haproxy -c -f /etc/haproxy/haproxy.cfg && sudo systemctl reload haproxy

# Суперпользователь Django
sudo -u adminportal bash -c \
  'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py createsuperuser'

# Наполнение каталога ресурсов
sudo -u adminportal bash -c \
  'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py \
   sync_resources /opt/admin-portal/django_app/resources.example.yaml'

Дальше — к разделу 6 (проверка).

5. Установка — вручную, шаг за шагом

Если нужно понимать/контролировать каждое действие (или адаптировать под другой дистрибутив), либо не доверяете единому скрипту — то же самое руками.

Шаг 1. Системные пакеты

sudo apt-get update
sudo apt-get install -y haproxy nginx postgresql redis-server \
    python3 python3-venv python3-dev \
    libldap2-dev libsasl2-dev libssl-dev build-essential ufw

Шаг 2. Системный пользователь приложения

sudo useradd --system --home /opt/admin-portal --shell /usr/sbin/nologin adminportal

Шаг 3. Код приложения и виртуальное окружение

sudo mkdir -p /opt/admin-portal
sudo cp -r django_app /opt/admin-portal/django_app
sudo chown -R adminportal:adminportal /opt/admin-portal

sudo python3 -m venv /opt/admin-portal/venv
sudo /opt/admin-portal/venv/bin/pip install --upgrade pip
sudo /opt/admin-portal/venv/bin/pip install -r /opt/admin-portal/django_app/requirements.txt
sudo chown -R adminportal:adminportal /opt/admin-portal/venv

Шаг 4. Переменные окружения

cp .env.example .env
bash scripts/generate_secrets.sh   # вставить значения в .env
nano .env

Заполнить как минимум: DJANGO_SECRET_KEY, DJANGO_ALLOWED_HOSTS, POSTGRES_PASSWORD, AD_SERVER_URI, AD_BIND_DN, AD_BIND_PASSWORD, AD_USER_SEARCH_BASE, AD_GROUP_SEARCH_BASE, RESOURCE_TOKEN_SECRET.

sudo mkdir -p /etc/admin-portal
sudo install -o root -g adminportal -m 640 .env /etc/admin-portal/admin-portal.env

Шаг 5. PostgreSQL

source .env   # только для этой команды, читаем значения POSTGRES_*
sudo -u postgres psql -c "CREATE ROLE ${POSTGRES_USER} LOGIN PASSWORD '${POSTGRES_PASSWORD}';"
sudo -u postgres psql -c "CREATE DATABASE ${POSTGRES_DB} OWNER ${POSTGRES_USER};"
sudo systemctl enable --now postgresql

Шаг 6. Redis

sudo systemctl enable --now redis-server

По умолчанию Redis слушает только 127.0.0.1 — это то, что нужно, менять bind в /etc/redis/redis.conf не требуется.

Шаг 7. Миграции и статика

sudo -u adminportal bash -c \
  'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py migrate --noinput && \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py collectstatic --noinput'

Шаг 8. Gunicorn как systemd-сервис

sudo install -m 644 systemd/admin-portal.service /etc/systemd/system/admin-portal.service
sudo systemctl daemon-reload
sudo systemctl enable --now admin-portal
sudo systemctl status admin-portal   # должен быть active (running)

Шаг 9. HAProxy

sudo install -m 644 haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg
sudo install -m 644 haproxy/group_map.cfg /etc/haproxy/group_map.cfg
sudo mkdir -p /etc/haproxy/certs && sudo chmod 700 /etc/haproxy/certs

Положить сертификат:

cat fullchain.pem privkey.pem | sudo tee /etc/haproxy/certs/fqdn.pem >/dev/null
sudo chmod 600 /etc/haproxy/certs/fqdn.pem

Для теста — self-signed:

openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
  -keyout /tmp/key.pem -out /tmp/cert.pem -subj "/CN=portal.example.com"
cat /tmp/cert.pem /tmp/key.pem | sudo tee /etc/haproxy/certs/fqdn.pem >/dev/null

Проверить и включить:

sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl enable --now haproxy

Шаг 10. Демо-бэкенды (Nginx) — опционально, для сквозной проверки

for res in resource1 resource2; do
  sudo mkdir -p /var/www/admin-demo-${res}
  sudo cp backend_demo/${res}/index.html /var/www/admin-demo-${res}/index.html
  sudo install -m 644 backend_demo/${res}/nginx.conf /etc/nginx/sites-available/admin-demo-${res}
  sudo ln -sf /etc/nginx/sites-available/admin-demo-${res} /etc/nginx/sites-enabled/admin-demo-${res}
done
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl enable --now nginx && sudo systemctl reload nginx

Шаг 11. Фаервол

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable   # если ещё не включён — проверить, что не потеряете SSH (22/tcp)

Шаг 12. Суперпользователь и каталог ресурсов

sudo -u adminportal bash -c \
  'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py createsuperuser'

Дальше зайти на https://<FQDN>/django-admin/ и создать ResourceGroup (привязка к реальной AD-группе) и Resource (конкретный ресурс), либо воспользоваться декларативным файлом:

sudo -u adminportal bash -c \
  'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
   /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py \
   sync_resources /opt/admin-portal/django_app/resources.example.yaml'

6. Проверка

systemctl status admin-portal haproxy nginx postgresql redis-server
curl -kI https://portal.example.com/          # ожидаем редирект на /login/

Залогиниться доменной учёткой, убедиться, что на портале появились ресурсы, доступные группам этого пользователя, и что клик по ресурсу открывает демо-страницу (Demo Resource 1/2) — это подтверждает, что вся цепочка HAProxy → Django → AD → выдача токена → маршрутизация на backend работает.

7. Добавление нового ресурса/backend'а в дальнейшем

  1. Поднять реальную админку ресурса — на этой же ВМ (новый порт на 127.0.0.1) либо на отдельном хосте сети, доступном от HAProxy, но не доступном напрямую из интернета.
  2. Добавить в /etc/haproxy/haproxy.cfg новую backend be_<name> секцию со server этой админки (по образцу be_admin_resource1).
  3. Добавить строку в /etc/haproxy/group_map.cfg: /adgroup/resource-slug/ be_<name>.
  4. Проверить и перечитать конфиг без разрыва соединений: sudo haproxy -c -f /etc/haproxy/haproxy.cfg && sudo systemctl reload haproxy.
  5. Создать запись Resource в Django admin или через sync_resources.

8. Эксплуатация

  • Логи: journalctl -u admin-portal -f (Django/Gunicorn), journalctl -u haproxy -f, /var/log/nginx/*.log (демо-бэкенды).
  • Обновление кода портала:
    sudo -u adminportal rsync -a --delete django_app/ /opt/admin-portal/django_app/
    sudo -u adminportal bash -c \
      'set -a; source /etc/admin-portal/admin-portal.env; set +a; \
       /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py migrate --noinput && \
       /opt/admin-portal/venv/bin/python /opt/admin-portal/django_app/manage.py collectstatic --noinput'
    sudo systemctl restart admin-portal
    
  • Резервное копирование: штатный pg_dump ${POSTGRES_DB} по расписанию (cron/systemd timer). Redis бэкапить не нужно — там только сессии/кэш.
  • Обновление TLS-сертификата: заменить /etc/haproxy/certs/fqdn.pem и выполнить systemctl reload haproxy (без разрыва активных соединений).
  • Масштабирование: вынести PostgreSQL/Redis на отдельные ВМ (поменять POSTGRES_HOST/REDIS_URL в .env), поднять второй Django+Gunicorn на другой ВМ и добавить вторую строку server в backend be_django; HAProxy балансирует между ними без изменения остальной конфигурации.

Полное описание архитектуры, потоков данных, вариантов передачи identity в backend и вопросов безопасности — см. docs/architecture.md.