feat(iot): Этапы 2-7 — MQTT auth, IoT API, EMQX, mqtt-bridge, E2E demo

Этап 2+4: internal/api/handler/iot_device_handler.go
  - MQTTAuth: POST /internal/mqtt/auth (без JWT, для EMQX)
  - CreateIoTDevice, ListIoTDevices, GetIoTDevice (c password), DeleteIoTDevice, UpdateIoTDevice
  - crypto/subtle.ConstantTimeCompare против timing attacks

Этап 4: internal/api/router.go
  - /v1/namespaces/{ns}/iot/devices CRUD
  - /internal/mqtt/auth (без JWT middleware)

Этап 3: deployments/k8s/emqx.yaml
  - EMQX 5.5.1, emqx.conf (HOCON) с HTTP auth backend
  - Сервис exposure: 1883 (MQTT), 8083 (WS), 18083 (Dashboard)

Этап 3: iot/cmd/mqtt-bridge/main.go
  - paho.mqtt.golang: подписка на +/telemetry/+
  - amqp091-go: publish в iot.{namespace}.telemetry
  - deployments/k8s/iot-mqtt-bridge.yaml

Этап 7: examples/IOT/ — E2E demo (main.tf, handler.py, README.md)

go.mod: добавлен github.com/eclipse/paho.mqtt.golang v1.5.1
go build ./... — ошибок нет
This commit is contained in:
Naeel
2026-04-04 09:45:23 +03:00
parent 716efafda8
commit 1e53766c46
14 changed files with 1209 additions and 151 deletions
+167
View File
@@ -0,0 +1,167 @@
# Создано: 2026-04-04
# EMQX MQTT-брокер для IoT-сервиса (namespace: sless).
#
# Архитектура:
# IoT Device → MQTT CONNECT → EMQX (HTTP auth → sless-operator:9090/internal/mqtt/auth)
# EMQX → MQTT PUBLISH → sless-iot-bridge (paho subscriber) → RabbitMQ queue iot.{ns}.telemetry
# RabbitMQ → event-dispatcher → serverless function
#
# EMQX 5.x конфиг через emqx.conf (HOCON формат), монтируется как ConfigMap volume.
# НЕ используем env vars для конфигурации EMQX 5.x — они не поддерживаются аналогично 4.x.
#
# Порты:
# 1883 — MQTT (plaintext)
# 8883 — MQTTS (TLS, для prod надо настроить certSecret)
# 8083 — MQTT over WebSocket
# 18083 — EMQX Dashboard (admin/public по умолчанию — менять в prod!)
#
# Применение: kubectl apply -f deployments/k8s/emqx.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: emqx-config
namespace: sless
data:
# emqx.conf — HOCON конфиг для EMQX 5.5.x
# Раздел authentication: HTTP Backend для проверки MQTT credentials IoT-устройств.
# Наш сервис (sless-operator) ищет Secret iot-{deviceId} и сравнивает пароль.
emqx.conf: |
## EMQX 5.x configuration (HOCON format)
## Изменено: 2026-04-04
## HTTP Auth Backend для IoT-устройств
## EMQX посылает POST с {username, password, clientid} → наш сервис отвечает {"result":"allow"|"deny"}
authentication = [
{
mechanism = password_based
backend = http
enable = true
method = post
url = "http://sless-operator.sless.svc:9090/internal/mqtt/auth"
body {
username = "${username}"
password = "${password}"
clientid = "${clientid}"
}
headers {
"content-type" = "application/json"
}
connect_timeout = 5s
request_timeout = 5s
## allow_timeout_error = false — если наш сервис не отвечает, deny (безопаснее)
pool_size = 8
}
]
## ACL по умолчанию — разрешаем всё аутентифицированным клиентам
## Тонкая ACL настраивается через HTTP auth response (поле acl)
authorization {
no_match = allow
deny_action = disconnect
cache {
enable = true
max_size = 32
ttl = 1m
}
}
## MQTT настройки
mqtt {
max_packet_size = 1MB
max_topic_levels = 10
retain_available = false
}
## Listeners — только plaintext MQTT для MVP
## TLS (8883) отключён — настроить при необходимости
listeners.tcp.default {
bind = "0.0.0.0:1883"
max_connections = 1024
}
listeners.ws.default {
bind = "0.0.0.0:8083"
max_connections = 512
}
## Dashboard
dashboard {
listeners.http {
bind = 18083
}
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: emqx
namespace: sless
labels:
app: emqx
spec:
replicas: 1
selector:
matchLabels:
app: emqx
template:
metadata:
labels:
app: emqx
spec:
containers:
- name: emqx
image: emqx/emqx:5.5.1
ports:
- name: mqtt
containerPort: 1883
- name: ws
containerPort: 8083
- name: dashboard
containerPort: 18083
volumeMounts:
- name: emqx-conf
mountPath: /opt/emqx/etc/emqx.conf
subPath: emqx.conf
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
tcpSocket:
port: 1883
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
tcpSocket:
port: 1883
initialDelaySeconds: 40
periodSeconds: 20
volumes:
- name: emqx-conf
configMap:
name: emqx-config
---
apiVersion: v1
kind: Service
metadata:
name: emqx
namespace: sless
spec:
selector:
app: emqx
ports:
- name: mqtt
port: 1883
targetPort: 1883
- name: ws
port: 8083
targetPort: 8083
- name: dashboard
port: 18083
targetPort: 18083