docs: API token saga — DDoS-Guard User-Agent fix, new tokens, endpoint matrix

This commit is contained in:
“Naeel”
2026-06-30 17:25:17 +04:00
parent 8ce7a7aa93
commit 6c442623be
2 changed files with 199 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
# 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.
**Фикс:**
```bash
# НЕ работает:
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"`.
**Декодирование старого токена:**
```json
{
"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` была комбинация двух проблем:
1. Старый формат (без token_type) → `"invalid JWT token type"`
2. Плюс 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-запрос
```bash
# Рабочий запрос к 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):
```go
// Сейчас (БАГ):
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:
```go
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)