174 lines
6.6 KiB
Markdown
174 lines
6.6 KiB
Markdown
# Traefik ForwardAuth: HTML-логин для внутренних сервисов
|
||
|
||
## 1. Контекст
|
||
|
||
Текущая схема использует BasicAuth — браузерный нативный диалог, не кастомизируемый.
|
||
ForwardAuth позволяет заменить его на HTML-страницу входа с сессиями.
|
||
|
||
**Что меняется:** вместо `Middleware basicAuth` → `Middleware forwardAuth` + отдельный auth-pod.
|
||
|
||
---
|
||
|
||
## 2. Как работает ForwardAuth
|
||
|
||
```
|
||
Клиент → Traefik :10002 → ForwardAuth Middleware
|
||
│
|
||
▼
|
||
auth-сервис /auth
|
||
│
|
||
┌───────────┴───────────┐
|
||
│ 200 OK │ 401 → redirect на /login
|
||
│ (сессия валидна) │ (HTML-страница логина)
|
||
▼ ▼
|
||
longhorn-frontend форма → POST /login
|
||
│
|
||
проверка пароля
|
||
│
|
||
Set-Cookie session
|
||
│
|
||
redirect обратно
|
||
```
|
||
|
||
Traefik делает subrequest на `authResponseHeaders` — если auth-сервис вернул 200, пропускает запрос дальше. Если 401/302 — возвращает клиенту ответ auth-сервиса (redirect на страницу логина).
|
||
|
||
---
|
||
|
||
## 3. Варианты реализации
|
||
|
||
### 3.1. oauth2-proxy (рекомендуется)
|
||
|
||
**Что это:** легковесный reverse-proxy с поддержкой htpasswd, GitHub, Google, OIDC.
|
||
Для внутреннего использования подходит режим `--htpasswd-file` без внешнего провайдера.
|
||
|
||
**Плюсы:**
|
||
- Один pod, ~50MB RAM
|
||
- Htpasswd-файл через Kubernetes Secret — никаких внешних зависимостей
|
||
- HTML-форма из коробки, можно переопределить шаблоны
|
||
- Cookie-сессии, configurable TTL
|
||
|
||
**Минусы:**
|
||
- Один экземпляр oauth2-proxy на весь Traefik (или по одному на сервис)
|
||
- Нет 2FA
|
||
|
||
**Схема деплоя:**
|
||
```
|
||
roles/oauth2-proxy/
|
||
tasks/main.yml — Kubernetes Deployment + Service
|
||
tasks/secret.yml — инструкция по созданию htpasswd Secret вручную
|
||
tasks/middleware.yml — ForwardAuth Middleware CRD
|
||
|
||
inventory/prod/group_vars/oauth2proxy.yml — cookie_secret, upstream, htpasswd ref
|
||
```
|
||
|
||
**Ключевые параметры:**
|
||
```yaml
|
||
# Helm values / env vars
|
||
--provider=htpasswd
|
||
--htpasswd-file=/etc/oauth2-proxy/htpasswd
|
||
--cookie-secret=<32-byte-random> # генерируется вручную
|
||
--cookie-secure=false # HTTP, без TLS
|
||
--email-domain=*
|
||
--upstream=static://200 # ForwardAuth: upstream не используется
|
||
```
|
||
|
||
**Middleware CRD:**
|
||
```yaml
|
||
apiVersion: traefik.io/v1alpha1
|
||
kind: Middleware
|
||
metadata:
|
||
name: forwardauth-oauth2proxy
|
||
namespace: traefik
|
||
spec:
|
||
forwardAuth:
|
||
address: http://oauth2-proxy.traefik.svc:4180/oauth2/auth
|
||
trustForwardHeader: true
|
||
authResponseHeaders:
|
||
- X-Auth-Request-User
|
||
- X-Auth-Request-Email
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2. Authelia
|
||
|
||
**Что это:** полноценный self-hosted identity provider. HTML-логин, 2FA (TOTP, WebAuthn), LDAP, правила доступа по пользователям/группам.
|
||
|
||
**Плюсы:**
|
||
- Красивая HTML-форма с брендингом
|
||
- 2FA из коробки
|
||
- Гранулярный контроль: разные пользователи для разных сервисов
|
||
|
||
**Минусы:**
|
||
- Требует Redis (сессии) + хранилище пользователей (файл или LDAP)
|
||
- ~150MB RAM минимум
|
||
- Сложнее в настройке (YAML-конфиг, несколько секретов)
|
||
|
||
**Оправдано если:** нужен 2FA или несколько пользователей с разными правами.
|
||
|
||
---
|
||
|
||
### 3.3. thomseddon/traefik-forward-auth
|
||
|
||
**Что это:** минималистичный ForwardAuth-сервис только для Google/OIDC OAuth.
|
||
Для htpasswd **не подходит** — требует внешний провайдер.
|
||
|
||
---
|
||
|
||
## 4. Рекомендация
|
||
|
||
Для текущего стека (внутренняя сеть, один оператор, нет SSO) — **oauth2-proxy с htpasswd**.
|
||
|
||
| Критерий | oauth2-proxy | Authelia |
|
||
|---|---|---|
|
||
| RAM | ~50MB | ~150MB |
|
||
| Внешние зависимости | нет | Redis |
|
||
| 2FA | нет | да |
|
||
| Сложность настройки | низкая | средняя |
|
||
| HTML-логин | да (кастомизируемый) | да (красивый) |
|
||
|
||
---
|
||
|
||
## 5. Интеграция с текущим port_map
|
||
|
||
Схема остаётся прежней — меняется только тип Middleware:
|
||
|
||
```yaml
|
||
# inventory/prod/group_vars/traefik.yml
|
||
traefik_port_map:
|
||
- name: longhorn-ui
|
||
port: 10002
|
||
backend:
|
||
namespace: longhorn-system
|
||
service: longhorn-frontend
|
||
port: 80
|
||
scheme: http
|
||
auth:
|
||
type: forwardauth # вместо basicauth
|
||
middleware: forwardauth-oauth2proxy # имя Middleware
|
||
```
|
||
|
||
При `type: forwardauth` шаблон `ingressroute.yml.j2` подставляет ForwardAuth Middleware вместо BasicAuth.
|
||
При `type: basicauth` — как сейчас.
|
||
|
||
---
|
||
|
||
## 6. Порядок развёртывания (если решим внедрить)
|
||
|
||
1. Добавить роль `oauth2-proxy` в `roles/`
|
||
2. Добавить `playbooks/setup_oauth2proxy.yml`
|
||
3. Создать Secret с htpasswd вручную:
|
||
```bash
|
||
kubectl create secret generic oauth2proxy-htpasswd \
|
||
--from-literal=htpasswd="$(htpasswd -nb admin 'pass')" \
|
||
-n traefik
|
||
```
|
||
4. Создать Secret с cookie_secret:
|
||
```bash
|
||
kubectl create secret generic oauth2proxy-cookie \
|
||
--from-literal=cookie-secret="$(openssl rand -base64 32)" \
|
||
-n traefik
|
||
```
|
||
5. Заменить `basicAuth` Middleware на `forwardAuth` в IngressRoute для нужных сервисов
|
||
6. Удалить старые BasicAuth Middleware и Secret `traefik-auth-longhorn`
|