Железо проекта: как мы строили комнату с хакерским квестом
Пару недель назад мы провели онлайн-квест для хакеров: построили комнату, которую заполнили умными устройствами и запустили из нее YouTube-трансляцию. Игроки могли управлять IoT-девайсами с сайта игры; целью было найти запрятанное в комнате оружие (мощную лазерную указку), хакнуть его и устроить в комнате короткое замыкание.
Чтобы добавить остросюжетности, мы поставили в комнате шредер, в который загрузили 200 000 рублей: шредер съедал по купюре в час. Выиграв игру, можно было остановить шредер и забрать все оставшиеся деньги.
Было очень много запросов показать момент уборки комнаты — показываем, как мы ее разбираем
Архитектура железа: управление комнатой
Проектировать аппаратное решение мы начали, когда был уже приблизительно понятен сценарий, готов бекенд и у нас стояла пустая комната, готовая для монтажа оборудования.
Вспоминая старый анекдот «The S in IoT stands for Security» («Буква S в аббревиатуре IoT обозначает Security») мы приняли решение, что в этот этот раз игроки по сценарию игры взаимодействуют только с фронтендом и бэкендом сайта, но не получают возможности добраться непосредственно к железу.
Это было сделано из соображений безопасности и зрелищности происходящего на экране: при непосредственном доступе игроков к железу, было бы значительно сложнее изолировать безопасные и потенциально опасные действия, например, ускоренную прокрутку шредера или управление пиротехникой.
Перед началом проектирования у нас сформулировались несколько принципов управления игровыми устройствами, которые стали базой конструкции:
Не использовать беспроводные решения
Все игровое пространство находится в одном кадре, до каждого уголка которого можно дотянуться. Реальной необходимости в беспроводных подключениях не было и они бы просто стали еще одной точкой отказа.
Не использовать какие-то специальные устройства от умного дома
В основном, ради гибкости настройки. Понятно, что можно настроить под нашу задачу множество коробочных версий систем умного дома с готовой админкой и управлением, но трудозатраты были бы сопоставимы с созданием своего простого решения.
Кроме того, нужно было придумать устройства, по которым будет явно видно, что именно игроки меняют его состояние: включили/выключили или проставили конкретный свет на буквах СОКОЛ.
Мы собрали все элементы из общедоступного железа, которое можно купить в обычных магазинах радиодеталей: между доставкой пиццы и диетической колы, на площадку постоянно приезжали курьеры Чип и Дип и Леруа.
Выбор собрать все самим упрощал отладку, масштабируемость, однако, требовал большей аккуратности при монтаже.
Все реле и арудино не должно быть видно в кадре
Мы решили свести все управляемые элементы в одно место и спрятать за кадром, чтобы иметь возможность контролировать работоспособность и, если понадобится, аккуратно проползти вне зоны видимости камеры и заменить вышедший из строя блок.
В итоге все спрятали под столом, а камеру установили так, чтобы ниже стола ничего не было видно. Это была наша «слепая зона» для подползания инженера
В итоге у нас получилось фактически одно умное устройство: оно получало от бэкенда состояние каждой своей части и меняло его соответствующей командой.
С точки зрения аппаратной реализации это устройство управляло 6 элементами:
Несколько настольных ламп, они имеют состояние вкл/выкл и управляются игроками
Буквы на стене, они могут менять свой цвет по команде игроков
Вентиляторы, которые крутятся и открывают флипчарт при нагрузке на сервер
Лазер, который управляется через ШИМ
Шредер который сжирал деньги по расписанию
Дым-машина, которая срабатывала перед каждым выстрелом лазера
Тестируем дым-машину вместе с лазером
Позже добавился ещё сценический свет, стоявший за кадром и управлявшийся ровно как светильники из пункта 1. Сценический свет срабатывал в двух случаях: подсвечивал лазер при подаче на него питания и подсвечивал гирю перед тем, как лазер запускался в боевом режиме.
Что из себя представляло это умное устройство
Всю дорогу Юра, наш хардварщик, старался не усложнять и придумать самое простое, минималистичное решение из возможных.
Предполагалось, что на VPS будет крутиться просто скрипт, который получает json с состоянием устройств и пересылает его на подключенную по usb ардуинку.
К портам подключались:
16 обычных реле (именно они издавали то щелканье, которое было слышно на видео. В основном мы выбрали их из-за этого звука)
4 твердотельных реле для управления каналов с ШИМ, например вентиляторов,
отдельный ШИМ выход для лазера
вывод, формирующий сигнал на светодиодную ленту
Вот пример json-команды, которая приходила к реле от сервера
Чтобы отследить момент, когда лазер наконец пережжет веревку и гиря полетит на аквариум, мы сделали небольшую кнопку, которая срабатывала на падение гири и давала сигнал системе.
Кнопка-мониторинг движения гири
При этом сигнале должны были загореться дымовые шашки, сделанные из шариков для пинг-понга. Мы вложили 4 дымовухи прямо в корпус сервера и подвели к ним нихромовую нить, которая должна была раскалиться и сработать как запал.
Корпус с дымовыми шашками и китайской гирляндой
Ардуино
На ардуинке по первоначальному замыслу происходило два действия.
Первое — при получении нового запроса, запрос парсился с помощью библиотеки ArduinoJson. Далее каждому управляемому устройству сопоставлялись два его свойства:
состояние питания «включен» или «выключен» (стандартное состояние)
период, на который устройство включено — время в микросекундах от старта платы, когда уже пора ее выключать, то есть приводить состояние к стандартному
Последнее время задавалось при получении соответствующего параметра в JSON, однако его можно было и не передавать, тогда значение устанавливалось в 0 и обнуления не происходило.
Второе действие, которое производила ардуинка каждый цикл — это актуализация состояний, то есть проверка, нет ли необходимости что-то включить или не пришло ли время выключать какое-либо устройство.
Лазерная указка — тот самый Мегатрон 3000
Это обычный лазерный модуль для резки и маркировки LSMVR450-3000MF 3000мВт 450нм с ручной фокусировкой.
Буквы Сокол
Сделаны очень просто — мы просто скопировали буквы с логотипа, вырезали их из картона, а потом обклеили led-лентой. При это пришлось спаивать куски ленты между собой, по 4 контакта на каждом шве, но результат того стоил. Наш бекендер Паша показал чудеса умелости, сделав это меньше чем за несколько часов.
Первые тесты iot-устройства и допиливание
Мы сделали первые тесты и заодно нам подъехали новые задачи. Дело в том, что в середине процесса к команде присоединился настоящий кинопродюсер и оператор из ВГИКа Илья Серов — он выстроил кадр, добавил дополнительное киношное освещение и немного изменил сценарий игры, чтобы сюжет получался более эмоциональным, а картинка более драматичной и театральной.
Это существенно увеличило качество, но появились элементы, которые тоже понадобилось подключать к реле и прописывать алгоритм работы.
Другой проблемой оказался лазер: мы провели несколько экспериментов с разными типами веревки и лазерами различной мощности. Для теста мы просто вертикально подвешивали груз на веревке.
При запуске с тестовым токеном мощность регулируемая через шим составляла менее 10% и веревку не повреждала даже при длительной экспозиции.
Для боевого режима лазер расфокусировали примерно до пятна диаметром 10 мм и он уверенно пережигал веревку с грузом, с расстояния около метра.
Так лазер срабатывал отлично на тестах
Когда мы уже начали тестировать все прямо в комнате на подвешенной гире, оказалось, что надежно закрепить лазер не так-то просто. Затем, что когда веревка горит — она плавится, растягивается и смещается из под первоначального фокуса.
А вот так он уже не работал: веревка смещалась
Илья переместил лазер на противоположной от веревки конец комнаты, чтобы лазерный луч шел через всю сцену и красиво смотрелся в кадре, из-за чего расстояние увеличилось вдвое.
Проведя ещё несколько экспериментов с пережиганием веревки уже в бою, мы решили не пытать судьбу и подстраховать разрезание веревки с помощью нихромовой проволоки. Она уничтожала нить через 120 секунд после включения лазера в боевом режиме. Это, а также отключение проволоки и запал дымовых шашек при срабатывания контакта отрыва мы решили жестко прописать прямо в железе микроконтроллера.
Нить, которая в итоге пережигала веревку за кадром
Таким образом появилась третья задача которую решала ардуинка — отработать последовательности, связанные с исполнением этих команд.
Также мы решили отдать ардуинке необходимость вести отсчет денег на телевизоре и запускать шредер. Первоначально предполагалось что этим займется бекэнд и на сайте будет виден текущий баланс, а на телевизоре мы будем показывать комментарии с ютуба, как дополнительный интерактивный элемент, подсказывающий зрителям, что события в комнате происходят в реальном времени.
Но на тестовом прогоне Илья отсмотрел сцену и предложил на самом большом экране показывать игровой баланс: сколько денег еще осталось, сколько съедено и обратный отсчет до следующего запуска шредера.
Ардуино мы завязали на текущее время: каждый полный час запускался шредер. Картинка на телевизор выдавалась с помощю распберри, которая в тот момент уже получала с сервера запросы и пересылала их на исполнение в ардуинку. Картинки с денежными показателями рисовались с помощью вызова консольной утилиты fim примерно вот так
image = subprocess.Popen(["fim", "-q", "-r", "1920×1080", fim_str]), где fim_str
И формировалась исходя из нужной суммы или времени.
Картинки мы сгенерировали заранее: просто взяли готовое видео с таймером и экспортировали 200 картинок.
Вот такая механика была запрограммирована в кресте. К моменту, как запустился финальный отсчет, мы все выехали на площадку, вооружились огнетушителями и сели ждать пожар (который вовсю пылал только в дискорде)
Как сделать трансляцию, которая работает неделю: выбор камеры
Для квеста нам нужна была непрерывная трансляция на ютубе в течение 7 дней — именно столько мы закладывали как максимальную продолжительность игры. Было две вещи, которые нам могли помешать:
Перегрев камеры от непрерывной работы
Обрыв интернета
Камера должна была отдавать картинку как минимум Full HD, чтобы играть и наблюдать за комнатой было комфортно.
Изначально мы смотрели в сторону веб-камер, которые выпускают для стримеров. Мы резали бюджет, поэтому покупать камеру не хотелось, а в аренду, как оказалось, их не дают. В этот же момент мы чудом нашли лежащую у меня дома камеру Xbox Kinect, поставили в комнате и запустили тестовую трансляцию на неделю.
Камера справлялась нормально и не перегревалась, но Илья почти сразу заметил, что в ней не хватает настроек, в частности нельзя выставить экспозицию.
Илья стремился приблизить вид трансляции к стандартам кино-видео производства: передавать динамично меняющуюся световую сцену с яркими источниками света, затемнённым фоном и предметами в кадре. При этом хотелось сохранить проработку изображения как в светах так и в тенях, с минимальным цифровым шумом.
Поэтому, хоть кинект и показал себя надежным при тестах и ему не требовалась плата видеозахвата (еще одна точка отказа), от него мы решили отказаться. После трёх дней тестов разных камер, Илья выбрал Sony FDR-AX53 — небольшой надежный камкордер, бюджетный в аренде, но при этом обладающий достаточной надежностью и изобразительными характеристиками.
Мы арендовали камеру, включили ее на неделю в связке с платой видеозахвата и поняли, что с ней можем рассчитывать на непрерывную трансляцию в течении всего квеста.
Делаем кино: постановка сцены и света
Работа над освещением требовала определенного изящества, нам требовалось минимальными средствами выстроить световую партитуру:
1. Подсветка предметов, когда их находят игроки (лазер, гиря), а также постоянный свет на шредер. Здесь использовались dedolight 150 — надежные и компактные осветительные киноприборы с низковольтными галогенными лампами, позволяющие акцентно сфокусировать луч на конкретном предмете, не задевая фон и остальные предметы.
2. Практический игровой свет — настольная лампа, торшер, звезда, гирлянда. Весь практический свет был гармонично распределён в кадре, чтоб освещать свою область изображения, внутри стояли led лампы с цветовой температурой 3200К, лампа в торшере была закрыта красным фолиевым фильтром Rosco, для создания необычного цветового акцента-подсказки.
Я у мамы инженер или запуск завтра
Как мы резервировали интернет и электричество
К вопросу отказоустойчивости подошли почти как в дата-центре: решили не отступать от основных принципов и зарезервировали по привычной схеме N+1.
Если на ютубе трансляция прекращается, это значит, что заново подсоединиться по той же ссылке и продолжить стрим уже будет невозможно. Это был критический момент, к тому же комната находилась в обычном офисе.
Для этого мы использовали роутер на базе OpenWRT и пакет mwan3. Он автоматически тестировал каждые 5 секунд доступность канала и, в случае обрыва, переключался на резервный модем с Yota. В итоге переключение на резервный канал происходило меньше чем за минуту.
Также не менее важно было исключить перебои с электричеством, ведь даже кратковременный скачок напряжения вызвал бы перезагрузку всех компьютеров.
Поэтому мы взяли бесперебойник ippon innova g2 3000, который резервировал бы все игровые устройства: суммарная потребляемая мощность нашей системы была в районе 300 Ватт. Его хватило бы на 75 минут, вполне достаточно для наших целей.
Мы решили пожертвовать дополнительным освещением в случае, если в помещении отключится электричество — его к бесперебойнику не подключали.
Благодарности
Всей команде RUVDS, которая придумывала и реализовывала игру.
Отдельно админам RUVDS, за то, что следили за работой серваков, нагрузка была приемлемой и все работало штатно в обычном режиме.
Лучшему боссу ntsaplin за то, что в ответ на звонок «есть идея: мы возьмем сервер, на него поставим аквариум, а над ним подвесим гирю, бум, бах, все залило водой, короткое замыкание, пожар!» он всегда уверенно говорит «делайте!»
Спасибо Tilda Publishing и отдельно Михаилу Карпову за то, что он не просто пошел навстречу и разрешил нарушить Terms of use, но даже подарили нам бизнес-аккаунт на год, когда мы рассказали о проекте.
Илье Серову S_ILya за то, что он присоединился и стал сопродюсером проекта, готовым полночи ползать, приклеивая светодиодную ленту, искать технические решения и сделать все, чтобы у нас получилось настоящее кино.
zhovner за то, что всегда был готов спасти ситуацию, когда другие разводили руками, борщик, моральную поддержку и разговоры до утра.
samat за то, что связал нас с лучшим пентестером страны, который проконсультировал нас и помог с задачками.