Knowledge Base
Cloudflare Access — Zero Trust защита для админ-панели
Cloudflare Access — Zero Trust для /nr-control/
Категория: Server Hardening · Риск: info
Cloudflare Access — Zero Trust для /nr-control/
Что такое Cloudflare Access
Cloudflare Access — бесплатный (до 50 пользователей) Zero Trust шлюз. Он **перехватывает запросы до nginx** и требует аутентификации через email OTP, GitHub, Google, Azure AD или любой OIDC-провайдер.
Для пользователя это выглядит как дополнительная страница входа перед тем, как попасть на `/nr-control/`. Для сервера — Cloudflare добавляет подписанный JWT в заголовок `Cf-Access-Jwt-Assertion`, который nginx/backend могут проверить.
Почему это лучше просто IP allowlist
| Метод | Смена IP | Мобильный | Команда | MFA | |-------|----------|-----------|---------|-----| | IP allowlist | ломается | сложно | нужно добавлять каждого | нет | | Cloudflare Access | не зависит | работает | email-приглашения | да | | Tailscale | не зависит | работает | удобно | да |
Настройка Cloudflare Access (15 минут)
Шаг 1 — Zero Trust Dashboard
cloudflare.com → Zero Trust → Access → Applications
→ Add an Application → Self-hosted
Шаг 2 — Параметры приложения
Application name: NodeRoute Admin
Session Duration: 24 hours
Application domain: noderoute.ru
Path: nr-control/
(также добавьте: api/nr-admin/)
Шаг 3 — Policy (политика доступа)
Policy name: Admins
Action: Allow
Include:
→ Emails ending in: @yourcompany.com
или
→ Emails: admin@gmail.com, teammate@gmail.com
Require (для MFA):
→ Authentication method: mTLS / One-time PIN
Шаг 4 — Login method
Zero Trust → Settings → Authentication
→ Add: One-time PIN (бесплатно, нет нужды в провайдере)
→ Или: GitHub / Google OAuth
Проверка JWT на стороне nginx (опционально, рекомендуется)
После включения Access Cloudflare добавляет заголовок. Nginx может его проверить:
# Проверка наличия CF Access JWT
location /nr-control/ {
# Cloudflare Access автоматически блокирует доступ без JWT
# Дополнительно можно проверить заголовок на backend-уровне:
# Разрешить только Cloudflare IP (они добавляют JWT)
include /etc/nginx/cloudflare-ips.conf;
deny all;
alias /usr/share/nginx/html/admin/;
try_files $uri $uri/ /admin/index.html;
...
}
# Скачать актуальный список IP Cloudflare
curl -s https://www.cloudflare.com/ips-v4 | \
awk '{print "allow "$1";"}' > /etc/nginx/cloudflare-ips.conf
curl -s https://www.cloudflare.com/ips-v6 | \
awk '{print "allow "$1";"}' >> /etc/nginx/cloudflare-ips.conf
Проверка JWT в FastAPI (максимальная защита)
# app/core/admin_auth.py — дополнительная проверка CF Access JWT
import jwt # pip install PyJWT
import httpx
_CF_CERTS_URL = "https://<your-team>.cloudflareaccess.com/cdn-cgi/access/certs"
_CF_AUD = "<application-audience-tag>" # из настроек Access
async def verify_cf_access_jwt(request: Request) -> None:
"""Verify Cloudflare Access JWT. Call from require_admin if CF Access is enabled."""
token = request.headers.get("Cf-Access-Jwt-Assertion")
if not token:
raise HTTPException(status_code=401, detail="CF Access token missing")
async with httpx.AsyncClient() as client:
certs = (await client.get(_CF_CERTS_URL)).json()
public_keys = [jwt.algorithms.RSAAlgorithm.from_jwk(k) for k in certs["keys"]]
for key in public_keys:
try:
payload = jwt.decode(token, key, algorithms=["RS256"], audience=_CF_AUD)
return # valid
except jwt.InvalidTokenError:
continue
raise HTTPException(status_code=401, detail="Invalid CF Access token")
Мониторинг попыток доступа
В Cloudflare Zero Trust → Logs → Access вы видите:
- Кто и когда заходил в `/nr-control/`
- Отклонённые попытки с IP и email
- Геолокацию входов
Когда использовать что
| Ситуация | Рекомендация | |----------|-------------| | Один администратор, фиксированный IP | `ADMIN_ALLOWED_IPS` в .env | | Команда или меняющийся IP | Cloudflare Access | | Максимальная безопасность | Tailscale + отдельный порт | | Уже есть WireGuard/Tailscale | Туннель через VPN |
Связанные проверки
- [Tailscale VPN](/kb/vpn/tailscale-admin)
- [WireGuard](/kb/vpn/wireguard-private-network)
- [Nginx hardening](/kb/http/nginx-basic-hardening)