Хабрахабр

Аутентификация устройств на Linux по аппаратному ключу в системах верхнего уровня

Industrial IoT — это мониторинг, диспетчеризация и автоматизация инженерных систем промышленных объектов, зданий, бизнес-объектов. Датчики разных параметров, счетчики и контроллеры собирают данные с этих объектов, например, температуру и влажность воздуха в серверной, показания счетчиков воды в многоквартирных домах, уровень углекислого газа в помещениях. Контроллеры обрабатывают эту информацию и отправляют все в «облако».

Устройства собирают данные с нефтедобывающих скважин и банковских отделений, следят за микроклиматом в серверных и супермаркетах. Компания Wiren Board производит контроллеры с Linux для industrial IoT. Системы аутентифицируют устройства — понимают, что разговаривают со своим датчиком, а не с чужим, а потом авторизуют. Контроллеры интегрируются с системами верхнего уровня партнеров компании. Простые традиционные способы, например, пары логин/пароль, уязвимы к атакам и неудобны в развёртывании. На этом этапе возникает проблема — контроллеров тысячи, клиентов сотни, а единой системы интеграции нет.

Теперь единая система интеграции не нужна —аутентификация и авторизация защищены, и работают «из коробки». Поэтому в компании разработали аутентификацию в системах верхнего уровня по аппаратным ключам — на основе стандартной асимметричной криптографии с использованием аппаратного защищённого элемента для хранения ключей. Особый упор на развёртывание: внедрение инициализации устройств на производстве, внедрение поддержки разного софта верхнего уровня, в том числе в чужого и закрытого.
О спикере: Евгений Богер (evgeny_boger) — технический директор и сооснователь Wiren Board. Как это удалось сделать расскажет Евгений Богер: как выбирали «крипточип», как прикручивали его к железу и к Linux, как заставили с ним дружить распространённые библиотеки и ПО. Занимается встраиваемыми системами и, в особенности, встраиваемыми Linux.

Проблемы

Начну с того, что мы делаем и откуда у нас эта проблема возникла. Мы в Wiren Board разрабатываем и производим оборудование в России. Раньше это называли M2M, а сейчас — industrial IoT. Это автоматизация инженерных систем зданий, мониторинг и диспетчеризация. Кратко вся работа выглядит так: датчики разных параметров, исполнительные устройства, счетчики и контроллеры (edge-computing или IoT-gateway) собирают разные данные с объектов, обрабатывают их, исполняют локальную логику, а потом собираются в одной большой системе диспетчеризации, мониторинга или управления.

Мы производим оборудование, которое интегрируется с несколькими системами верхнего уровня наших партнеров. У нас нет цельной экосистемы, в отличии от некоторых конкурентов. Без хороших технических средств интеграция не будет работать — просто договориться не получается. Компаний-партнеров много и они разделяют между собой ответственность.

Первый — выдать логин/пароль клиенту, как делают все, а второй — генерировать и зашивать «секрет» на производстве. Для решения этих проблем есть два простых решения. Оба варианта нам не подошли — расскажу почему.

Простые решения

Первое решение — выдача логина и пароля клиенту. Так делают все и мы до недавнего времени.

Он будет общий на контроллерах и на системе верхнего уровня, которая собирает данные с нескольких контроллеров. Для аутентификации устройства, которое отправляет данные в какую-то систему, можно сделать секретный ключ — условно логин/пароль («секрет»).

Кто-то должен сгенерировать секретную пару, отправить по e-mail, аутентифицировать клиента по номеру счета. Пару логин/пароль (общий «секрет») нужно как-то выдать клиенту — компании или человеку. Это стандартная процедура — низкие технологии.

Она в том, что у нас много таких систем. Проблема. Это сложное взаимодействие между всеми причастными сторонами. Клиент наш, а данные он может отправлять в систему нашего партнера.

Кроме проблемы множества систем, есть еще другие.

  • Плохая выдача и доставка до клиента.
  • Логины и пароли хранят на сервере. Если будем хранить еще и хэши, это нас немного обезопасит от утечек. Но даже при этом возникает неприятное чувство, когда на сервере хранятся секретные ключи для всех контроллеров клиентов. Некоторые из них могут заниматься критическими задачами: наружным освещением, мониторингом нефтяных вышек.
  • Синхронизация между сервисами.
  • Восстановление при потере. Непонятно, что делать при потерях, когда клиент стер память контроллера — в какую память писать? Придется повторять все заново.
  • Защита от копирования реквизитов. Есть платные системы мониторинга, которые предоставляют клиенту сервис и берут с него оплату по подписке. Не хочется, чтобы конечный клиент смог как-то обходить систему через нас — заплатить один раз, а использовать два.

Второе решение — генерировать и зашивать «секрет» на производстве. Это улучшение предыдущего решения.

Логины и пароли из оборудования нельзя ни прочитать, ни поменять. Схема такая: мы, как производитель контроллеров, заранее генерируем логины и пароли для всех, зашиваем в свою систему и заносим в оборудование. Это лучше предыдущего варианта, потому что не требует взаимодействия между людьми.

Остались все проблемы, кроме первой, но главная из них — синхронизация между сервисами и интранет. Проблемы. У нас есть клиенты, которые используют оборудование в своих закрытых сетях. Сервисов много и непонятно, как их синхронизовать — из-за этого мы не смогли внедрить второе решение. Она настроена, один раз работает, а донести «секреты» дальше сложно. Мы выпустили новый контроллер, продали клиенту, а его система закрытая. В организациях все сложно, хотя технически просто. Доносить партиями?

Поэтому мы решили пойти по другому пути. Оба решения нам не подошли. Но перед этим решили обозначить общие задачи и цели.

Задачи и цели

Сначала общие задачи.

Это способ понять, кто разговаривает с системой верхнего уровня, кто именно подключается к системе диспетчеризации. Аутентификация.

Аутентификация — это не предоставление или разграничение прав доступа, а способ понимания, кто с нами говорит.

Задача отправки данных. Наши контроллеры — это компьютеры с Linux, разработанные под специальную задачу. Нам нужно, чтобы они отправляли данные в системы верхнего уровня, подключались по VPN. При этом мы хотим, чтобы отправка работала «из коробки» — без настроек и взаимодействия наших клиентов и конечных пользователей системы с нами и с клиентами.

Это надежность соединения, шифрование канала данных, но отдельный вопрос — авторизация. Другие задачи. Задача авторизации связана с внешними сервисами и делится на три части.

  • Бесплатный сервис производителя. Предоставлять доступы по серийному номеру устройства.
  • Белые списки серийных номеров для сервиса наших партнеров — привязывать покупки и доступы к аккаунту клиента.
  • Лицензии. Разрешать или запрещать доступ на основе опций, которые указаны в сертификате.

Цели — это то, что мы хотим достичь, когда решим задачи.

Без участия людей — информация зашивается роботами на производстве. Выдача и доставка до клиента.

Мы хотим, чтобы вообще не было потерь секретных реквизитов. Восстановление при потере.

Хотим обойтись без неё, чтобы не требовалось ничего доставлять в сервисы. Доставка от производства до сервисов. При запуске нового оборудования мы не хотим обновлять базы всех сервисов, которые должны аутентифицировать эти устройства.

Желательно вообще ничего там не хранить. Хранение на сервере.

Также желательно ничего не синхронизовать — ведь ничего хранить не будем. Синхронизация между сервисами и интранет.

Хотим, чтобы что-то секретное, за что берутся деньги, нельзя было скопировать и получить бесплатно. Защита от копирования реквизитов.

Цифровая подпись спешит на помощь

Электронная цифровая подпись (ЭЦП) — это технология, вокруг которой у нас все работает.

Это как обычная подпись, только цифровая. ЭЦП легко проверить, но сложно подделать. Знакомые всем прописные истины криптографии, которым десятки лет.

Если знать публичный ключ (public key), легко проверить, что электронная подпись для сообщения правильная. Электронная подпись — это что-то, что можно посчитать по сообщению, если знать секретный приватный ключ (private key). По названию понятно — публичный принято сообщать всем, а секретный только у того, кто подписывает.

Все подписи и ключи — это просто числа.

В нашем случае это 32 байта данных, которая работает на математической «магии». Математика гарантирует, что подпись просто проверить, но сложно подделать.

Мы используем подпись ECDSA-256+SHA-256:

  • e = HASH(m) — криптографическая хеш-функция необратимо преобразовывает сообщение m в число e;
  • private key (dA) — случайное число;
  • public key (QA) — генерируется из private key, но не наоборот;
  • signature (r,s) = sign(private key, e) — подпись;
  • verify(public key, signature, e) — проверка подписи.

Аутентификация по ЭЦП. Первая попытка

Что можно сделать для нашей задачи, используя этот хитрый механизм, который в одну сторону работает просто, а в другую сложно?

Генерируем случайный приватный ключ для каждого устройства на производстве. Выдача и доставка до клиента. Никому не говорим, потому что даже сами его не знаем, и записываем в устройство.

Дальше используем только публичный ключ этого устройства для аутентификации на сервисах. Доставка от производства до сервисов. На сервисах храним только список публичных ключей вместо паролей.

Стандартный алгоритм проверки работоспособности:

  • сервис отправляет контроллеру случайное сообщение m;
  • контроллер: sign(private key, m);
  • контроллер отправляет сервису подпись;
  • сервис: verify(public key, signature, m).

Единственное, что мы решили таким способом — это то, что больше не храним на своих сервисах общие «секреты» в открытом или закэшированном виде. Это не то, что нам хочется.

Аутентификация по ЭЦП. Вторая попытка

Мы не хотим что-то хранить на сервисах. Чтобы этого добиться, мы можем заставить наши устройства отправлять свои публичные ключи сервису.

Первая — проверили, что выдали сервису ключ. На прошлом этапе мы решили две задачи. Вторая — убедились, что устройство владеет приватным ключом, который лежит где-то на флешке. У нас есть публичный ключ, значит приватный тоже делали мы. Если устройство могло что-то подписать, значит у него есть приватный ключ.

Как проверить, что никто его не перехватил, не подделал, и что все работает? Теперь устройство отправит сервису еще и публичный ключ.

Создаем себе еще один публичный ключ. Проверка публичного ключа. Это корневой ключ «root private key + public key». Он будет нашим ключом, как производителя. Устройство должно отправить свой публичный ключ и подпись своего публичного ключа сервису. Этим корневым секретным ключом на производстве подпишем публичный ключ устройства (device public key) и будем хранить эту подпись на устройстве. Если он подписан корневым ключом (root private key), значит мы выдали этот ключ. Теперь сервис может проверить публичный ключ устройства.

Создать и хранить подпись на устройстве может только производитель — мы, а проверить — все.

Публичный ключ мы публикуем на сайте в разделе «Контакты». Кто угодно может его взять, и проверить публичный ключ устройства, который отправило устройство на сервис. Дальше можно проверить, что само устройство обладает собственным приватным ключом.

Общий алгоритм выглядит так.

  • (once) random root private key;
  • factory: random device private key;
  • factory: sign(root private key, device public key) = signature_1;
  • device->service: отправляет device public key + signature_1;
  • service: verify(root public key, signature_1, device public key)?

Результат второй попытки

Мы решили проблему с доставкой до клиента — информация зашивается на производстве, и восстанавливать ничего не надо.

Весь ключ занимает 33 байта. Важно, что мы решили проблему с доставкой «секретов» до сервисов верхнего уровня, потому что все, что нужно хранить на сервисе — это публичный ключ производителя. С их помощью и математической магии можно дальше провести handshake-соединение и проверить, что устройство обладает соответствующим приватным ключом.

На сервере мы храним только ключ производителя (root public key).

Также у нас нет защиты от копирования реквизитов. Синхронизация между сервисами и интранета у нас нет, о чем мы уже говорили.

Устройство отправило приватный ключ, а мы проверили, что это мы его сделали и выдали, и проверили, что устройство им владеет. Единственное, о чем мы забыли, так это об аутентификации. Но мы не знаем, что это за устройство, а мы их тысячи производим.

Поэтому мы применили трюк, который называется «Сертификат».

Аутентификация и сертификаты

На этом шаге во всю математическую магию с подписями и их проверками мы добавляем дополнительную информацию — сертификат. Для этого подпишем на фабрике не только публичный ключ (device public key), а ключ с дополнительной информацией.

Дополнительная информация в нашем случае.

  • Дата производства и производитель.
  • Модель и аппаратная конфигурация.
  • Серийный номер, по которому можно аутентифицировать устройство.
  • Опции: аппаратные и программные. Разные комплектации физически могут ничем не отличаться друг от друга, но сертификат будет содержать данные о том, за что заплатил клиент.
  • Имя клиента и номер счета.

Всю эту информацию вместе с публичным ключом мы будем подписывать своим ключом производителя — root public key. После этого информация попадет на сервисы и они смогут удостовериться, что она правильная. Поскольку это сервисы наши и наших партнеров, нам они доверяют.

Статус по целям

Информация также зашивается на производстве, а доставка до сервисов не нужна. На сервере храним только ключ производителя.

Всю информацию из сертификатов зашиваем во флеш-память устройства. Восстановление при потере. Даже сама подпись не секретна — там есть публичный ключ и подпись нашим ключом. Теоретически ее можно случайно или намеренно удалить, но в этой информации в сертификате нет ничего секретного. Единственный секрет в сертификате — объемы продаж устройств с разными опциями.

Клиенты редко специально стирают служебную область памяти. Сертификат можно хранить на фабрике и высылать клиенту, если он его потерял. Обычно это делаем мы во время процедуры восстановления устройства: пришло устройство от клиента, оно полностью пропускается через инициализацию, все стирается, загружается заново, а сертификат копируется из заводской базы.

У нас нет восстановления при потере, защиты от копирования и синхронизации между сервисами.

Нам понятно, что это за устройство — мы знаем производителя, модель и серийный номер, что ему можно, а что нельзя. На этапе аутентификации мы получаем и проверяем сертификат.

Авторизация

Сертификат позволяет хранить информацию для авторизации.

Зная серийный номер устройства, можно давать доступ всем. Бесплатный сервис производителя. В своих сервисах мы даем доступ всем нашим базовым клиентам.

Для сервиса наших партнеров можно завести таблицу с белым списком серийных номеров: «Клиент Василий купил у нас два контроллера с такими-то серийниками, которые привязаны к его аккаунту» Белые списки серийных номеров.

Можно заранее что-то продать, а потом разрешать или запрещать доступ на основе опций, которые указаны в сертификате — контроллер с лицензией на систему X. Лицензии.

Все работает исключительно на информации от контроллера которая подписана нами, как производителем, когда он аутентифицирует в системе. Никакой общей базы между сервисами, производителем или производителем систем нет.

Промежуточный сертификат

Еще одна техническая задача, которую мы решали по дороге. В схеме, про которую я сейчас рассказал, есть корневой сертификат производителя — root private key. Он физически нужен каждый раз, когда вы создаете устройство. Но если устройств много, то к этому ключу нужен постоянный доступ для ограниченного круга лиц. Это плохо, потому что если его потерять, то придётся обновлять публичные ключи на всех сервисах, а к злоумышленникам он попасть не должен. Это большие организационные проблемы. Но есть решение.

Вводим промежуточные ключи на партию устройств, которые не так страшно потерять.

Мы сделали так же, только цепочка длиннее.

Физически это «флешка», которая на день выдается бригадиру на производстве. Сертификатом производителя подписываем промежуточный ключ. В середине схемы мы добавили промежуточный сертификат, в остальном ничего не менялось. Аппаратными средствами ограничено число устройств, которые может подписать ключ.

Защищённое хранилище ключей

Во всем этом нам не хватает защиты приватного ключа устройства — это все еще файл, который лежит на флешке. Злоумышленник может его скопировать, но скорее всего его потеряют или случайно откроют доступ.

В идеальном случае приватный ключ устройства хорошо бы защитить от копирования — положить его в черный ящик.

Черный ящик выполняет 4 операции:

  • внутри себя генерирует ключ по запросу, но не отдает;
  • отдает публичный ключ;
  • подписывает сообщение;
  • проверяет подпись.


Для проверки подписи нужен только публичный ключ, поэтому достаточно трех операций.

Есть несколько вариантов, лучший из которых — специальный криптопроцессор внутри SoC или в виде отдельного чипа. В моем понимании это должно быть аппаратное решение, желательно, отдельное от процессора.

Проблема в том, что он реализован программными способами в Boot ROM процессора. Первый вариант черного ящика, который мы рассматривали — это модуль CAAM в процессорах NXP i.mx 6, 7, 8, которые мы используем.

Пару лет назад в этом модуле нашли дыру, которая позволяла обходить проверку подписи при загрузке прошивки. В нем могут быть баги, которые можно найти и даже эксплуатировать через другую функциональность процессора. Другая проблема — процессоры с этим модулем тяжело ввозить в Россию, бумажки требуют заполнять. Это не та функциональность, которая нужна нам, но осадок остался.

Признаюсь честно, я рассчитывал на то, что если мы не сможем привезти его в Россию, то что-нибудь придумаем — чип маленький, стоит 1 доллар. Поэтому мы взяли отдельный чип. Но все получилось удачно — нашли чип Microchip ATECC, у которого все бумажки уже есть.

Microchip ATECC608A

Это отдельная маленькая микросхема, которая стоит копейки. Чип подключается по I2C — две «ножки» процессора, которые вы можете поделить еще и с другой периферией. У чипа стандартная распиновка. Мы использовали чип в первых версиях оборудования и просто паяли его поверх другой микросхемы с таким же протоколом и распиновкой, потому что она стандартная.

Чип умеет то, что нам нужно от такой микросхемы: считать подписи, хранить ключи и многое другое.

Характеристики:

  • 16 слотов для ключей;
  • умеет считать подписи ECSDSA, хеши, MAC, и шифровать AES, умеет DH;
  • имеет генератор случайных чисел и криптографические счётчики;
  • корпуса: SOIC-8, DFN6;
  • протоколы: I2C, single wire;
  • ~0.7$@1000pcs.

Как работать с микросхемой

К нему есть приличная документация, но под NDA. Если вы напишете сразу в gamma.spb.ru, то вам дадут её через 2 недели. Если в другую компанию — через 3 месяца. Мы написали в две компании, и когда уже все сделали, нам ответил другой дилер Microchip.

Есть софт на GitHub — библиотека с HAL. Аппнотов мало и они хуже среднего. Софт не поддерживает Linux, а поддерживает Raspberry Pi и МК от Atmel — это немного не то. Это забавно — документация под NDA, а софт, который по ней написан, на GitHub. Разработчики считают, что на всем оборудовании есть только одна I2C шина, например, ножки называются как на Raspberry Pi.

Нет примеров под Linux и нет работы с персонализацией. Есть интеграция с OpenSSL — плохо работает, но есть.

Персонализация чипа

Персонализация — это самая большая головная боль с чипом.

Проблема в том, что чип умеет очень много всего. У него есть 16 слотов, в которых хранится 16 ключей: пользовательские данные, или публичные ключи, или временные хранилища для других слотов — много вариантов.

К слотам надо как-то ограничивать доступ, и там тоже много конфигурационных вариантов: ограничить по паролю, по аутентификации в другом слоте, по времени обращения на фабрики.


В таблице тип ключа, доступ на чтение и запись, отношения между слотами — SlotConfig, KeyConfig.

В битовой маске (по 16 бит) каждого ключа, который мы используем, везде разные числа.

Мы испортили 50 чипов, прежде чем все сделали правильно. Самое грустное, что конфигурационная зона одноразовая, которая устанавливает функции слотов. Отдельно есть блокировка отдельных слотов Чип работает только после блокирования конфигурации.

Есть документация на отдельные биты, но там все сложно. Документации нет ни в примерах, ни в софте. Во всех примерах от Microchip написано: «Такой блок загрузите, и у вас как-то будет работать как в примере отправки данных в Amazon».

На это ушло много времени, но в процессе сделали классную утилиту.

Утилита atecc-util

Это консольная утилита, которая умеет выполнять большинство функций чипа и позволяет работать чуть проще. Она есть на GitHub под MIT-лицензией.

Она умеет дружественнее работать с конфиг-зоной, умеет работать с SHA, MAC, ECDSA, DH. Утилита использует CryptoAuthLib. То, что ее может вызвать человек — побочная фича. Интерфейс дружественный к batch, потому что мы создавали утилиту для использования в скриптах, в первую очередь. Утилитой можно составить список — план команд: «Сначала персонализируй эту зону, потом запиши такой ключ».

Пример вызова утилиты достаточно человекочитаемый.

atecc - b 10 - c 'serial' - c 'read-config /tmp/config.dump'

Утилита собрана под Linux, под AMD64 — есть в Debian-пакете.

Другие инструменты персонализации

У нас есть Excel-табличка, чтобы считать биты. Если вы покажете нам скан NDA c Microchip, мы вам ее отдадим.

Тесты проверяют реальное устройство. Мы все покрыли тестами, поскольку много вариантов, когда можно забыть один бит, и ваш приватный ключ прочитает какая-нибудь служебная команда. Они обращаются к микросхеме и проверяют правильность конфигурации на устройстве: можно ли этот слот можно прочитать, можно ли сделать такую подпись?

Используем фреймворк bats — очень интересная штука. Параллельно с битами мы создали список гарантий, которым должно удовлетворять это устройство, и проверяли, как все работает. Выглядит это так.

Верхние пройдены, а нижние нет.
Список тестов для примера.

Настройки в устройствах

Для себя мы используем всего два слота для задачи, о которой я сейчас рассказываю. В обоих мы храним приватный ключ устройства. Разница в том, что с первым связан постоянный сертификат, который выписан в 1970 году на 200 лет.

Инфраструктура сертификатов предполагает проверку срока валидности сертификата. Это сделано из-за того, что в IoT время не всегда синхронизованное. Если синхронизация на устройствах сломана, то какой-нибудь жизненно важный сервис может отказать, например, VPN.

Он генерируется однократно и не меняется на протяжении жизни устройства. Поэтому один слот бесконечный — постоянный. Для этого ключа генерируется сертификат на 200 лет — для закрытых сетей.

Максимальный срок жизни сертификатов — год. Другой слот обновляется. Приватный обновляемый ключ устройства генерируется по мере истечения срока валидности сертификата устройства. Это сделано на всякий случай, если что-то будет скомпрометировано. Используется для аутентификации в открытых сетях, обновляется раз в месяц или реже, вместе с сертификатом.

Пользователи могут сгенерировать свой ключ в отдельном слоте, если не доверяют нашему приватному ключу. Для пользователей мы сгенерировали разные комбинации, включая несколько слотов для приватных ECDSA ключей. Пользователи могут считать подписи, сделать шифрование — мы отдали все, что умеет микросхема. Для этого нужно доверять только Microchip.

Пока, к сожалению, никто не использовал, но мы надеемся на это.

Инфраструктура: промежуточные ключи

Я уже говорил, что в какой-то момент мы внедрили промежуточные сертификаты, чтобы не светить корневым сертификатом, который нельзя терять. Он никогда не появляется на фабрике.

От 608 отличается незначительно, но в 508 есть функциональность, которая пригодилась для ключей, а в 608 её уже нет. Физически промежуточные сертификаты — это чип ATECC508A.

Это USBISP с прошивкой tiny-usb-i2c — программатор, который можно перепрошить в USB-I2C бридж. Чип подключается через USB-I2C переходник. Промежуточные сертификаты подписывают своим приватным ключом сертификаты устройств.

Для нас оказались полезны две возможности микросхемы.

Микросхему можно запрограммировать, чтобы она считала подпись только при выполнении двух условий: Аппаратная защита паролем слота.

  • когда устройство воткнули в компьютер;
  • введен пароль.

Бригадиру на производство мы выдаем промежуточный ключ и пароль на какое-то количество контроллеров. Соответственно, надо украсть и ключ, и пароль, чтобы получить доступ. Эту возможность мы получили бесплатно, но она повышает безопасность системы.

Криптографический счетчик внутри может только увеличиваться. Аппаратное ограничение на количество использований. Когда он достигает заранее заданного один раз предела, микросхема больше ничего не подписывает.

OpenSSL на клиенте

Рассмотрим как все работает на клиенте. На контроллере у нас OpenSSL. Мы не стали ничего изобретать — это обычный TLS, обычный PKI. Нам дополнительно понадобилась клиентская библиотека. В подавляющем большинстве софта Linux она используется для защищенного соединения.

1. Мы взяли код от Microchip, его немножко дописали, поддержали свежий OpenSSL
1. В итоге он умеет работать с аппаратным ключом — аппаратно поддерживает пароли для приватных ключей.

Выглядит это примерно так.

openssl req -new -engine ateccx08 -keyform engine -key ATECCx08:00:04:C0:00 -subj "/CN=wirenboard-AP6V5MDG" -out device AP6V5MDG.csr

Это вызов обычного OpenSSL и указание использовать соответствующий модуль engine. Здесь задается ключ: адрес, модель, а последние два байта — это номер слота, который используется. Все передается так, будто это файл ключа, но это не файл — надо зайти в устройство.

SSL на сервере

На сервере работает любой SSL, в том числе OpenSSL. Никаких доработок и нестандартных сборок на серверной части уже не нужно. Все, что нужно на сервере, это уметь проверять цепочку certificate bundle (device cert + intermediate cert), и хранить наш публичный ключ, который мы опубликовали на сайте — Wiren Board ROOT CA.

В теории клиент — наш контроллер — аутентифицирует и сервер. Стандартный TLS говорит о том, что обе стороны должны аутентифицировать друг друга. Это достается бесплатно — в том самом handshake.

Её можно сделать самоподписанной, и тогда на все клиенты можно раздать публичный ключ. Для этого у сервера тоже должна быть ключевая пара: приватный и публичный ключ. Можно использовать letsencrypt или сертификат в SSL, как на сайтах, чтобы домен был в браузере зеленым.

В трех сервисах мы это сейчас сделали, первый из них — MQTT.

MQTT: mosquitto на клиенте

Это стандартная и популярная шина для передачи данных от IBM. У нас она используется для связи контроллеров с нашим облаком и с некоторыми партнерскими системами.

Нам пришлось его пропатчить, чтобы использовать OpenSSL engine (передать одну опцию) и парсить опцию «keyfile», чтобы указывать там аппаратный ключ. Mosquitto — это распространенная реализация брокера и клиентских библиотек, в том числе, под Linux. Патчи на клиент маленькие, по 20 строк.

Дальше клиент передает страшный bundle.

После этого используется аппаратный приватный ключ и проверяется сертификат сервера в другую сторону.

mosquitto_sub -h mqtt.wirenboard.com -p 8884 -cert /etc/ssl/device/device_bundle.crt.pem --key 'engine:ateccx08:ATECCx08:00:04:C0:00' --capath /etc/ssl/certs/ -t /# -v

Здесь сначала идет консольная утилита. Дальше указан сертификат устройства — он начинается с -cert. Сертификат идет bundle-файлом — метаинформация. Приватный ключ идет после сертификата --key. За ключом нужно идти в аппаратное хранилище.

Мы его проверяем по общемировому списку SSL-ключей, потому что у нас letsencrypt. Последняя часть, которая начинается с --capath, это проверка нашего сервера.

Так выглядит настройка бриджа.

root@wirenboard-AXXVJI62:~# cat /etc/mosquitto/conf.d/bridge-hw.conf connection wb_devices_cloud.wirenboard-AXXVJI62 address contactless.ru:8884 bridge_capath /etc/ssl/certs/
bridge_certfile /etc/ssl/device/device_bundle.crt.pem bridge_keyfile engine:ateccx08:ATECCx08:00:04:C0:00 notifications true
notification_topic /client/wirenboard-AXXVJI62/bridge_status topic/# both 1 ""/dient/wirenboard-AXXVJI62

Mosquito-бридж также настраивается и передаются данные.

На сервере стандартный Mosquitto — ничего патчить не надо.

per _listener_settings true listener 8884 0.0.0.0
cafile/etc/mosquitto/certs/WirenBoard_Root_CA.crt certfile /etc/letsencrypt/live/contactless.ru/fullchain.pem keyfile/etc/letsencrypt/live/contactless.ru/privkey.pem require.certificate true use_identity_as_username true password_file /etc/mosquitto/passwd.conf allow_anonymous false
acl_file /etc/mosquitto/ad.conf :~$ cat /etc/mosquitto/acl.conf
pattern write /client/%u/#
pattern read /client/%u/#

Вся настройка — несколько шагов.

  • Зашиваем Root CA и letsencrypt-сертификаты от домена — прописать в настройках. Дальше указываем команду проверять сертификаты.
  • Дальше классная опция Mosquitto. Она позволяет без всяких допиливаний использовать метаинформацию сертификата в качестве username для дальнейших листов доступа к MQTT.
  • После того, как клиент отправил свой сертификат, например, с серийником (CN) wirenboard-AXXVJI62, у нас написано, к каким подтопикам разрешать доступ клиенту.
  • per_listener_settings: на отдельном порту, чтобы не мешать аутентификации по логину/паролю (>1.5.5).

Это вся настройка MQTT-брокера нашего Wiren Board IoT Cloud Platform.

OpenVPN

OpenVPN нам нужен, чтобы ходить к клиентам на контроллер, когда они все себе сломали. Для этого нужно, чтобы он поднимался по одному клику из настроечного интерфейса и нам давался доступ к клиентскому устройству.

Дальше в опции запуска добавляется то же, что и выше: bundle, проверка сервера, engine. Для OpenVPN на клиенте тоже нужен патч, но он простой.

openvpn --capath /etc/ssl/certs/ --cert /etc/ssl/device/device_bundle.crt.pem --key engine:ateccx08:ATECCx08:00:04:C0:00

На сервере мы также используем letsencrypt.

ca /etc/openvpn/WirenBoard_Root_CA.crt cert
/etc/letsencrypt/live/vpn1.wirenboard.com/fullchain.pem key
/etc/letsencrypt/live/vpn1.wirenboard.com/privkey.pem

Развернуть другой сервер легко — не надо передавать никакие файлы на контроллеры. Это все подписано по стандартной эко-системе публичных ключей.

Nginx

Наша заключительная фича. Nginx сделан для партнеров, у которых сложный сервис, или если не хочется прикручивать проверку клиентских сертификатов, SSL. Часто у них уже стоит nginx перед сложным сервисом на web-сервере, как reverse-proxy. Если нет — ставится одной строчкой в конфиге nginx.

Если всё ОК, то выставляет хедеры перед передачей запроса ниже: Common Name, разрешено ли клиенту использовать этот сервис, заплатил ли он за него при покупке контроллера. nginx проверяет клиентский сертификат, отдает HTTP-запрос, а дальше своему бэкенду или сложному сервису. Если не ОК, то ошибка 400.

ssl_client_certificate WirenBoard_Root_CA.crt; ssl_verify_client on;

nginx на клиенте. У нас есть агенты — приложения, которые отправляют данные по HTTP. На Linux-контроллерах мы используем nginx на клиенте, чтобы агенты тоже ничего не знали о SSL, наших аппаратных ключах, работу с OpenSSL.

Все настраивается в 10 строчек. Дальше можно обычным wget без ключей, bash или вашим любимым языком, завернуть любой HTTP-запрос в TLS с аппаратным ключом.

server { listen 8080; location / { proxy_pass https://example.com; proxy_ssl_name example.com; proxy_ssl_server_name on; proxy_ssl_certificate/etc/ssl/device/device_bundle.crt.pem; proxy_ssl_certificate_key
engine:ateccx08;ATECCx08:00:04:C0:00; }
}

Где посмотреть

Криптомодуль есть во всех контроллерах Wiren Board 6, которые выпускаем уже полтора года. В инфраструктуре уже был задел, но развернули и настроили все только недавно.

Также мы подняли среду Grafana с InfluxDB, в которой все работает по MQTT. У нас это работает для удаленного доступа к web-интерфейсу контроллера на cloud.wirenboard.com для OpenVPN для контроллера. Можете посмотреть в системе saymon.info — это система мониторинга (MQTT) наших партнеров.

Поделимся инструкциями — поможем. Если вы производитель систем верхнего уровня, делаете что-то для себя, или хотите поднять удаленный доступ, Grafana, MQTT-брокер, как у нас, то пишите, звоните.

Спасибо им! Всю работу, о которой я рассказал, выполняли два человека: Олег Сериков — настройка OpenSSL на клиентах и серверах, и Никита Маслов — всё остальное.

Подписывайтесь на YouTube-канал с остальными лучшими докладами с конференции 2019 года. Это была статья на основе одного из лучших докладов конференции InoThings Conf 2019. В чате участники задают вопросы, делятся наработками, опытом и обсуждают свежие материалы по IoT. Также вступайте в канал и чат в Telegram.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть