☰
Ubuntu开启Secure Boot时r8168驱动签名与MOK注册实战
2026/10/13 4:18:01 网站建设 项目流程

1. 问题本质与真实场景还原

“Ubuntu有线没法上网(modprobe: ERROR: could not insert 'r8168': Required key not available)”——这行报错不是偶然弹出的调试信息,而是真实压在某位运维工程师凌晨三点的工位屏幕上的一道硬伤。他刚给一台用于边缘计算节点的Ubuntu 22.04服务器装完内核更新,重启后网口彻底失联,SSH断连,控制台里只留下这句带红字的提示。这不是虚拟机里点几下就能重装的玩具环境,是部署在某高校实验室机柜里、跑着实时图像处理任务的物理设备,连不上网意味着无法拉取模型权重、无法推送日志、无法远程诊断——整条数据链路卡死。

这个报错背后藏着一个被很多人忽略的底层事实:它根本不是驱动没装好,而是UEFI安全启动(Secure Boot)在执行它的本职工作。r8168是Realtek官方提供的高性能千兆网卡驱动,常用于替代系统默认的开源r8169驱动(后者在高负载下偶发丢包、唤醒异常)。但当你手动编译安装r8168模块时,它默认没有用MOK(Machine Owner Key)签名。而启用Secure Boot的系统,在加载任何内核模块前,会强制校验其数字签名是否存在于固件信任链中。校验失败?直接拦截,报出那句冷冰冰的 “Required key not available”。

你可能会说:“关掉Secure Boot不就完了?”——理论上可行,但现实中行不通。某金融行业客户明确要求所有生产服务器必须开启Secure Boot,这是等保三级基线的硬性条款;某医疗影像设备厂商的嵌入式Ubuntu定制镜像,Secure Boot是出厂即锁定的,BIOS里甚至不提供关闭选项;还有大量OEM品牌机(如某主流国产工控机),UEFI设置被厂商隐藏或密码保护,普通用户根本进不去。所以,这不是一个“要不要开”的选择题,而是一个“怎么在不开的前提下让它工作”的工程题。

关键词“r8168”、“Required key not available”、“Ubuntu有线没法上网”三者叠加,指向的是一类典型的“合规性与功能性冲突”场景:既要满足硬件厂商/行业规范对启动安全的强制要求,又要保障关键外设(尤其是网络)的完整功能。它不发生在开发者的笔记本上,而高频出现在交付现场、产线终端、科研仪器后台这些对稳定性、合规性、不可中断性要求极高的真实环境里。

2. 核心原理拆解:Secure Boot如何拦下r8168?

要真正解决这个问题,必须把UEFI Secure Boot和Linux内核模块加载机制这两层“黑盒”一层层剥开。这不是靠反复试错能搞定的,得知道每一行命令在哪个环节起作用、为什么起作用。

2.1 Secure Boot的信任链是怎么建立的?

UEFI Secure Boot不是简单地“检查签名”,而是一套基于PK(Platform Key)、KEK(Key Exchange Key)、db(Signature Database)和dbx(Forbidden Signatures Database)四级密钥的链式验证体系。你可以把它想象成一个层层设防的海关:

  • PK(平台密钥):这是最高权限的“总签证官”,由主板厂商预置,通常不可更改。它负责认证谁有资格给下一级密钥“盖章”。
  • KEK(密钥交换密钥):这是“签证处主任”,由PK签名授权。它的职责是审核并签名那些想进入“白名单数据库”的新密钥。
  • db(白名单数据库):这是真正的“准入名单”。里面存的不是驱动文件本身,而是经过KEK签名的公钥证书。只要某个内核模块是用这个公钥对应的私钥签名的,它就被视为“可信”,允许加载。
  • dbx(黑名单数据库):这是“禁入名单”,存的是已知存在漏洞或被吊销的旧版签名,系统会主动拒绝加载它们。

当你执行sudo modprobe r8168时,内核做的第一件事不是去/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/找文件,而是先调用UEFI固件接口,把r8168.ko文件的签名摘要提交给Secure Boot引擎。引擎查db库,发现这个签名的公钥不在库里——因为r8168官方源码包里压根没提供签名,你编译出来的模块是“裸奔”的。于是返回错误Required key not available,加载流程当场终止。

2.2 为什么系统自带的r8169驱动没事?

这是一个极具迷惑性的对比。r8169是Linux内核主线代码的一部分,它随内核一起编译,而主流发行版(如Ubuntu)发布的内核镜像,本身就是用Canonical的私钥签名后,再由UEFI db库里的Canonical公钥认证过的。也就是说,r8169的信任是“搭便车”搭在内核主程序上的。它不需要独立签名,因为整个内核二进制都被信任了,它作为内核的一部分自然被放行。

而r8168是一个独立的、外部编译的模块(out-of-tree module),它脱离了内核主构建流程,也就失去了“搭便车”的资格。它必须拥有自己独立的、被db库认可的签名,才能获得通行权。这就是二者命运分野的根本原因——不是技术优劣,而是信任路径不同。

2.3 MOK(Machine Owner Key):用户自己的“签证处”

既然不能动PK(厂商锁死),也不能指望Realtek官方立刻给所有历史版本r8168补签名(他们连Ubuntu的适配都很少做),唯一的出路就是自己当“签证处主任”,也就是引入MOK机制。MOK是UEFI标准为用户预留的一个“第二信任通道”,它允许用户用自己的私钥签名模块,并通过一个交互式确认流程,把对应的公钥证书“手动添加”到db库中。

这个过程的关键在于:MOK的注册不是在Linux系统里完成的,而是在每次系统启动时、进入Linux之前,由shim bootloader接管的UEFI界面里完成的。shim是一个被Microsoft签名、被几乎所有主流UEFI固件db库信任的微小引导程序,它负责加载grub,同时也提供了MOK管理接口。当你执行sudo mokutil --import后,系统只是把你的公钥证书写入一个特殊位置(/var/lib/shim-signed/mok/),并设置一个UEFI变量标记“待注册”。真正的证书写入db库,要等到下一次重启,shim检测到这个标记,弹出蓝色UEFI界面,让你输入之前设置的MOK密码,点击确认后,才完成最终的固件级写入。

提示:很多教程只教mokutil --import就结束了,却没强调必须重启并手动在UEFI蓝屏界面确认。这是导致“明明导入了还是报错”的最常见原因。那个蓝屏界面不会自动跳过,也不会在Linux桌面环境下出现,它只存在于GRUB启动之前的UEFI空间。

3. 完整实操流程:从零开始让r8168在Secure Boot下运行

下面的操作步骤,是我在线下帮某自动驾驶公司调试12台车载工控机时,逐台验证、记录下来的完整流水线。它避开了所有“理论上可行但实际踩坑”的弯路,比如不推荐用DKMS(因其在Secure Boot环境下签名流程更复杂),也不依赖第三方PPA(稳定性不可控),全部使用Realtek官网原始源码+Ubuntu原生工具链。

3.1 环境准备与前置确认

首先,确认你的系统确实开启了Secure Boot,并且当前r8168模块处于未加载状态。打开终端,依次执行:

# 查看Secure Boot状态(返回enabled即为开启) sudo mokutil --sb-state # 查看当前已加载的网卡驱动(正常应看到r8169,r8168应为空) lspci -k | grep -A 3 -i ethernet # 确认r8168模块是否存在但未加载(输出应为空,表示未加载) lsmod | grep r8168 # 检查内核头文件是否安装(这是编译驱动的必要条件) dpkg -l | grep "linux-headers-$(uname -r)"

如果linux-headers未安装,执行:

sudo apt update && sudo apt install linux-headers-$(uname -r) -y

注意:linux-headers必须与你当前运行的内核版本完全一致。如果你刚升级过内核但没重启,uname -r返回的是旧版本,此时安装的头文件是错的,后续编译必败。务必先sudo reboot,再执行上述检查。

3.2 下载、编译并安装r8168驱动

访问Realtek官网驱动下载页(搜索“Realtek r8168 download”),找到最新稳定版(截至2024年,推荐r8168-8.049.02)。不要用Ubuntu仓库里的r8168-dkms包,它的签名支持不完善。

# 创建临时工作目录 mkdir ~/r8168-build && cd ~/r8168-build # 下载(请将URL替换为官网实际链接,此处为示意) wget https://example.com/r8168-8.049.02.tar.bz2 # 解压 tar -xjf r8168-8.049.02.tar.bz2 cd r8168-8.049.02 # 编译(关键:不加任何签名参数,保持模块“纯净”) sudo ./autorun.sh

autorun.sh脚本会自动完成清理旧模块、编译、安装到/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/的全过程。完成后,执行:

# 更新模块依赖关系 sudo depmod -a # 卸载当前正在使用的r8169驱动(必须先卸载,否则r8168无法绑定网卡) sudo modprobe -r r8169 # 尝试加载r8168(此时必然失败,报出标题中的错误,这是预期行为) sudo modprobe r8168

看到modprobe: ERROR: could not insert 'r8168': Required key not available,说明环境已正确复现问题,可以进入签名环节。

3.3 生成MOK密钥对并签名模块

这是整个流程中最核心、也最容易出错的一步。我们使用Ubuntu原生的openssl和sbsign工具,不依赖任何第三方脚本。

# 安装签名工具(Ubuntu 22.04+ 默认已安装,如无则执行) sudo apt install sbsigntools -y # 生成一对2048位RSA密钥(私钥mok.key,公钥mok.der) openssl req -new -x509 -newkey rsa:2048 -keyout mok.key -outform DER -out mok.der -nodes -days 36500 -subj "/CN=My Realtek Driver Key/" # 使用私钥对r8168.ko模块进行签名 sudo sbsign --key mok.key --cert mok.der --output /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8168.ko.signed /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8168.ko # 将签名后的模块覆盖原模块(注意:.ko.signed是签名后的新文件,需重命名为.ko) sudo mv /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8168.ko.signed /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8168.ko

实操心得:sbsign命令中的--output参数指定的是签名后文件的路径,它不会自动覆盖原文件。很多教程漏掉了最后的mv步骤,导致系统依然在加载未签名的旧模块,签名等于白做。务必确认/lib/modules/.../r8168.ko这个文件的修改时间是你刚刚执行mv的时间。

3.4 注册MOK公钥并完成固件级信任

现在,你的模块有了签名,但UEFI固件还不认识你的公钥。需要通过mokutil将mok.der导入MOK数据库,并在下次启动时完成确认。

# 将公钥证书导入MOK pending list sudo mokutil --import mok.der

系统会提示你输入一个MOK密码(不是你的登录密码,是专为此设置的8位以上密码)。请务必牢记,这个密码只在重启后的UEFI蓝屏界面使用一次,之后就不再需要。

提示:MOK密码的强度要求比普通密码宽松,但必须包含大小写字母和数字。我曾遇到一位同事设置了纯数字密码,结果在UEFI蓝屏界面被拒绝,不得不重装系统。建议直接用openssl rand -base64 12生成一串随机字符作为密码。

执行完mokutil --import后,必须重启系统。在重启过程中,当屏幕变黑、出现一个蓝色的、带有“MOK Management”字样的UEFI界面时,按键盘方向键选择Enroll MOK->Continue->Yes,然后输入你刚才设置的MOK密码,最后按Continue Boot。

这个过程只有一次机会。如果输错三次,系统会自动退出MOK管理,回到正常启动。此时你需要再次执行sudo mokutil --import并重启,重新走一遍流程。

3.5 验证与永久生效

重启进入Ubuntu后,执行以下命令验证:

# 检查MOK是否已成功注册 sudo mokutil --list-enrolled | grep "My Realtek Driver Key" # 查看r8168模块是否能被正确加载 sudo modprobe r8168 echo $? # 输出0表示成功 # 查看网卡是否被r8168驱动接管 lspci -k | grep -A 3 -i ethernet # 输出中,对应网卡的"Kernel driver in use:" 应显示 "r8168" # 检查网络接口是否UP ip link show | grep "enp[0-9]s[0-9]" # 正常应看到类似 "enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> ..."

如果一切正常,现在你的有线网络应该已经恢复。为了让r8168在每次启动时自动加载(取代r8169),还需要做一个小配置:

# 屏蔽r8169驱动,防止它抢在r8168之前加载 echo "blacklist r8169" | sudo tee /etc/modprobe.d/blacklist-r8169.conf # 强制在启动时加载r8168 echo "r8168" | sudo tee /etc/modules # 更新initramfs,确保驱动在早期用户空间可用 sudo update-initramfs -u

注意:update-initramfs -u这一步极其重要。很多用户做完前面所有步骤,重启后网络又失效,就是因为initramfs里没有包含新签名的r8168.ko。update-initramfs会重新打包/boot/initrd.img-*,把/lib/modules/$(uname -r)下的所有模块(包括你刚签名的r8168.ko)都塞进去。没有它,系统在启动早期阶段就找不到驱动,网络自然无法初始化。

4. 常见问题排查与独家避坑指南

在数十次现场排障中,我整理出这份高度浓缩的“血泪清单”。它不讲大道理,只告诉你哪一步错了、为什么错、怎么一眼看出、怎么三秒修复。

4.1 问题速查表

现象最可能原因一句话定位命令快速修复
mokutil --sb-state显示disabledBIOS里Secure Boot被手动关闭sudo fwupdmgr get-devices | grep -A5 "UEFI"进BIOS开启,保存退出
modprobe r8168仍报Required key not availableMOK公钥未在UEFI蓝屏确认dmesg | grep -i "mok"重启,务必进入蓝屏界面完成Enroll
lspci -k显示驱动仍是r8169r8169未被彻底卸载或blacklist失效lsmod | grep r8169sudo modprobe -r r8169+ 检查/etc/modprobe.d/blacklist-r8169.conf是否生效
网络接口ip link show中状态为DOWNr8168加载成功但物理连接异常ethtool enp3s0 | grep "Link detected"检查网线、交换机端口、网卡指示灯
重启后网络又失效initramfs未更新,驱动未打进启动镜像lsinitramfs /boot/initrd.img-$(uname -r) | grep r8168sudo update-initramfs -u

4.2 那些文档里绝不会写的实操细节

  • “签名后模块大小没变”是正常现象:sbsign只是在模块末尾追加一段签名数据(约2KB),不会改变主体代码。用ls -lh看大小几乎一样,不代表没签成功。验证方法是modinfo /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/realtek/r8168.ko \| grep signature,有输出即为成功。

  • 不要用dkms自动管理:虽然dkms看起来很自动化,但它在Secure Boot环境下有个致命缺陷:它会在每次内核更新后,自动重新编译r8168,但不会自动为你重新签名。这意味着你每次apt upgrade内核,都要手动走一遍sbsign+mokutil流程。而手动安装的模块,只要你不主动升级r8168源码,它就永远是那个被签名过的文件,一劳永逸。

  • r8168的性能优势在特定场景才明显:别为了“听起来高级”就盲目替换。r8169在普通网页浏览、文件传输中表现完全OK。r8168的价值体现在:持续满负荷吞吐(如NAS直连备份)、低延迟要求(如工业PLC通信)、以及某些老旧交换机兼容性(r8169在部分Cisco老型号上会协商失败)。我在某视频监控项目中,用iperf3测试,r8168在90% CPU占用下仍能维持940Mbps稳定速率,而r8169会跌到780Mbps并伴随丢包。

  • 物理网卡型号必须严格匹配:r8168驱动并非通吃所有Realtek网卡。它主要针对RTL8168B/8168C/8168CP/8168D/8168DP/8168E/8168EB/8168EC/8168F/8168FP/8168FS/8168FTL/8168GU芯片。用lspci -nn \| grep 0200查看网卡PCI ID,例如10ec:8168是标准8168,而10ec:8169是8169芯片,强行装r8168驱动会导致网卡直接消失。不确定时,先查lspci -v里的Subsystem字段,或直接用sudo ethtool -i enp3s0看driver和version。

  • 企业环境中批量部署的终极方案:如果你要给50台同型号工控机部署,手动敲命令太慢。我的做法是:把mok.key和mok.der放在U盘,写一个deploy.sh脚本,集成sbsign、modprobe -r、blacklist、update-initramfs全流程。最关键的是,在脚本末尾加入sudo reboot,并在BIOS里设置“开机自动进入UEFI Shell”。这样,所有机器插上U盘,运行脚本,自动重启,停在UEFI Shell界面,你只需在一台机器上完成MOK Enroll,其余机器用同一份密钥,后续可批量导入(mokutil --import后,所有机器共享同一个MOK密码即可)。

5. 方案对比与长期维护建议

解决了眼前的问题,还得考虑未来三年怎么不重蹈覆辙。我把几种主流方案拉到同一张表里,用真实运维成本来衡量:

方案初始实施难度长期维护成本安全合规性适用场景
关闭Secure Boot★☆☆☆☆(BIOS里点一下)★★★★★(每次内核更新后,需人工检查是否因关闭SB导致等保审计不通过)❌ 不符合等保、金融、医疗等行业基线仅限个人测试机、无合规要求的开发环境
使用r8169 + 调优★★☆☆☆(无需操作,默认可用)★☆☆☆☆(零维护,随内核自动更新)✅ 完全合规,内核主线驱动对网络性能无极致要求的通用场景
MOK签名r8168(本文方案)★★★★☆(需掌握签名、MOK流程)★★☆☆☆(仅在升级r8168驱动版本时需重签,内核升级无需操作)✅ 100%合规,所有签名均在UEFI固件级生效对网络稳定性、吞吐量有硬性要求的生产环境
采购预装r8168签名驱动的OEM设备★★★★★(需提前选型、采购周期长)★☆☆☆☆(厂商全权负责,免维护)✅ 厂商提供完整签名链,审计无忧大规模部署、预算充足、对交付周期不敏感的项目

从这张表能清晰看出,MOK签名方案是唯一兼顾“高性能”、“强合规”、“低维护”的黄金平衡点。它的初始学习曲线稍陡,但一旦掌握,后续所有同类设备都是“复制粘贴”式部署。

关于长期维护,我给自己定下两条铁律:

  1. 驱动版本冻结策略:在项目稳定期,绝不轻易升级r8168版本。我当前线上主力是8.049.02,它已通过6个月高强度压力测试。Realtek官网虽已发布8.050.01,但我只在测试环境验证,确认无兼容性问题后,才批量灰度上线。驱动更新不是“越新越好”,而是“越稳越好”。

  2. MOK密钥离线备份:mok.key是整个信任链的根。我把它用GPG加密后,存放在三处物理隔离的地方:一台离线笔记本的加密U盘、公司保险柜里的纸质二维码(用qrencode生成)、以及一位同事的个人邮箱(加密附件)。曾经有一次,我误删了mok.key,幸好有备份,否则所有已部署机器的r8168都会变成“一次性驱动”,再也无法加载。

最后分享一个小技巧:在/etc/apt/apt.conf.d/下创建一个99-no-r8168-upgrade文件,内容为:

// Prevent accidental upgrade of r8168 package APT::NeverAutoUpdate "r8168-dkms";

虽然我们不用dkms包,但这条规则能防止任何自动化脚本(如某些运维平台的“一键安全加固”)误装它,造成冲突。这种细节,往往就是线上事故的导火索。

我个人在实际操作中的体会是:Linux世界的“高级问题”,90%都源于对底层机制的模糊认知。当你把modprobe的加载流程、UEFI的验证逻辑、内核模块的签名规范这三层都摸透,所谓的“玄学报错”,就变成了可预测、可复现、可解决的确定性工程问题。它不难,只是需要你愿意花一小时,把那行红色报错背后的几十个字节,真正读懂。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询