Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр

Введение. Обзор существующих публикаций

В последнее время системные администраторы сталкиваются с задачей объединения разнородных операционных систем в сети предприятия. В частности, одной из проблем является применение серверов GNU/Linux совместно с рабочими станциями и серверами под управлением Windows различных версий.

Обычно сеть небольшого предприятия включает в себя около 20-30 рабочих станций с операционной системой Windows 7, контроллер домена на базе Windows Server 2008 R2, маршрутизатор и нескольких специализированных серверов. Дальше мы будем рассматривать включение таких серверов на базе GNU/Linux в домен Windows Server 2008 R2 и порядок работы с такими серверами.

В качестве первой задачи рассмотрим организацию файлового сервера Samba в домене Windows Server 2008 R2. Проблеме создания файловых серверов на основе Samba посвящено множество статей и публикаций на различных форумах. В качестве примера можно привести документацию по Samba, опубликованную на официальном сайте проекта

. Здесь приведены различные материалы, начиная со второго издания известной книги «Using Samba», написанной Джеем Ц (Jay Ts), Робертом Экштейном (Robert Eckstein) и Дэвидом Колльер-Брауном (David Collier-Brown) и выпущенной издательством O’Reilly & Associates.


Немалое количество дополнительной информации о работе Samba можно получить и на сайтах производителей основных дистрибутивов Linux.

Описание тестовой сети, домена Windows

Для организации тестовой сети мы будем использовать виртуальную среду VMware VSphere 5, реализованную на базе архитектуры гипервизора ESXi. Однако можно было бы воспользоваться и хорошо себя зарекомендовавшим Microsoft Hyper-V, а также любым другим аналогичным решением

Тестовая среда представляет собой, доменную сеть на базе Active Directory (Active Directory Domain Services – AD DS ), которая состоит из двух серверов инфраструктуры, работающих под управлением MS Windows Server 2008 R2 EE, и одной клиентской машины – MS Windows 7 Professional. Используются IP-адреса из подсети 192.168.7.0/24

Похожее:  Wi-Fi с логином и паролем для каждого пользователя или делаем WPA2-EAP/TLS подручными средствами / Хабр

Наименование домена – LAB.LOCAL Контроллер домена – LAB-DC1.lab.local Сервер Forefront Threat Management Gateway (TMG) 2022 – LAB-TMG.lab.local Клиент – LAB-CL1 .lab.localНа LAB-DC1 установлены роли

Требуемые пакеты для GNU/Linux

Все упомянутые ниже пакеты нужны для развертывания OpenLDAP, Kerberos и Samba на сервере, работающем под управлением Ubuntu Linux 10.04.4 LTS 64 с графической оболочкой Xfce. Также приводятся сведения о необходимых для установки предустановленных пакетах в соответствии с официальной документацией для OpenLDAP, Kerberos и Samba

Для сборки OpenLDAP необходимы следующие пакеты:

Необходимые пакеты можно установить командой sudo apt-get install имя_пакета.Так же потребуется Oracle Berkeley DB версий 4.4 – 4.8 или 5.0 – 5.1. О том, как собрать ее из исходников, мы расскажем чуть позже, когда будем говорить о сборке OpenLDAP.

Для сборки Kerberos нам понадобятся пакеты flex и bison(sudo apt-get install flex bison), иначе при сборке вы получите ошибку “yacc – command not found”. Затем нам понадобится g (sudo apt-get install g ), так как в противном случае Kerberos снова не соберется, сообщив, что “g — command not found.”

К моменту сборки Samba у нас уже должны быть установлены и OpenLDAP и Kerberos, в этом случае установка дополнительных пакетов не потребуется.Для установки пакетов gcc, g , flex, bison можно воспользоваться менеджерами пакетов, установленной на Вашем дистрибутиве GNU/Linux. Обычно нужно просто отметить эти пакеты при первоначальной установке системы.

Сборка пакетов из исходных текстов.

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

Сборка OpenLDAP

Сначала с сайта Oracle скачиваем source-файлы Berkeley DB(далее — BDB) с сайта Oracle.

Authentication methods


К счастью, в openssh начиная с версии 6.2 сделали нативную поддержку второго фактора. Теперь с помощью опции

AuthenticationMethods

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

lwn.net/Articles/544640

Пример подобной конфигурации:

AuthenticationMethods publickey,password hostbased,publickey


Что же здесь написано? Для успешной аутентификации нужно пройти одну из следующих комбинаций:

Но где подключить модуль для двухфакторной аутентификации? Он подключается в методе keyboard-interactive. То есть если вы хотите, чтобы после аутентификации через publickey требовалось подтверждение через тот же модуль google auth, то задаете в конфиге sshd следующее:

AuthenticationMethods publickey,keyboard-interactive

а в файле

pam.d/sshd

указываете:

auth required pam_google_authenticator.so

Все довольно просто. Но ровно до тех пор, пока вы не захотите включить несколько методов аутентификации, при этом если один метод выполняется на уровне самого sshd (publickey или kerberos), а другой — на уровне pam (тот же password). Проблема заключается в том, что и password и keyboard-interactive обрабатываются в одном и том же pam-конфиге. Нужно как-то научиться отделять первую стадию аутентификации от второй в случае такого конфига sshd:

AuthenticationMethods password,keyboard-interactive publickey,keyboard-interactive

Microchip atecc608a

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

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

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

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

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


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

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

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

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

Nginx

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

Openssl на клиенте

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

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

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

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

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

Openvpn

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

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

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

На сервере

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

Pam_p11


Данный модуль позволяет осуществить двухфакторную аутентификацию пользователей по смарт-картам или USB-токенам с помощью ассиметричной криптографии. Рассмотрим общую схему его работы:

Аутентификация происходит следующим образом:

  1. На токене выполняется поиск сертификата пользователя
  2. Через PAM производится запрос PIN-кода к токену
  3. Если аутентификация на токене прошла успешно, то производится подпись случайных данных с помощью закрытого ключа с токена. Сама подпись выполняется аппаратно.
  4. Полученная ЭЦП проверяется с помощью сертификата пользователя

Если в итоге проверка подписи осуществлена успешно, то модуль говорит наружу, что все хорошо.


В данной схеме используются ключевая пара RSA длины 2048 бит, сгенерированная аппаратно на токене.

Ssl на сервере

На сервере работает любой SSL, в том числе OpenSSL. Никаких доработок и нестандартных сборок на серверной части уже не нужно. Все, что нужно на сервере, это

уметь проверять цепочку certificate bundle

(device cert intermediate cert), и 

хранить наш публичный ключ

, который мы опубликовали на сайте — Wiren Board ROOT CA.

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

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

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

Авторизация

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

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

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

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

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

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


На этом шаге во всю математическую магию с подписями и их проверками мы добавляем

дополнительную информацию — сертификат

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

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

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

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

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


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

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

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

Проверка публичного ключа. Создаем себе еще один публичный ключ. Он будет нашим ключом, как производителя. Это корневой ключ «root private key public key». Этим корневым секретным ключом на производстве подпишем публичный ключ устройства (device public 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)?

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

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

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

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

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

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


Единственное, что мы решили таким способом — это то, что

больше не храним на своих сервисах общие «секреты»

в открытом или закэшированном виде. Это не то, что нам хочется.

Варианты настройки

Как я и говорил, тема 2fa для linux очень популярна, есть много решений, которые позволяют это сделать.

Существует два принципиальных способа сделать второй фактор при аутентификации через ssh. Первый способ — псевдо-второй фактор, запуск произвольного бинарника после стадии авторизации через опцию ForceCommand в настройках sshd:

Второй фактор через pam

Классический сценарий представляет собой модификацию конфига

/etc/pam.d/sshd

, когда в самое начало помещают нужный модуль примерно в таком формате:

auth required pam_google_authenticator.so

Но это не решает проблему, если аутентификация выполняется не на уровне pam’а, а выполняется средствами самого sshd-сервера, например аутентификация по ключам. Как же быть в таком случае?

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


Криптомодуль есть во всех контроллерах

Wiren Board 6

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

Для рутокен эцп

При установке новой версии opensc потребовалось удовлетворить зависимости пакетов. Для этого были взяты следующие пакеты из репозитория Debian squeeze:

Доработка напильником


Но пути назад нет, поэтому начинаем читать исходники.

Основной файл, в котором идут все проверки:

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

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

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

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

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр
Список тестов для примера. Верхние пройдены, а нижние нет.

Задачи и цели

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

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

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

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

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

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

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

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

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

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

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

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

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

Занесение сертификата в список доверенных


На данном этапе нам осталось только прочитать с токена сертификат с нужным ID и записать его в файл доверенных сертификатов:

$ mkdir ~/.eid
$ chmod 0755 ~/.eid
$ pkcs15-tool -r <certificate_id> > ~/.eid/authorized_certificates
$ chmod 0644 ~/.eid/authorized_certificates

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

Во всем этом нам не хватает

защиты приватного ключа устройства

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

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

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

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

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / ХабрДля проверки подписи нужен только публичный ключ, поэтому достаточно трех операций.

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

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

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

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

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

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

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

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

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

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

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


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

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

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

К нему есть приличная

документация

Конфигурация pam

Если приложению требуется аутентификация, то оно должно создать файл со своим именем в каталоге /etc/pam.d, в котором должны быть указаны модули, с помощью которых производится аутентификация и прочие действия. Посмотрим, что лежит в каталоге /etc/pam.d в Ubuntu 11.10

Модуль pam и его зависимости

Для осуществления аутентификации по токену были установлены пакеты:

Настройка pam_p11

К счастью, нам не почти не придется править конфиги руками. Достаточно только создать файл /usr/share/pam-configs/p11 со следующим содержанием:

Name: Pam_p11 
Default: yes 
Priority: 800 
Auth-Type: Primary 
Auth: sufficient pam_p11_opensc.so /usr/lib/opensc-pkcs11.so


Интерес предоставляет последняя строчка конфига, в которой мы указываем тип модуля, имя библиотеки и параметры, передаваемые модулю. Наш модуль принимает в качестве параметра путь к библиотеке PKCS#11.

Теперь нам осталось только выполнить команду

$ pam-auth-update

В появившемся диалоге необходимо выбрать pam_p11. Если вы хотите отключить аутентификацию по паролям, то можно отключить Unix authentication. Поскольку в конфигурационном файле профиля было указано, что модуль будет «sufficient», то при получении от нашего модуля ответа «PAM_SUCCESS» весь процесс аутентификации будет считаться успешным.

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр

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

Для себя мы используем всего два слота

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

постоянный сертификат

, который выписан в 1970 году на 200 лет.

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

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

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

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

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

Немного истории

В старые добрые времена если приложению в Linux требовалось запросить аутентификацию пользователя, то ему приходилось обращаться к файлам /etc/passwd и /etc/shadow. Такой подход был прост как пробка, но при этом разработчикам приходилось думать не только о работе с файлами, но и о вопросах безопасности.

Решением тому стал проект Linux-PAM. К слову сказать, сама архитектура PAM была впервые предложена компанией Sun в октябре 1995 года, а в августе 1996 года инфраструктура Linux-PAM была включена в дистрибутив Red Hat Linux. В настоящее время существуют три основных реализации PAM:

  1. Linux-PAM – основная реализация архитектуры PAM, рассматривается нами в этой статье
  2. OpenPAM – альтернативная реализация PAM, используемая в BSD-системах и Mac OS X
  3. Java PAM – Java-обертка над Linux-PAM

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

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


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

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

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр
В таблице тип ключа, доступ на чтение и запись, отношения между слотами — SlotConfig, KeyConfig.

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

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

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

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

Практическое использование

В качестве подопытного дистрибутива можно было бы взять свежую Ubuntu, но учитывая то, что в 12.04 все слишком хорошо работает, мы решили с пользой для общего дела настроить аутентификацию в релизе «Смоленск» операционной системы Astra Linux Special Edition по USB-токенам Рутокен ЭЦП и Рутокен S.

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр

Проблемы

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

Кратко вся работа выглядит так: датчики разных параметров, исполнительные устройства, счетчики и контроллеры (edge-computing или IoT-gateway) собирают разные данные с объектов, обрабатывают их, исполняют локальную логику, а потом собираются в одной большой системе диспетчеризации, мониторинга или управления.

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

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

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

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

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

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

Разработка модуля аутентификации для pam

В этом разделе мы разберем исходный код модуля pam_p11 и рассмотрим основные моменты, которым стоит уделить внимание при написании своего собственного модуля.

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


Мы решили проблему с 

доставкой

до клиента — информация зашивается на производстве, и 

восстанавливать ничего не надо

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

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

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

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

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

Собственно разработка модуля

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

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

Для работы с PAM необходимо определить специальные константы, а только затем подключить заголовочные файлы:

#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define PAM_SM_PASSWORD
#include <security/pam_appl.h>
#include <security/pam_modules.h>

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


Приступим к написанию функции pam_sm_authenticate. Она имеет следующую сигнатуру:

PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv);

Из важных параметров тут стоит отметить:

Функция должна вернуть одно из следующих значений:

Внутри нашего модуля мы будем пользоваться библиотекой libp11 для работы с API PKCS#11 и OpenSSL для работы с сертификатами.


Первым делом определим переменные, которые нам потребуются:

Создание ключа и сертификата

Для начала создаем ключевую пару RSA длины 2048 бит c ID «45» (id стоит запомнить, он понадобится при создании сертификата).

$ pkcs15-init --generate-key rsa/2048 --auth-id 02 --id 45
 <вводим PIN пользователя>

Проверим сгенерированный ключ:

$ pkcs15-tool --list-keys
Using reader with a card: Aktiv Rutoken ECP 00 00 
Private RSA Key [Private Key] 
Object Flags : [0x3], private, modifiable 
Usage : [0x4], sign Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local
ModLength : 2048 
Key ref : 1 (0x1) 
Native : yes 
Path : 3f001000100060020001 
Auth ID : 02 
ID : 45


Теперь с помощью OpenSSL создадим самоподписанный сертификат. Запускаем openssl и подгружаем модуль поддержки pkcs11:

$ openssl
OpenSSL> engine dynamic -pre SO_PATH:/usr/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:opensc-pkcs11.so
(dynamic) Dynamic engine loading support
[Success]: SO_PATH:/usr/lib/engines/engine_pkcs11.so
[Success]: ID:pkcs11
[Success]: LIST_ADD:1
[Success]: LOAD
Loaded: (pkcs11) pkcs11 engine

Создаем сертификат в PEM-формате:

OpenSSL> req -engine pkcs11 -new -key 1:45 -keyform engine -x509 -out cert.pem –text

В последней команде 1:45 — это пара :. Таким образом, мы создали сертификат на базе ключевой пары, хранящейся на токене. При этом в текущем каталоге должен создаться файл сертификата с именем cert.pem.

Теперь сохраним сертификат на токен:

$ pkcs15-init --store-certificate cert.pem --auth-id 02 --id 45 --format pem 
<Вводим PIN пользователя>

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


Информация также зашивается на производстве, а 

доставка

до сервисов не нужна.

На сервере

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

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

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

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

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

Структура pam


Для начала разберемся, что же такое «Модуль PAM». Модули представляют собой библиотеки, в которых прописаны обработчики операций, которые может направлять к ним сам PAM. Для примера, стандартный модуль pam_unix умеет следующее:

Ниже представлена общая схема работы PAM

Разработка и применение модуля PAM для аутентификации в Astra Linux с использованием Рутокен ЭЦП и Рутокен S / Хабр

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

  1. Приложение инициализирует библиотеку PAM (libpam.so)
  2. PAM в соответствии с конфигурационным файлом для приложения обращается к требуемым модулям
  3. Модули выполняют возложенные на них действия
  4. Приложению возвращается результат операции


Конечно, PAM позволяет проводить не только аутентификацию. Функции PAM классифицируются по типу модулей. В скобках указаны обозначения модулей в конфигурационных файлах:

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

Установка дополнительных пакетов

Для начала пришлось установить некоторые пакеты. Для работы Рутокен S необходима старая версия OpenSC: 0.11.13, а для работы Рутокен ЭЦП – более новая: 0.12.2. В качестве middleware для обоих токенов используется OpenCT версии 0.6.20.


В итоге были поставлены пакеты, переданные разработчиками дистрибутива:

Утилита atecc-util

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

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

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

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

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

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

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

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

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

Эксперименты с настройкой pam

Тут мы снова вспоминаем, что же такое стэк pam, и с какими опциями можно подключать модуль. Все помнят стандартные варианты подключения в секции auth — required, requisite, sufficient, optional.

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

И тогда мы начинаем настраивать pam более тонко. Для каждого результирующего статуса можно указывать своё влияние на стэк, в т.ч. «пропускать» один или несколько подключаемых модулей.

Например, вот таким образом.

auth     [success=1 default=ignore]     pam_radius_auth.so

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

PAM_ABORT

. То есть аутентификация начинает выглядеть так:

AuthenticationMethods gssapi-with-mic,keyboard-interactive password,keyboard-interactive


А конфиг pam.d/sshd становится вот таким:

auth	[success=2 abort=ignore default=1] /lib64/security/pam_duo.so
auth   	[success=1 default=ignore]          	pam_unix.so nullok_secure
auth   	requisite                                            	pam_deny.so
auth   	required                                                pam_permit.so

Рассмотрим, что происходит в первом варианте возможной аутентификации — gssapi-with-mic,keyboard-interactive

Заключение

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

Описанные шаги по настройке системы аутентификации можно использовать как инструкцию в любом современном дистрибутиве Linux.

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

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