Yandex Cloud Functions и n8n: безопасный webhook-прокси для событий ¶
Обновлено: 2026-05-30
Импортируйте workflow, замените credentials и прогоните тестовый payload до включения production.
Проблема: Yandex Cloud Functions удобно использовать как serverless-точку входа, но если она просто прокидывает JSON в n8n, любой получивший URL сможет имитировать событие и запускать workflow.
Решение: сделать Cloud Functions тонким защищённым прокси: функция добавляет timestamp, event_id и HMAC-подпись, n8n проверяет подпись, отсеивает повторы и только потом отправляет событие в CRM, Telegram, S3 или внутренний API.
Проблема: почему публичный webhook n8n нельзя оставлять без защиты ¶
Связка “Cloud Functions → n8n” часто нужна для событий Object Storage, Message Queue, API Gateway или небольших публичных интеграций. Проблема в том, что n8n webhook по умолчанию — это URL. Если он утечёт в логах, документации или фронтенде, злоумышленник сможет отправлять фальшивые события.
Без подписи нельзя отличить настоящее событие от ручного POST. Без idempotency повторная доставка может запустить бизнес-действие дважды. Без timestamp нельзя ограничить replay-атаки. Поэтому статья закрывает не “как дернуть n8n из функции”, а как сделать безопасный event ingress.
Архитектура связки Yandex Cloud Functions → n8n ¶
| Нода | Роль | Что проверить |
|---|---|---|
| Cloud Function | принимает событие или HTTP-запрос | service account, секрет, timeout |
| Sign payload | добавляет `x-nodbot-signature` | HMAC SHA-256, timestamp, event_id |
| n8n Webhook | принимает подписанное событие | production URL, только POST |
| Verify signature | сравнивает HMAC и возраст события | constant-time compare, max age |
| Idempotency check | не пропускает повторный event_id | Postgres unique key или durable storage |
| Route event | запускает нужный бизнес-процесс | тип события, retry, alert |
Cloud Functions не должна содержать бизнес-логику CRM. Её задача — принять событие, подписать его и быстро передать в n8n. Так проще менять automation-логику без redeploy функции.
Контракт события от Cloud Functions ¶
{
"event_id": "yc-evt-2026-05-30-00091",
"event_type": "object_storage.created",
"bucket": "client-docs",
"object_key": "incoming/report-1042.pdf",
"occurred_at": "2026-05-30T10:00:00Z",
"metadata": {
"tenant_id": "acme",
"source": "yandex-cloud-functions"
}
}
`event_id` должен быть стабильным для повторной доставки одного и того же события. Если источник не даёт такой ID, соберите его из bucket, object_key, version и timestamp источника.
Code Node: проверка HMAC, timestamp и event_id ¶
const crypto = require('crypto');
const secret = $env.YC_N8N_WEBHOOK_SECRET;
if (!secret) throw new Error('YC_N8N_WEBHOOK_SECRET is not configured');
const headers = $json.headers ?? {};
const body = $json.body ?? $json;
const signature = String(headers['x-nodbot-signature'] ?? headers['X-Nodbot-Signature'] ?? '');
const timestamp = String(headers['x-nodbot-timestamp'] ?? headers['X-Nodbot-Timestamp'] ?? '');
const eventId = String(body.event_id ?? '').trim();
if (!eventId) throw new Error('Missing event_id');
if (!timestamp || Math.abs(Date.now() - Number(timestamp)) > 5 * 60 * 1000) {
throw new Error('Webhook timestamp is missing or too old');
}
const raw = JSON.stringify(body);
const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${raw}`).digest('hex');
if (!signature || !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new Error('Invalid Cloud Functions signature');
}
return [{
json: {
event_id: eventId,
idempotency_key: `yc-functions:${eventId}`,
event_type: body.event_type,
payload: body,
verified_at: new Date().toISOString()
}
}];
Что должна делать сама Cloud Function
Функция должна собрать raw JSON, timestamp в миллисекундах и подпись HMAC SHA-256 по строке timestamp.body. Секрет хранится в переменных окружения Cloud Functions и n8n, но не попадает в payload или лог ответа.
Готовый workflow JSON: скачать и импортировать ¶
Скачать готовый workflow JSON Скачать тестовый payload
{
"name": "Nodbot - Yandex Cloud Functions to n8n secure webhook",
"nodes": [
{
"name": "n8n Webhook",
"type": "n8n-nodes-base.webhook",
"purpose": "Принять событие от Cloud Functions"
},
{
"name": "Verify HMAC signature",
"type": "n8n-nodes-base.code",
"purpose": "Проверить подпись, timestamp и event_id"
},
{
"name": "Check idempotency",
"type": "n8n-nodes-base.postgres",
"purpose": "Отсеять повторную доставку"
},
{
"name": "Route by event type",
"type": "n8n-nodes-base.code",
"purpose": "Выбрать сценарий по event_type"
},
{
"name": "Call business workflow",
"type": "n8n-nodes-base.httpRequest",
"purpose": "Запустить CRM/S3/Telegram/API действие"
},
{
"name": "Respond to Cloud Function",
"type": "n8n-nodes-base.respondToWebhook",
"purpose": "Вернуть безопасный статус"
}
],
"connections": "n8n Webhook → Verify HMAC signature → Check idempotency → Route by event type → Call business workflow → Respond to Cloud Function"
}
Пошаговая настройка Cloud Functions, секрета и n8n ¶
- Создайте секрет `YC_N8N_WEBHOOK_SECRET` в Cloud Functions и в окружении n8n.
- В Cloud Functions добавьте HMAC-подпись по timestamp и raw body.
- Импортируйте workflow JSON и включите production webhook URL.
- Создайте таблицу idempotency с unique index по `idempotency_key`.
- Настройте маршруты по `event_type` и alert на invalid signature.
Тесты перед production и проверка подписи ¶
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/yandex-cloud-functions-to-n8n" \
-H "Content-Type: application/json" \
--data @yandex-cloud-functions-to-n8n-payload.json
- Отправьте корректное событие с валидной подписью.
- Повторите тот же `event_id` и проверьте, что бизнес-действие не повторилось.
- Измените один символ payload после подписи: workflow должен отклонить запрос.
- Отправьте старый timestamp и проверьте защиту от replay.
- Проверьте ошибку downstream API: n8n должен залогировать событие и отправить alert.
Production-риски serverless webhook-прокси ¶
- Секрет прошит в коде функции. Используйте переменные окружения и секреты, а не строку в репозитории.
- Сравнение подписи обычным `===`. Для HMAC лучше constant-time compare, чтобы не открывать timing-атаки.
- Нет idempotency. Повторная доставка serverless-события запускает бизнес-действие дважды.
- Функция ждёт долгий workflow. Пусть n8n отвечает быстро, а долгие операции уходят в отдельную очередь или sub-workflow.
- Логи содержат payload с PII. Маскируйте персональные данные и не пишите секреты в execution data.
Полезные ссылки и смежные workflow ¶
См. также Webhook signature validation, idempotency keys, webhooks API gateway и error workflow alert. Официальные документы: Yandex Cloud Functions, Cloud Functions triggers и n8n Webhook node.
Критерии готовности ¶
- Все запросы от Cloud Functions подписаны HMAC.
- n8n отклоняет старые timestamp и invalid signature.
- Повторный event_id не запускает бизнес-действие второй раз.
- Секрет хранится в ENV/secret manager, а не в workflow description.
- Ошибки downstream API попадают в alert и audit log.
Nodbot настроит защищённый webhook ingress: Cloud Functions, HMAC, idempotency, retry, alerting и маршрутизацию событий в ваши workflow.
Обсудить serverless-интеграцию