Автоматический перенос credentials между n8n
У меня стоит 2 версии n8n где пишу скрипты и есть версия куда я перемещаю уже сформированные сценарии которые запускаются один раз и больше я их особо не трогаю. Так вот, мне надоело каждый раз копировать доступы (credentials) между n8n верями и я написал простой триггер для PostgresSQL базы который автоматически копирует или обновляет триггеры на "боевой" версии n8n.
Предварительная настройка
Обе копии должны работать с одним ключем шифрования и он должен быть обязательно выставлен в окружении .env файле n8n среды. У меня он прописан таким образом:
N8N_ENCRYPTION_KEY=Kp9mX2vL8nQ4rT1231231aZ3bC5dE7fG9hJ0iK2lM4
Если у вас n8n на бегет, то файл лежит тут:
/opt/beget/n8n/.env
Но опять же, скрипт работает если n8n у вас лежат в одной БД и у одного пользователя есть доступ сразу к двум БД одновременно.
Запускаете данный скрипт в БД откуда требуется копировать данные автоматически, а вместо n8n_fire вы прописываете название БД в которую хотите копировать доступы. Вместо kirill.vech@gmail.com прописываете email пользователя которому будет выдаваться доступ к credentials в "боевой" версии n8n.
-- === Функция синхронизации (INSERT / UPDATE) === CREATE OR REPLACE FUNCTION sync_credential_to_fire() RETURNS trigger AS $$ DECLARE target_db TEXT := 'n8n_fire'; -- Целевая база target_user_email TEXT := 'kirill.vech@gmail.com'; -- Владелец target_project_id TEXT; BEGIN -- Проверяем наличие dblink PERFORM 1 FROM pg_extension WHERE extname='dblink'; IF NOT FOUND THEN EXECUTE 'CREATE EXTENSION IF NOT EXISTS dblink'; END IF; -- Получаем projectId пользователя по email BEGIN SELECT id INTO target_project_id FROM dblink( format('dbname=%I', target_db), format( $q$ SELECT p."id" FROM project p JOIN project_relation pr ON pr."projectId" = p."id" JOIN "user" u ON u."id" = pr."userId" WHERE u."email" = %L ORDER BY p."createdAt" ASC LIMIT 1 $q$, target_user_email ) ) AS proj("id" text) LIMIT 1; EXCEPTION WHEN OTHERS THEN RAISE NOTICE '❌ Ошибка при получении project_id: %', SQLERRM; RETURN NEW; END; IF target_project_id IS NULL THEN RAISE NOTICE '⚠️ Проект не найден для пользователя % в %', target_user_email, target_db; RETURN NEW; END IF; -- Копируем или обновляем credential BEGIN PERFORM dblink_exec( format('dbname=%I', target_db), format( $q$ INSERT INTO credentials_entity ("id","name","data","type","createdAt","updatedAt","isManaged") VALUES (%L,%L,%L,%L,%L,%L,%L) ON CONFLICT ("id") DO UPDATE SET "name"=EXCLUDED."name", "data"=EXCLUDED."data", "type"=EXCLUDED."type", "updatedAt"=EXCLUDED."updatedAt", "isManaged"=EXCLUDED."isManaged"; $q$, NEW."id",NEW."name",NEW."data",NEW."type", NEW."createdAt",NEW."updatedAt",NEW."isManaged" ) ); EXCEPTION WHEN OTHERS THEN RAISE NOTICE '❌ Ошибка при копировании credential %: %', NEW."id", SQLERRM; RETURN NEW; END; -- Добавляем доступ на проект пользователя BEGIN PERFORM dblink_exec( format('dbname=%I', target_db), format( $q$ INSERT INTO shared_credentials ("credentialsId","projectId","role","createdAt","updatedAt") VALUES (%L,%L,'owner',NOW(),NOW()) ON CONFLICT DO NOTHING; $q$, NEW."id",target_project_id ) ); EXCEPTION WHEN OTHERS THEN RAISE NOTICE '❌ Ошибка при создании shared_credentials для %: %', NEW."id", SQLERRM; END; RAISE NOTICE '✅ Credential % синхронизирован и расшарен для проекта %', NEW."id", target_project_id; RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- === Пересоздаём только один триггер (без delete) === DROP TRIGGER IF EXISTS trg_sync_credentials_to_fire ON credentials_entity; CREATE TRIGGER trg_sync_credentials_to_fire AFTER INSERT OR UPDATE ON credentials_entity FOR EACH ROW EXECUTE FUNCTION sync_credential_to_fire();