From fb6f9d48cd5787d542682534786e83bfa797fdee Mon Sep 17 00:00:00 2001 From: Naeel Date: Sat, 4 Apr 2026 19:56:31 +0300 Subject: [PATCH] =?UTF-8?q?feat(tls):=20HTTPS=20+=20wss://=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20iot.kube5s.ru?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - emqx-ws-ingress.yaml: TLS секция + cert-manager letsencrypt-prod, ssl-redirect=true - router.go: CORS Allow-Origin: http → https://iot.kube5s.ru - iot-console.html: дефолт MQTT брокера ws:// → wss:// - operator.yaml: v0.1.53 → v0.1.54 - crypto.subtle теперь работает (HTTPS страница) --- deployments/k8s/emqx-ws-ingress.yaml | 24 +++++++++++++++--------- deployments/k8s/operator.yaml | 2 +- internal/api/router.go | 10 +++++----- internal/api/ui/iot-console.html | 6 +++--- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/deployments/k8s/emqx-ws-ingress.yaml b/deployments/k8s/emqx-ws-ingress.yaml index b360cb9..08d6cda 100644 --- a/deployments/k8s/emqx-ws-ingress.yaml +++ b/deployments/k8s/emqx-ws-ingress.yaml @@ -1,12 +1,13 @@ -# Изменено: 2026-04-04 (iot-console: добавлен path /console → sless-operator:9090) -# ВРЕМЕННЫЙ WORKAROUND: MQTT over WebSocket через порт 443. +# Изменено: 2026-04-04 (tls: добавлен TLS + cert-manager, wss://, https://) +# WORKAROUND: MQTT over WebSocket через порт 443. # Причина: порт 1883 заблокирован NSX-T Edge firewall на уровне облака. -# Решение: EMQX WebSocket listener (8083) проксируется через nginx-ingress. +# Решение: EMQX WebSocket listener (8083) проксируется через nginx-ingress с TLS termination. # -# IoT устройство подключается: ws://iot.kube5s.ru/mqtt -# IoT Консоль (UI): http://iot.kube5s.ru/console +# IoT устройство подключается: wss://iot.kube5s.ru/mqtt +# IoT Консоль (UI): https://iot.kube5s.ru/console # # DNS A-запись: iot.kube5s.ru → 185.247.187.147 (создана через Nubes API, zoneUid=498096ee) +# TLS: cert-manager + letsencrypt-prod, secret=iot-kube5s-ru-tls # # Когда DevOps откроет порт 1883 — этот файл можно удалить. --- @@ -32,14 +33,19 @@ metadata: namespace: sless annotations: kubernetes.io/ingress.class: nginx - # ssl-redirect=false: IoT устройства не умеют следовать 301 редиректам при WebSocket upgrade - nginx.ingress.kubernetes.io/ssl-redirect: "false" + cert-manager.io/cluster-issuer: letsencrypt-prod + # ssl-redirect=true: принудительно HTTPS для всего трафика на iot.kube5s.ru + nginx.ingress.kubernetes.io/ssl-redirect: "true" # WebSocket: nginx-ingress автоматически добавляет Upgrade/Connection при proxy-http-version=1.1 nginx.ingress.kubernetes.io/proxy-http-version: "1.1" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" spec: ingressClassName: nginx + tls: + - hosts: + - iot.kube5s.ru + secretName: iot-kube5s-ru-tls rules: - host: iot.kube5s.ru http: @@ -53,8 +59,8 @@ spec: port: number: 8083 # IoT Консоль (UI) — HTML SPA встроенный в бинарник sless-operator - # URL: http://iot.kube5s.ru/console - # Почему здесь: UI работает по HTTP чтобы ws:// (без TLS) не вызывал mixed content + # URL: https://iot.kube5s.ru/console + # TLS termination на Ingress → wss:// MQTT и https:// API работают без mixed content - path: /console pathType: Exact backend: diff --git a/deployments/k8s/operator.yaml b/deployments/k8s/operator.yaml index 5b39714..d30abc6 100644 --- a/deployments/k8s/operator.yaml +++ b/deployments/k8s/operator.yaml @@ -75,7 +75,7 @@ spec: - name: operator # При обновлении версии оператора — менять тег здесь (не latest!) # v0.1.50 — добавлены IoT controller, IoT REST API, MQTT auth endpoint - image: pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-operator:v0.1.53 + image: pearlharbor.registryk8s.services.ngcloud.ru/naeel/sless-operator:v0.1.54 # Always — чтобы всегда тянуть по точному тегу (не кешировать старый) imagePullPolicy: Always ports: diff --git a/internal/api/router.go b/internal/api/router.go index 35783bb..18ea616 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -1,8 +1,8 @@ -// Изменено: 2026-04-04 (iot-console: добавлен CORS middleware + /console маршрут) +// Изменено: 2026-04-04 (tls: CORS origin обновлён с http → https для iot.kube5s.ru) // router.go — регистрация всех REST-маршрутов через gorilla/mux. // Все маршруты /v1/ защищены Bearer-токеном (middleware.Auth). // /console — публичный маршрут (статический HTML без auth). -// CORS включён для http://iot.kube5s.ru — там хостится IoT Консоль (UI). +// CORS включён для https://iot.kube5s.ru — там хостится IoT Консоль (UI). package api @@ -16,12 +16,12 @@ import ( "gitea-naeel.giteak8s.services.ngcloud.ru/naeel/sless/internal/api/middleware" ) -// corsMiddleware добавляет CORS-заголовки для IoT Консоли на http://iot.kube5s.ru. -// Нужен потому что: консоль на http://iot.kube5s.ru, API на https://sless.kube5s.ru — разные origin. +// corsMiddleware добавляет CORS-заголовки для IoT Консоли на https://iot.kube5s.ru. +// Нужен потому что: консоль на https://iot.kube5s.ru, API на https://sless.kube5s.ru — разные origin. // Обрабатывает preflight OPTIONS запросы от браузера. func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "http://iot.kube5s.ru") + w.Header().Set("Access-Control-Allow-Origin", "https://iot.kube5s.ru") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type") w.Header().Set("Access-Control-Max-Age", "600") diff --git a/internal/api/ui/iot-console.html b/internal/api/ui/iot-console.html index 217624d..591b04b 100644 --- a/internal/api/ui/iot-console.html +++ b/internal/api/ui/iot-console.html @@ -194,7 +194,7 @@ const S = { // ns вычисляется из токена автоматически (SHA256(sub) → "sless-{hex}"), не вводится вручную ns: localStorage.getItem('iot_ns') || '', apiBase: localStorage.getItem('iot_api_base') || 'https://sless.kube5s.ru', - mqttBase: localStorage.getItem('iot_mqtt_base')|| 'ws://iot.kube5s.ru/mqtt', + mqttBase: localStorage.getItem('iot_mqtt_base')|| 'wss://iot.kube5s.ru/mqtt', // Рабочие данные devices: [], @@ -479,7 +479,7 @@ function renderLogin() {
- +
@@ -522,7 +522,7 @@ async function doLogin() { } S.apiBase = api || 'https://sless.kube5s.ru'; - S.mqttBase = mqtt || 'ws://iot.kube5s.ru/mqtt'; + S.mqttBase = mqtt || 'wss://iot.kube5s.ru/mqtt'; S.ns = ns; S.token = tok;