8.9 KiB
API Token Saga — 30.06.2026
Дата: 30 июня 2026 Контекст: попытка доступа к Nubes Cloud API для правки Terraform Provider
Кратко
6 часов debug'а. DDoS-Guard резал запросы, выдавая 403 Forbidden.
Причина: User-Agent фильтрация + протухшие токены + неправильный endpoint.
Хронология ошибок
Ошибка 1: 403 от DDoS-Guard (2 часа потеряно)
$ curl https://deck-api.ngcloud.ru/api/v1/index.cfm/services/90
→ 403 Forbidden
Что думали: DDoS-Guard блокирует наш IP, нужно добавлять в whitelist. Проверяли с ВМ, из подов кластера — везде 403.
Реальная причина: DDoS-Guard фильтрует по User-Agent. curl/8.x блокируется, браузерный Mozilla/5.0 ... пропускается.
Как нашли: HAR-файлы (HAR/OK.har) показали что успешные запросы из браузера идут с HTTP/2 и браузерным User-Agent. Провайдер форсит HTTP/1.1 с Go-шным UA.
Фикс:
# НЕ работает:
curl https://deck-api.ngcloud.ru/...
# РАБОТАЕТ:
curl -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
https://deck-api.ngcloud.ru/...
Ошибка 2: Старые токены без token_type (30 минут)
$ curl -H "Authorization: Bearer $OLD_TOKEN" ... (с правильным UA)
→ {"message":"invalid JWT token type"}
Что думали: Токены протухли. Проверили — живые (exp: август-сентябрь 2026). Потом думали что API изменился и требует новый формат.
Реальная причина: Старые токены из secrets/prod.token и secrets/dev.token были выданы БЕЗ поля token_type в JWT. API обновился и теперь требует token_type: "tech".
Декодирование старого токена:
{
"iss": "auth-api",
"sub": "0199e325-1cdf-7cda-9319-e5302a85e291",
"exp": 1786932260,
// token_type: ОТСУТСТВУЕТ ← причина ошибки
}
Ошибка 3: Токен не того стенда (30 минут)
$ curl -H "Authorization: Bearer $TEST_TOKEN" https://deck-api.ngcloud.ru/...
→ {"message":"IAM error"}
Что думали: Токен битый, неправильная подпись.
Реальная причина: Токены привязаны к конкретному API-endpoint. TEST-токен работает только на deck-api-test.ngcloud.ru, PROD — на deck-api.ngcloud.ru, DEV — на deck-api-dev.ngcloud.ru.
Ошибка 4: Двойной сбой (1 час)
На prod.token была комбинация двух проблем:
- Старый формат (без token_type) →
"invalid JWT token type" - Плюс DDoS-Guard скрывал реальный ответ API за
403 Forbidden
Пока не добавили User-Agent, мы даже не видели сообщение "invalid JWT token type" — видели только 403.
Как это работает (правильная схема)
1. API endpoints
| Стенд | Endpoint | Токен |
|---|---|---|
| PROD | https://deck-api.ngcloud.ru/api/v1/index.cfm |
secrets/prod.token |
| TEST | https://deck-api-test.ngcloud.ru/api/v1/index.cfm |
secrets/test.token |
| DEV | https://deck-api-dev.ngcloud.ru/api/v1/index.cfm |
secrets/dev.token |
Токены НЕ взаимозаменяемы между стендами.
2. Аутентификация
┌──────────┐ Bearer JWT ┌───────────┐ validate ┌──────────┐
│ Client │ ──────────────────→ │ deck-api │ ──────────────→ │ auth-api │
│ (curl/Go)│ ←── JSON response ─ │ (CFML) │ ←── OK/FAIL ── │ (IAM) │
└──────────┘ └───────────┘ └──────────┘
- Токен передаётся как
Authorization: Bearer <JWT> - deck-api проверяет токен через auth-api (внутренний вызов)
- JWT содержит:
iss: "auth-api",token_type: "tech",ClientID: "WZ03709" token_typeобязателен (новое требование API)
3. User-Agent фильтрация DDoS-Guard
┌──────────┐ ┌────────────┐ ┌──────────┐
│ Client │ ─── HTTP request → │ DDoS-Guard │ ─── if UA ok ───→ │ deck-api │
│ │ ←── 403 если UA ── │ 185.178... │ │ │
│ │ не браузерный └────────────┘ └──────────┘
DDoS-Guard проверяет заголовок User-Agent:
curl/x.y.z→ 403 Forbidden (блокировка)Go-http-client/x.y→ 403 Forbidden (провайдер блокируется!)Mozilla/5.0 ...→ пропускается
Это критический баг провайдера: Go HTTP-клиент по умолчанию отправляет Go-http-client/2.0, который DDoS-Guard режет.
4. Правильный curl-запрос
# Рабочий запрос к PROD API:
curl -sk --max-time 10 \
-H "Authorization: Bearer $(cat secrets/prod.token)" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
"https://deck-api.ngcloud.ru/api/v1/index.cfm/services/90"
# Аналогично для TEST:
curl -sk --max-time 10 \
-H "Authorization: Bearer $(cat secrets/test.token.new)" \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
"https://deck-api-test.ngcloud.ru/api/v1/index.cfm/services/90"
5. Живые токены (30.06.2026)
| Файл | Назначение | Выдан | Истекает | token_type | ClientID |
|---|---|---|---|---|---|
secrets/prod.token |
PROD | 18.02.2026 | 17.08.2026 | ❌ отсутствует | ❌ |
secrets/dev.token |
DEV | 26.03.2026 | 22.09.2026 | ❌ отсутствует | ❌ |
secrets/test.token |
TEST | 14.03.2026 | 10.09.2026 | ❌ отсутствует | ❌ |
secrets/test.token.new |
TEST | 30.06.2026 13:37 | ~дек.2026 | ✅ "tech" |
✅ WZ03709 |
secrets/dev.token.new (в памяти) |
DEV | 30.06.2026 13:42 | ~дек.2026 | ✅ "tech" |
✅ WZ03709 |
secrets/prod.token.new (в памяти) |
PROD | 30.06.2026 13:41 | ~дек.2026 | ✅ "tech" |
✅ WZ03709 |
⚠️ Новые токены ещё не сохранены в файлы secrets/ — только test сохранён.
Что надо исправить в провайдере
P0: User-Agent
В universal_rebuild/internal/core/client.go (и internal/core/client.go Legacy):
// Сейчас (БАГ):
req.Header.Set("User-Agent", "Go-http-client/2.0") // или default
// Надо:
req.Header.Set("User-Agent", "Terraform-Provider-Nubes/5.0") // пропускаемый UA
Или в http.Client.Transport, или в каждом doRequest.
Связанное: HTTP/2
Провайдер форсит HTTP/1.1:
NextProtos: []string{"http/1.1"},
ForceAttemptHTTP2: false,
HAR показывает что API работает через HTTP/2. Возможно стоит разрешить HTTP/2 (убрать ForceAttemptHTTP2: false) — это ускорит поллинг.
Ключевые файлы
/home/naeel/tf_provider/HAR/OK.har— эталонные запросы (HTTP/2 + браузерный UA)/home/naeel/tf_provider/secrets/prod.token— старый prod-токен (без token_type)/home/naeel/tf_provider/secrets/test.token.new— новый test-токен (рабочий)/home/naeel/tf_provider/devops/profiles/*/profile.env— endpoint'ы стендов/home/naeel/tf_provider/universal_rebuild/internal/core/client.go—doRequest()(надо править UA)/home/naeel/tf_provider/universal_rebuild/internal/provider/provider.go— HTTP-транспорт (HTTP/1.1 force)