diff --git a/FIX_401_INVOKE.md b/FIX_401_INVOKE.md new file mode 100644 index 0000000..c3f94af --- /dev/null +++ b/FIX_401_INVOKE.md @@ -0,0 +1,117 @@ +# Fix: 401 "key is of invalid type" при invoke функций + +## Статус: ГОТОВО К ПРАВКЕ (не исправлено) + +## Root Cause (установлен 2026-05-18) + +Secret `router` в k8s namespace `fission` был ротирован. +Router pod перезапустился — подхватил новый пароль. +Console pod НЕ перезапускался (5d8h) — имеет старый пароль в env var. + +| | | +|---|---| +| `FISSION_AUTH_PASSWORD` в console pod (env) | `ToAjBTs0Sb8mLC1J9NN3` (СТАРЫЙ) | +| `password` в k8s secret `router` (текущий) | `slxGj3G3FAD7l5ms2tJ9` | + +### Цепочка отказа + +1. `getRouterToken()` → `POST /auth/login` со старым паролем → **401 Unauthorized** +2. Fallback: `return s.readSAToken()` → Kubernetes SA token, `alg: RS256` +3. Console отправляет `Authorization: Bearer ` в router +4. Router keyfunc: `return []byte(JWT_SIGNING_KEY), nil` — возвращает `[]byte` для **любого** алгоритма +5. `jwt.Parse` получает RS256 JWT но ключ `[]byte` (ожидается `*rsa.PublicKey`) → **"key is of invalid type"** + +### Подтверждено + +```bash +# Старый пароль → 401: +kubectl exec -n fission fission-console-874c786c6-j6fvd -- wget -qO- \ + --post-data='{"username":"admin","password":"ToAjBTs0Sb8mLC1J9NN3"}' \ + --header='Content-Type: application/json' \ + http://router.fission.svc.cluster.local/auth/login +# → HTTP/1.1 401 Unauthorized + +# Новый пароль → OK: +# password=slxGj3G3FAD7l5ms2tJ9 → {"accesstoken":"eyJhbGciOiJIUzI1NiI..."} +``` + +--- + +## Что нужно исправить + +### Файл 1: `console/internal/api/server.go` — функция `getRouterToken()` + +**Проблема A:** читает пароль из env var один раз при старте → устаревает при ротации secret. +**Проблема B:** при ошибке login молча возвращает SA token вместо ошибки. + +**Нужно:** +- Читать username/password из **файла** при каждом вызове `getRouterToken()`, а не из `os.Getenv` при старте. + Путь файла: `/etc/fission-router-secret/username` и `/etc/fission-router-secret/password` +- При ошибке login — возвращать `("", error)`, не `readSAToken()`. + Caller (`handleInvokeFunction`) должен вернуть 503 с понятным сообщением. + +### Файл 2: `console/deploy/console.yaml` + +**Нужно:** заменить `env` → `secretKeyRef` на volume mount. + +```yaml +# Убрать из env: +- name: FISSION_AUTH_USERNAME + valueFrom: + secretKeyRef: + name: router + key: username +- name: FISSION_AUTH_PASSWORD + valueFrom: + secretKeyRef: + name: router + key: password + +# Добавить volume: +volumes: +- name: router-secret + secret: + secretName: router + items: + - key: username + path: username + - key: password + path: password + +# Добавить volumeMount: +volumeMounts: +- name: router-secret + mountPath: /etc/fission-router-secret + readOnly: true +``` + +Kubernetes обновляет смонтированные secret-файлы автоматически в течение ~60с после изменения secret. + +--- + +## Порядок работы + +1. Прочитать текущий код `getRouterToken()` в `console/internal/api/server.go` +2. Найти где инициализируются `s.authUser` / `s.authPass` (вероятно в `NewServer()` или аналоге) +3. Убрать сохранение в struct, читать из файла на каждый вызов `getRouterToken()` +4. Изменить возврат при ошибке login: `return "", fmt.Errorf("router login failed: %w", err)` вместо `readSAToken()` +5. Найти всех callers `getRouterToken()` — обработать ошибку (вернуть 503) +6. Обновить `console/deploy/console.yaml` (volume mount вместо env) +7. Увеличить тег образа (согласно правилам: vX.Y.Z → vX.Y.Z+1) +8. rsync → build → push → apply + +## Текущий тег образа + +Проверить: `grep "naeel/fission-console" console/deploy/console.yaml` +Последний известный: `v1.3.92` + +## SSH / rsync + +```bash +# rsync: +rsync -az -e "ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10" \ + ~/fission-console/ naeel@5.172.178.213:~/terra/fission/ + +# SSH: +ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213 'КОМАНДА' +```