生成一致的机器唯一ID


20

我们能否为每台PC生成唯一的ID,例如uuuidgen,但是除非进行硬件更改,否则它永远不会改变?我当时正在考虑合并CPUID和MACADDR并对其进行哈希处理以生成一致的ID,但是我不知道如何使用bash脚本解析它们,我知道如何从中获取CPUID

dmidecode -t 4 | grep ID

ifconfig | grep ether

那么我需要组合这些十六进制字符串,并使用sha1或md5对其进行散列以创建固定长度的十六进制字符串。
如何解析该输出?


4
您尝试使用此方法解决的问题到底是什么?
Darkhogg 2014年

1
我和Darkhogg在一起。在当今时代尝试做这类事情通常是一个坏主意。虚拟化使得将软件绑定到物理硬件的实践毫无意义。如果仔细检查您的需求(这就是Darkhogg追求的目标),通常会有更好的答案。
Calphool 2014年

4
我不使用此软件将软件绑定到计算机,而是Linux采矿设备需要向云控制和监视服务标识自己,而不是手动命名数千个设备,而是需要使用其硬件ID来唯一标识它们
uray

1
@ user77710:如果是这种情况,那么您真的真的在乎硬件吗?如果不存在,为什么不在计算机上仅生成一个UUID。这就是UUID的意义所在-它们是普遍唯一的(从天文学角度来看,它们重叠的可能性很小)。 serverfault.com/questions/103359/how-to-create-a-uuid-in-bash
Calphool 2014年

1
@JoeRounceville-我并不是说SecureBoot本身就是解决方案-尽管它确实支持自签名证书-而是它的方法。但是它使用系统固件提供的API- 任何UEFI系统都将具有每个固件变量名称中已经设置的尽可能多的UUID-请参阅我的答案。另外,您不需要任何应用程序-或bash-在任何Linux上生成UUID。cat /proc/sys/kernel/random/uuid
mikeserv

Answers:


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,无论哪个NIC被称为什么,您都应该能够获得一个唯一且稳定的名称:

    $ 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    

    请注意,该哈希值与上面的哈希值有所不同,因为我正在传递返回ifconfig到的两个MAC地址sha256sum

  2. 而是根据您的硬盘驱动器的UUID创建哈希:

    $ blkid | grep -oP 'UUID="\K[^"]+' | sha256sum | awk '{print $1}'
    162296a587c45fbf807bb7e43bda08f84c56651737243eb4a1a32ae974d6d7f4

很好,但是如何消除尾随的破折号'-'?
uray 2014年

@ user77710查看更新的答案。
terdon

1
我想cpuid会更糟... wikipedia.org/wiki/cpuid
mikeserv

@mikeserv啊,是的,我明白你的意思。谢谢,答案已编辑。
terdon

为同一主机上的所有来宾OS生成相同的ID。
Nitinkumar Ambekar

23

首先,请注意,对于英特尔Pentium III之后的任何系统,CPUID绝对不是通常可访问的唯一标识标记。虽然用MAC地址对其进行哈希处理肯定会导致唯一的标记,但这仅是由于MAC本身的唯一性质,在这种情况下,CPUID只是偶然的。而且,所产生的哈希值不可能比主板的UUID唯一,并且更容易检索,并且该过程不太容易出错。从wikipedia.org/wiki/cpuid

EAX = 3:处理器序列号

另请参阅:Pentium III§关于隐私问题的争议

这将返回处理器的序列号。处理器序列号是在Intel Pentium III上引入的,但是出于隐私方面的考虑,此功能不再在以后的型号中实现(始终清除PSN功能位)。Transmeta的Efficeon和Crusoe处理器也提供此功能。但是,AMD CPU在任何CPU型号中均未实现此功能。

您可以自己查看,cat /proc/cpuinfo甚至可以查看已解析的cpuid lscpu

我认为这将为您提供Linux内核识别的网络接口的所有MAC地址:

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

如果列表可能包含带有随机生成的MAC的虚拟网卡,则可能有必要对其进行过滤。您可以在ip直接调用中使用标记来执行此操作。请参阅ip a help以获取有关如何执行此操作的信息。

另请注意,此问题不是唯一的ip问题,如果使用也必须解决ifconfig,但与作为成员的-相比,它可以更可靠地进行处理ip-它是iproute2网络套件的一部分,并且正在积极维护- ifconfignet-tools软件包的最后一次发行是在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

如您所知,您正在将用户的资源最终锁定为他们的唯一ID,并且不能依赖于硬盘的存在,所以我想改变一下策略。

考虑到这一点,我再次查看了文件系统并找到了该/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

当然,它是随机生成的,你将不得不重新考虑ID分配,但它是一样容易,因为它得到获得至少。如果您能找到对其进行加密的方法,它应该非常可靠。

最后,在UEFI系统上,这变得容易得多-因为每个EFI固件环境变量都包含其自己的UUID。环境变量{Platform,}LangCodes-${UUID}应该出现在每个UEFI系统上,应该持续重新启动,甚至包括大多数固件升级和修改,并且任何装有efivarfs模块的Linux系统都可以列出一个或两个名称,就像:

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

LangCodes-${UUID}显然已经弃用了较旧的格式- 在较新的系统上应保留该格式,PlatformLangCodes-${UUID}但根据规范,每个UEFI系统中应存在一个或另一个。您可以毫不费力地定义自己的重新引导持久性变量,并以这种方式更多地使用内核的UUID生成器。如果有兴趣,请查看efitools


它甚至没有硬盘或任何磁盘在运行,其采矿设备,如果您不知道它是什么,请参阅此diit.cz/sites/default/files/images/3988/…虚拟机无法在单个虚拟机上运行6个GPU主板
uray

无论如何,它永远不应该使用任何随机数,因为它打破了一致命名机器的目的,因为它们启动ID时不应更改
uray 2014年

@ user77710-ang,伙计,那很酷。那是一台机器吗?也许您是对的,但是使用XDMX和Chromium的组合可能是可能的-一些分布式图形工具。无论如何,没关系-我倒退了。谁愿意用自己的钱打败自己?我在想一些软件许可之类的东西-您正在开设银行帐户。
mikeserv

他们是您到达那里的一些绝妙技巧,+ 1。
terdon

@terdon-对此表示赞赏,但在大多数情况下,它们并不是技巧。ip2是专门为要解析而设计的,可能是我做得不够好-我怀疑几乎没有可以完成相同的操作grep/sed。可能可以轻松完成相同的操作udevadm。每个EFI环境变量名称都旨在针对此类情况进行唯一标识。
mikeserv

19

许多现代发行版都提供了一个文件,/etc/machine-id其中包含一个最可能是唯一的十六进制32个字符的字符串。它起源于systemd,在其中联机帮助页上有更多信息,并且可能适合您的目的。


+ 1,@ XZS,您也可以在此处从URL添加相关信息。
拉梅什2014年

1
很好,我发现了类似的信息并几乎使用了它……但是我已经致力于另一条路。不过,应该注意的是dbus,我认为这是特定的,如果擦除/重新安装操作系统,这会有所更改。
mikeserv

这真是太棒了。
GeneCode

5

在许多Linux机器上,该文件/var/lib/dbus/machine-id包含每个Linux发行版的唯一ID,可以通过调用来访问dbus_get_local_machine_id()。这可能与/etc/machine-id上面提到的相同。它也适用于虚拟Linux安装。我已经在当前的Ubuntu,SuSE和CentOS发行版上进行了检查。


1
在Fedora 19 + 20中,该文件不存在。在这里:/etc/machine-id
slm

也许我还不够清楚。我的意思是,如果您找不到一个地方,那就去另一个地方。或使用函数调用编写自己的程序。
rankeney 2014年

0

硬件更改时是否需要更改计算机ID?机器ID是否用于保护某些东西?我认为拥有“一致”机器ID的最好方法是在系统上的某个位置存储一个随机字符串,这样,如果任何硬件发生变化,那么机器ID也不会改变。这对于限制硬件访问且MAC ID为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;

因为/dev/urandom无论如何您都表示Linux,所以您可以这样做cat /proc/sys/kernel/random/uuid >$FILE,它会在每次读取时随机生成格式正确的UUID。但是,任何磁盘实现的持久性都将被删除,并且,如果可以接受并dbus已安装,则可能应该按照@XZS的建议执行操作。
mikeserv

0

其他答案给出了从硬件中提取ID的多种方法。您可以决定使用一件或多件硬件作为标识符。如果您需要任意更换或更换硬件,则这是有问题的。

某些人可能会将ID和生成的ID存储在他们的硬盘驱动器上(或使用UUID),但可以克隆硬盘。

TPM模块和安全启动可能会提供一种将主板和其他硬件绑定到硬盘上的方法。

如果您提供有关要完成的工作的更多信息,在这些情况下总是比较容易。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.