SPA аутентифицируется сессионной кукой и не прикладывает X-CSRFToken, а
SessionAuthentication из DRF требует его на любом небезопасном методе:
DELETE /api/core/videos/<id>/ -> 403
{"detail": "CSRF Failed: CSRF token missing."}
Проверено на контуре, тремя запросами по несуществующему id (403 = отказ
авторизации, 404 = авторизация прошла):
Bearer-токен -> 404 CSRF не при чём
сессия + X-CSRFToken -> 404 проходит
сессия без X-CSRFToken -> 403 ровно наша ошибка
без авторизации -> 401
То есть бэкенд исправен, ломается ровно сочетание "кука без заголовка".
С Bearer до SessionAuthentication дело не доходит: simple_jwt стоит в
DEFAULT_AUTHENTICATION_CLASSES раньше.
Ставим подкласс с пустым enforce_csrf на то же пятое место. Цена — с
cookie-запросов снимается защита от CSRF. Основной вектор закрыт самими
куками (sessionid и csrftoken выставляются с SameSite=Lax, браузер не
пошлёт их при кросс-сайтовом DELETE); остаётся щель в соседях по домену,
поскольку SameSite смотрит на site, а не на origin.
Импорт rest_framework в модуле настроек безопасен не всегда — обычно так
ловят AppRegistryNotReady. Здесь проверено запуском django.setup() внутри
работающего пода backend: setup проходит, строка пути к классу резолвится.
Браузер получал 404 на
https://sarex.contour.infra.sarex.tech/media/state/previews/....png
то есть backend отдавал АБСОЛЮТНЫЕ ссылки на чужой хост. Файлы при этом
лежали у нас — уходил не тот домен.
Источников оказалось три, и все в base:
* django-configmap, HOST = "https://sarex.contour.infra.sarex.tech" —
именно по нему строятся абсолютные ссылки на медиа;
* там же CSRF_TRUSTED_ORIGINS с тем же доменом: без нашего домена django
отклонял бы POST-формы админки по проверке Referer;
* envs backend SERVER_API_HOST и SERVER_HOST. У celery те же две
переменные я поправил раньше, а у backend пропустил.
Конфигмап скопирован в оверлей целиком: все настройки лежат одним значением
data.production.py на 331 строку, kustomize заменяет его только целиком —
та же причина, что у nginx-configmap рядом. Изменены ровно две строки,
остальное побайтно совпадает с base, так что diff остаётся читаемым.
После правки домена sarex.contour.infra.sarex.tech в рендере
clusters/aero/apps не остаётся ни одного вхождения.