генерировать согласованный уникальный идентификатор машины

20

Можем ли мы сгенерировать уникальный идентификатор для каждого ПК, например, uuuidgen, но он никогда не изменится, если не произойдут аппаратные изменения? Я думал о слиянии CPUID и MACADDR и хешировании их для создания согласованного идентификатора, но я не знаю, как их анализировать с помощью скрипта bash, я знаю, как получить CPUID из

dmidecode -t 4 | grep ID

и

ifconfig | grep ether

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

Урай
источник
4
Какую именно проблему вы пытаетесь решить с помощью этого метода?
Darkhogg
1
Я с Дархоггом. Обычно плохая идея пытаться делать такие вещи в наши дни. Виртуализация сделала бессмысленной привязку программного обеспечения к физическому оборудованию. Обычно лучше найти ответ, если вы внимательно изучите свои требования (именно к этому стремится Даркхогг).
Calphool
4
Я не использовать это , чтобы связать программное обеспечение с машиной, это линукс добычи вышка , что необходимо идентифицировать себя управление облаком и службу мониторинга, вместо того , чтобы назвать тысячи установки вручную, мне нужно , чтобы однозначно идентифицировать их , используя их идентификатор оборудования
Урай
1
@ user77710: Если это так, то действительно ли ты заботишься об аппаратном обеспечении? Почему бы просто не сгенерировать UUID на машине, если она не существует. В этом смысл UUID - они универсально уникальны (шансы их перекрытия астрономически маловероятны). serverfault.com/questions/103359/how-to-create-a-uuid-in-bash
Calphool
1
@JoeRounceville - я не имел в виду, что сам SecureBoot был решением - хотя он поддерживает самозаверяющие сертификаты - но скорее его метод . Но он использует API, предлагаемый микропрограммой системы - и любая система UEFI будет иметь столько идентификаторов UUID, сколько вам может понадобиться для установки в имени каждой переменной микропрограммы - см. Мой ответ. Кроме того, вам не нужно никакого приложения - или bash- чтобы генерировать UUID на любом Linux. cat /proc/sys/kernel/random/uuid,
mikeserv

Ответы:

21

Как насчет этих двух:

$ sudo dmidecode -t 4 | grep ID | sed 's/.*ID://;s/ //g'
52060201FBFBEBBF
$ ifconfig | grep eth1 | awk '{print $NF}' | sed 's/://g'
0126c9da2c38

Затем вы можете объединить и хешировать их с помощью:

$ echo $(sudo dmidecode -t 4 | grep ID | sed 's/.*ID://;s/ //g') \
       $(ifconfig | grep eth1 | awk '{print $NF}' | sed 's/://g') | sha256sum 
59603d5e9957c23e7099c80bf137db19144cbb24efeeadfbd090f89a5f64041f  -

Чтобы удалить концевую черту, добавьте еще одну трубу:

$ echo $(sudo dmidecode -t 4 | grep ID | sed 's/.*ID://;s/ //g') \
       $(ifconfig | grep eth1 | awk '{print $NF}' | sed 's/://g') | sha256sum |
  awk '{print $1}'
59603d5e9957c23e7099c80bf137db19144cbb24efeeadfbd090f89a5f64041f

Как отмечает @mikeserv в своем ответе , имя интерфейса может измениться между загрузками. Это означает, что сегодня eth0 может быть eth1 завтра, поэтому, если вы будете использовать grep, eth0вы можете получить другой MAC-адрес при разных загрузках. Моя система не работает таким образом, поэтому я не могу на самом деле проверить, но возможные решения:

  1. Grep для HWaddrна выходеifconfig но сохраните их все, а не только тот, который соответствует конкретному NIC. Например, в моей системе у меня есть:

    $ ifconfig | grep HWaddr
    eth1      Link encap:Ethernet  HWaddr 00:24:a9:bd:2c:28  
    wlan0     Link encap:Ethernet  HWaddr c4:16:19:4f:ac:g5  

    Захватив оба MAC-адреса и пропустив их через sha256sum , вы сможете получить уникальное и стабильное имя, независимо от того, какой сетевой адаптер называется:

    $ echo $(sudo dmidecode -t 4 | grep ID | sed 's/.*ID://;s/ //g') \
         $(ifconfig | grep -oP 'HWaddr \K.*' | sed 's/://g') | sha256sum |
          awk '{print $1}'
    662f0036cba13c2ddcf11acebf087ebe1b5e4044603d534dab60d32813adc1a5    

    Обратите внимание, что хеш отличается от приведенных выше, потому что я передаю оба MAC-адреса, возвращенные ifconfig в sha256sum.

  2. Вместо этого создайте хэш на основе UUID вашего жесткого диска:

    $ blkid | grep -oP 'UUID="\K[^"]+' | sha256sum | awk '{print $1}'
    162296a587c45fbf807bb7e43bda08f84c56651737243eb4a1a32ae974d6d7f4
terdon
источник
это приятно, но как избавиться от замыкающего тире '-'?
Ура
@ user77710 см обновленный ответ.
Тердон
1
Я думаю, что cpuid хуже ... wikipedia.org/wiki/cpuid
mikeserv
@mikeserv ах, да, действительно, я понимаю твою точку зрения. Спасибо, ответ отредактирован.
Тердон
Создает один и тот же идентификатор для всех гостевых ОС на одном хосте.
Нитинкумар Амбекар
23

Во-первых, обратите внимание, что CPUID определенно не является общедоступным маркером однозначной идентификации для любой системы, более поздней, чем Intel Pentium III. Хотя хэширование его с MAC-адресами, безусловно, может привести к уникальным маркерам, это связано только с уникальными качествами самих MAC, и CPUID в этом случае является не чем иным, как косвенным. Более того, результирующий хеш, скорее всего, не будет более уникальным, чем UUID материнской платы, и его гораздо проще получить, а процесс менее подвержен ошибкам. Из wikipedia.org/wiki/cpuid :

EAX = 3 : серийный номер процессора

Смотрите также: Pentium III § Спор о проблемах конфиденциальности

Это возвращает серийный номер процессора. Серийный номер процессора был введен на Intel Pentium III, но из-за соображений конфиденциальности эта функция больше не реализована на более поздних моделях (бит функции PSN всегда сбрасывается). Процессоры Transmeta Efficeon и Crusoe также предоставляют эту функцию. Процессоры AMD, однако, не реализуют эту функцию ни в каких моделях процессоров.

Вы можете просмотреть разобранный процессор самостоятельно, выполнив cat /proc/cpuinfoили даже простоlscpu .

Я думаю, что вы получите все MAC-адреса для сетевых интерфейсов, распознаваемых ядром Linux:

ip a | sed '\|^ *link[^ ]* |!d;s|||;s| .*||'

Может возникнуть необходимость отфильтровать этот список, если он может включать виртуальные сети со случайно сгенерированными MAC-адресами. Вы можете сделать это с флагами в вызове ipнапрямую. Видетьip a help информацию о том, как это сделать.

Также обратите внимание, что эта проблема не является уникальной ipи должна также решаться, если вы используете ifconfig, но она может быть решена более надежно ip- которая является частью iproute2сетевого пакета и активно поддерживается - чем она может ifconfig- которая является членом из net-toolsпакета и последнего увидела Linux релиза в 2001 году . Из-за изменения функций в ядре с момента его последнего выпуска ifconfigизвестно, что в них неправильно указаны флаги сетевых функций, и его следует по возможности избегать.

Тем не менее, следует понимать, что фильтрация по именам интерфейсов ядра eth[0-9]не является надежным средством для этого, поскольку они могут меняться в зависимости от порядка их параллельного обнаружения udevво время процесса загрузки. Пожалуйста, смотрите Предсказуемые сетевые имена для более подробной информации.

Поскольку dmidecodeв моей системе не установлено, я сначала подумал о том, чтобы хэшировать список серий жестких дисков, сгенерированных как:

lsblk -nro SERIAL

Сделайте lsblk --helpнекоторые подсказки по уточнению этого списка - скажем, по типу диска. Также рассмотрите lspciи / илиlsusb возможно.

Объединить их легко:

{ ip a | sed ... ; lsblk ... ; } | #abbreviated... for brevity...
    tr -dc '[:alnum:]' | #deletes all chars not alphanumeric - including newlines
    sha256sum #gets your hash

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

Учитывая это, я снова заглянул в файловую систему и нашел /sys/class/dmi/idпапку. Я проверил несколько файлов:

cat ./board_serial ./product_serial

###OUTPUT###
To be filled by O.E.M.
To be filled by O.E.M.

Тем не менее, это, кажется, довольно хорошо, но я не буду публиковать вывод:

sudo cat /sys/class/dmi/id/product_uuid

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

dmidecode -s system-uuid

Более простой, тем не менее, вы можете просто прочитать файл. Обратите внимание, что этот конкретный файл специально определяет материнскую плату. Вот отрывок из исправления ядра 2007 года, в котором изначально был реализован этот экспорт в /sysfsвиртуальную файловую систему:

+DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor,      0444, DMI_BIOS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_version,         0444, DMI_BIOS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_date,        0444, DMI_BIOS_DATE);
+DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor,       0444, DMI_SYS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(product_name,         0444, DMI_PRODUCT_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(product_version,   0444, DMI_PRODUCT_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(product_serial,    0400, DMI_PRODUCT_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(product_uuid,         0400, DMI_PRODUCT_UUID);
+DEFINE_DMI_ATTR_WITH_SHOW(board_vendor,         0444, DMI_BOARD_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(board_name,       0444, DMI_BOARD_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(board_version,     0444, DMI_BOARD_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(board_serial,         0400, DMI_BOARD_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag,   0444, DMI_BOARD_ASSET_TAG);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor,    0444, DMI_CHASSIS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_type,         0444, DMI_CHASSIS_TYPE);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_version,   0444, DMI_CHASSIS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial,    0400, DMI_CHASSIS_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);

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

sudo sh <<\CMD | tr -dc '[:alnum:]' | sha256sum
        ip a | sed '\|^ *link[^ ]* |!d;s|||;s| .*||'
        cat /sys/class/dmi/id/product_uuid 
CMD

Ядро Linux также может генерировать UUID для вас:

cat /proc/sys/kernel/random/uuid #new random uuid each time file is read

Или:

cat /proc/sys/kernel/random/boot_id #randomly generated per boot

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

Наконец, в системах UEFI это становится гораздо проще сделать, поскольку каждая переменная среды встроенного ПО EFI включает в себя собственный UUID. Переменная окружения {Platform,}LangCodes-${UUID}должна присутствовать в каждой системе UEFI, должна сохраняться перезагрузка и даже большинство обновлений и модификаций прошивки, и любая система Linux с efivarfsзагруженным модулем может перечислять одно или оба имени так же просто, как:

printf '%s\n' /sys/firmware/efi/efivars/*LangCodes-*

Старая форма - LangCodes-${UUID}по-видимому, сейчас устарела , и на более новых системах должна быть, PlatformLangCodes-${UUID}но, согласно спецификации, одна или другая должна присутствовать в каждой системе UEFI. Без особых усилий вы можете определить свои собственные постоянные переменные перезагрузки и, возможно, более активно использовать генератор UUID ядра таким образом. Если интересно, загляните в efitools .

mikeserv
источник
на нем даже нет жесткого диска или диска, а также его майнинг-буфера, если вы не знаете, что это такое. diit.cz/sites/default/files/images/3988/… виртуальная машина не может запустить 6 GPU на одном материнская плата
урай
в любом случае, он никогда не должен использовать какое-либо случайное число, так как он превосходит цель последовательного именования машины, так как они загружаются, идентификатор не должен меняться
uray,
@ user77710 - Черт, чувак, это круто. Это одна машина? Возможно, вы правы, но это может быть возможно с некоторыми комбинациями XDMX и Chromium - некоторыми распределенными графическими материалами. Во всяком случае, это не имеет значения - у меня это было задом наперед. Кто хотел бы выбить себя из своих денег? Я думал о лицензировании программного обеспечения или о чем-то еще - вы делаете банковские счета.
mikeserv
Там есть несколько хитрых трюков, +1.
Тердон
@terdon - комплимент высоко ценится, но, по большей части, это не уловки. ip2специально разработан для анализа, и, возможно, я недостаточно хорошо это делаю - подозреваю, что то же самое можно сделать почти без него grep/sed. Вероятно, то же самое можно сделать так же легко с udevadm. И каждое имя переменной среды EFI предназначено для уникальной идентификации именно для таких ситуаций.
mikeserv
19

Многие современные дистрибутивы поставляют файл, /etc/machine-idсодержащий наиболее вероятно уникальную шестнадцатеричную 32-символьную строку. Он происходит из systemd, где на man-странице есть больше информации , и может подходить для ваших целей.

XZS
источник
+1, @XZS, вы также можете добавить соответствующую информацию из URL.
Рамеш
1
Это хорошо, и я нашел похожую информацию и почти использовал ее ... но я уже был привержен другому маршруту. Тем не менее, следует отметить, что это dbusспецифично, я думаю, и меняется, если операционная система стерта / переустановлена.
mikeserv
Это чертовски круто.
GeneCode
5

На многих машинах Linux файл /var/lib/dbus/machine-idсодержит уникальный идентификатор для каждого дистрибутива Linux и может быть доступен с помощью вызова dbus_get_local_machine_id(). Это, вероятно, то же самое, что /etc/machine-idупомянуто выше. Это работает и на виртуальных установках Linux. Я проверил это на текущих дистрибутивах Ubuntu, SuSE и CentOS.

rankeney
источник
1
В Fedora 19 + 20 этот файл не существует. Это здесь: /etc/machine-id.
SLM
Возможно, я не был достаточно ясен. Я хотел сказать, что если вы не найдете это в одном месте, посмотрите в другое. Или напишите свою собственную программу, используя вызов функции.
Рэнки
0

Вам нужен идентификатор машины, чтобы измениться, когда меняется оборудование? Используется ли идентификатор машины для защиты чего-либо? Я считаю, что лучший способ иметь «согласованный» идентификатор машины - это хранить случайную строку где-то в системе, и таким образом, если любое из аппаратных средств изменится, идентификатор машины также не изменится. Это также хорошо для виртуализированных систем, где доступ к оборудованию ограничен, а MAC-адрес - 00: 00: 00: 00.

Попробуйте что-то вроде этого скрипта sh, чтобы создать и получить ID:

#!/bin/sh
FILE="/etc/machine-id"

if [ ! -f $FILE ]; then
    cat /dev/urandom|tr -dc A-Z0-9|head -c32 > $FILE;
fi

cat $FILE;
ub3rst4r
источник
Так как вы в /dev/urandomлюбом случае указываете на Linux, вы можете просто сделать, cat /proc/sys/kernel/random/uuid >$FILEчто случайным образом генерирует правильно отформатированный UUID при каждом чтении. Тем не менее, любое сохраняемое на диске постоянство подлежит удалению, и, при условии, что это приемлемо и при условии dbusустановлено, вам, вероятно, следует поступить так, как предложил @XZS.
mikeserv
0

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

Некоторые люди могут вместо этого сохранить идентификатор сгенерированного идентификатора на своем жестком диске (или использовать UUID), но жесткие диски могут быть клонированы.

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

В таких случаях всегда немного легче, если вы дадите больше информации о том, чего хотите достичь.

jgmjgm
источник