Portal:MicroOS/RemoteAttestation
Remote Attestation with Keylime
可信计算是一个很大的主题,涵盖多种技术,它们都使用单个硬件作为信任根:名为TPM(Trusted Platform Module)的加密协处理器。
一旦你获得它的所有权,它将生成一个无法提取(通过通常方式)的私钥,该私钥可用于生成新的辅助密钥、签署一些哈希值和加密一些文档。
如今运行的几乎所有系统都包含TPM设备。它们价格低廉,并且通常适用于多种架构。如果你的设备比较旧,那么很可能有一个版本为1.2的TPM。目前此版本不受支持,因为版本2.0已经可用近6年(2015年)。
TPM通常默认禁用,但可以从EFI / BIOS菜单中启用。在该菜单中,还有清除所有内部数据的选项,使所有由TPM生成的密钥失效,并随后使所有已签名的文档失效。因此请谨慎使用此选项。
Measured boot
如果我们已经启用了TPM 2.0,我们还可以开始使用它来检查启动链是否以任何形式被篡改。此过程称为measured boot。启动过程的每个步骤将根据内存(或磁盘)上下一阶段的内容计算哈希值,并将此哈希值注册到TPM内部的一些内部寄存器中。
这些寄存器被称为PCR,典型的TPM有24个,旨在存储哈希值。SHA1或SHA512等哈希函数具有不同的尺寸,TPM可以同时启用多个哈希函数。这使得对于每个PCR,我们将拥有多个插槽(bank)或相同寄存器的变体,每个哈希函数一个。例如,如果我们启用了TPM中的SHA1和SHA256哈希值,则PCR#1将有两个版本,一个为20字节,另一个为32字节。
重启后,PCR加载了已知的良好值,通常所有为0或所有为1,具体取决于寄存器。我们无法将特定值写入这些寄存器,但可以使用extend操作来更新内容。PCR的扩展定义为“PCR <- HASH(PCR_VALUE || DIGEST)”。例如,如果我们要使用给定的摘要值扩展PCR#1的SHA1插槽,我们需要将它与PCR的当前值前缀,并计算聚合的SHA1。
每次进行扩展时,摘要值都会存储在日志中,最终会到达内核并可供用户使用。此日志(名为event log)可用于重现PCR的预期值。现在我们可以要求TPM报告PCR的实际值(称为quote),并将它们与计算出的值进行比较。
由于quote由TPM拥有的私钥签名,我们可以确定这些是PCR的当前值。如果重新计算的值与TPM的quote匹配,我们也可以确定event log中列出的哈希值是扩展期间使用的哈希值。
我们可以将此事实用于将这些哈希值与来自不同来源的良好哈希值列表进行比较。此event log将包含一个用于固件(EFI)的哈希值,另一个用于引导加载程序,另一个用于内核等。现在我们可以将它们全部与我们拥有的良好哈希值列表进行比较。
我们可以本地进行比较,但如果我们将event log和TPM quote发送到拥有良好哈希值列表的远程机器进行比较,则效果更好。此过程称为远程证明。
正如我们稍后将看到的那样,通过远程证明,你可以验证比measured boot哈希值更多的元素。一个进程可以将任何生成的文档的签名委托给TPM,从而提供关于系统的任何类型的度量或任何其他信息。由于这种签名,我们可以
- 确保发送者是生成文档的系统。
- 文档在原始系统中没有被更改或篡改,也没有被任何拦截通信的代理篡改。
有了这些保证,我们可以发送有关已执行程序的信息以及内核的IMA组件生成的这些二进制文件的哈希值。
如果在启动过程中系统找到TPM设备,它将开始执行measured boot。生活在系统中的一些静态代码将从UEFI固件加载一些段,并生成一个用于扩展一些PCR寄存器的摘要。此扩展将通过事件通知,并以我们稍后可以检查的方式进行注册。之后,此组件将委托执行给UEFI固件,该固件将对链中的下一个组件执行相同的操作,直到到达内核。
Grub2可以帮助我们通过扩展寄存器8和9来收集更多数据,这些寄存器将解释Grub2命令行、内核命令行或Grub2在加载过程中读取的不同文件(如内核和initrd)。有关详细信息,请查看Grub2 documentation。
要激活此功能,我们应该将/boot/efi/EFI/opensuse中的grub.efi替换为存储在/usr/share/grub2/x86_64-efi中的版本,并将其命名为grub-tpm.efi。我们可以使用以下命令自动执行此操作:
shim-install --suse-enable-tpm
Installing Keylime
Keylime是一个开源项目,旨在帮助我们进行远程证明。它目前通过两个新的系统角色集成到openSUSE MicroOS中。
- MicroOS with Remote Attestation (Agent)
- MicroOS with Remote Attestation (Verifier)
所有将参与远程证明的系统都需要使用Agent系统角色进行安装,而将进行验证的系统将使用Verifier系统角色进行安装。
或者,我们可以通过容器安装服务(有关指示,请参阅后面的Notes部分)。控制平面容器在不想安装任何Python依赖项的情况下很有用,而Rust Keylime agent中不存在此问题。
系统角色将负责安装所有必需的软件,但无法检查当前是否有可用的TPM 2.0协处理器。
我们可以使用以下命令检查:
dmesg | grep TPM
如果未找到,请查看UEFI菜单中的选项。如果你找到TPM 1.2,你可以检查制造商是否有固件升级到2.0。
最终,你的系统中将有两个设备:/dev/tpm0和/dev/tpmrm0。
后者设备/dev/tpmrm0是内核实现的资源管理设备。需要资源管理,因为TPM是一个非常受限的处理器,当多个进程同时尝试访问它时需要一些帮助。
还有一个用户空间资源管理器已安装,独立于内核资源管理器,可以通过dbus访问,并作为Keylime依赖项安装。这是TPM访问代理和资源管理守护程序(abrmd),它位于tpm2-abrmd.service中,该服务通过DBus自动激活。
我们可以使用以下命令检查所有内容是否正常工作:
# Generate random numbers tpm2_getrandom --hex 10 systemctl status tpm2-abrmd.service
在任何时候,我们都可以从命令行检查PCR寄存器:
tpm2_pcrread
我们可以通过读取event log来检查不同的扩展及其原因:
tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
这些命令在我们需要从新安装的系统中提取良好的PCR值时很有用。
Keylime verifier
我们应该首先设置verifier,以便agent可以连接到它。
在启动verifier和registrar服务之前,我们应该检查/usr/etc/keylime/*.conf中的配置文件。软件包中部署的配置文件对于verifier和registrar角色来说应该没问题,如果有需要更改,我们可以在/etc/keylime/verifier.conf.d/或/etc/keylime/registrar.conf.d/中添加片段。有关完整示例,请查看Keylime agent的下一部分,我们将创建一个片段来更改默认配置(同时注意文件和目录的所有权和权限)。
现在我们可以激活verifier和registrar服务:
systemctl enable --now keylime_verifier.service
systemctl enable --now keylime_registrar.service
verifier需要创建一些证书,第一次创建,registrar将在这些证书不可用时失败。
Keylime agent
对于我们网络中的每个系统,我们将使用Agent系统角色进行安装。此角色将安装所有IMA / EVM基础设施、TPM / TSS工具和Keylime agent服务。
MicroOS中有两个不同的Keylime agent。一个是传统的Python keylime-agent子包。这是agent服务的参考实现。它维护良好且受支持,但需要在可以使用它之前安装所有Python堆栈。
第二个agent是rust-keylime。这是用Rust实现的,占用的空间更小,并且将来将成为参考实现。对于MicroOS,我们决定将此版本设置为默认版本,因为今天它功能相当完整,具有更少的内存和磁盘占用空间以及更好的安全模型。
/usr/etc/keylime/agent.conf中的默认配置,在keylime:tss用户和组下,在启动服务之前我们需要进行一些调整。
为此,我们将在/etc/keylime/agent.conf.d/中添加一个新的配置片段,其中仅包含对软件包分发的默认配置的更改。由于我们使用的是Rust agent,我们需要执行以下操作:
mkdir -p /etc/keylime/agent.conf.d cat << EOF > /etc/keylime/agent.conf.d/agent.conf [agent] uuid = "d111ec46-34d8-41af-ad56-d560bc97b2e8" registrar_ip = "<REMOTE_IP>" EOF chown -R keylime:tss /etc/keylime chmod -R 600 /etc/keylime
uuid默认值为“generate”,因此每次执行agent时都会生成一个新的UUID。我们可以通过调用uuidgen来生成我们的agent ID来获得更多控制权。
我们还需要更改<REMOTE_IP>并设置安装registrar和verifier的地址(但保留引号),并且由于仍然使用zmq协议,因此设置revocation_notification_ip。
如果出于某种原因我们正在使用Python agent,则片段应该类似,但请注意引号的区别。
mkdir -p /etc/keylime/agent.conf.d cat << EOF > /etc/keylime/agent.conf.d/agent.conf [agent] registrar_ip = <REMOTE_IP> revocation_notification_ip = <REMOTE_IP> EOF chown -R keylime:tss /etc/keylime chmod -R 600 /etc/keylime
Python agent默认情况下将基于hostname生成ID,但如果需要,我们也可以在片段中添加此参数。
此外,从Keylime 6.3.0开始,我们需要将CA生成的证书复制到agent节点。此证书用于验证mTLS连接,以确保它来自正确的控制平面。
# From the agent node mkdir -p /var/lib/keylime/cv_ca scp <REMOTE_IP>:/var/lib/keylime/cv_ca/cacert.crt /var/lib/keylime/cv_ca chown -R keylime:tss /var/lib/keylime/cv_ca
Agent系统角色将安装一个新的服务,即keylime-agent,需要启用并启动该服务。
systemctl enable --now keylime_agent.service
agent将联系register服务,以通信证书和agent的UUID。
openSUSE 的 MicroOS 包正在配置代理程序在系统用户 "keylime" 下运行。与 systemd 服务关联的是一个挂载单元,它将在同一个用户下挂载 "/var/lib/keylime/secure"。这将在 "keylime_agent.service" 之前激活,并且在代理服务停止后仍将保持活动(已挂载)状态。
systemctl status var-lib-keylime-secure.mount
注册
在开始发送有关系统本身的信息之前,需要注册并接受代理程序。这可以通过一个类似工具(keylime_tenant)来完成,该工具位于验证器节点中。
要注册新的代理程序,请将 <AGENT> 替换为代理程序地址,将 <UUID> 替换为代理程序 UUID,使用此命令行
keylime_tenant -v 127.0.0.1 \
-t <AGENT> \
-u <UUID> \
--cert default \
-c add
UUID 可以直接在 keylime.conf 配置文件中设置(agent_uuid 字段),也可以从系统日志中检查。
journalctl -u keylime_agent.service | grep "Agent UUID:"
要列出成功注册的系统,我们需要使用 reglist 命令
keylime_tenant -v 127.0.0.1 \
--cert default \
-c reglist
我们可以通过将最后一行替换为 -c delete 来删除已注册的机器,并且可以使用 --tpm_policy 参数来监控 PCR 的值,该参数需要一个 JSON 字符串。
...
--tpm_policy '{\
"5":["223DD8701C16AC430BDDB1B409792AE6002121E4",\
"2B23381030DEF370AF781B143A25761F03A1D27F44922695D32EC74A96595576"],\
"6":["B2A83B0EBF2F8374299A5B2BDFC31EA955AD7236",\
"3D458CFE55CC03EA1F443F1562BEEC8DF51C75E14A9FCF9A7234A13F198E7969"]}'
这可用于引用参与度量启动过程的 PCR 寄存器,例如。
为了方便起见,此策略可以添加到 keylime 配置文件中。
Keylime 还可以验证事件日志,并根据事件日志重新创建 PCR 的预期值,并将其与当前值进行比较。
为此,我们需要创建一个空的度量启动参考状态(Keylime 正在使此过程更加明确),并使用 --mb_refstate 参数。
echo "{}" > empty_mb_refstate.json
...
--mb_refstate empty_mb_refstate.json
有效载荷
Keylime 可以在识别和验证代理程序后向其传递机密数据。这些数据可以是密钥证书或需要在系统中部署的密码,例如。
在注册过程中,我们可以添加参数 --include 以引用一个 ZIP 文件,该文件将被加密并发送到代理程序,并在那里解压缩和执行。
ZIP 文件需要包含一个 shell 脚本 autorun.sh,该脚本仅在设备经过验证后才会执行。如果使用 Python Keylime 代理程序,此有效载荷还可以包含一些 Python 脚本,这些脚本将在检测到安全漏洞时执行。Rust 代理程序可以编译以提供对这些 Python 代理程序的一些支持,但 MicroOS 分发的版本配置为没有此功能。
有关更多信息,请参考 Keylime 文档
启用 IMA 跟踪
IMA/EVM 是另一个复杂的主题,在 openSUSE wiki 的 IMA/EVM 页面中进行了深入描述。
使用 IMA,我们可以在读取或执行文件之前计算文件的哈希值。此哈希值与插入到该文件的扩展属性中的哈希值进行比较,如果相同,系统将授权访问。仅凭这一点是不够的,EVM 用于签名存储在扩展属性中的稀疏哈希值,并保证它不会被第三方更改。
当系统处于评估模式时,会发生此授权。但是还有其他执行模式,在这种模式下,内核可以调整文件的扩展属性以修复注册的 IMA 哈希值,以及另一种模式,在这种模式下,哈希值被计算并记录到事件日志中。
当可用 TPM 时,每个 IMA 测量都会扩展一个 PCR 寄存器(通常是 PCR#10)。TPM 的引用和日志也可以发送到远程验证器,以证明比较。
使用 Keylime,我们可以执行 IMA 哈希值的此远程证明,并由系统中 TPM 提供的安全性支持。有关更多信息,请参考 Keylime 文档。
要在我们的系统中启用 IMA 测量,我们有两种选择。一种是启用代理程序中的默认内核策略,可以通过在内核命令行中添加参数 ima_appraise=log ima_policy=tcb 来完成。
可以通过更新 /etc/default/grub 中的 GRUB_CMDLINE_LINUX_DEFAULT 并重新生成 grub.cfg 来持久化此设置。
transactional-update grub.cfg reboot
此示例使用 tcb IMA 策略,该策略包含在内核中。不幸的是,此默认策略非常基础,并且会测量我们系统的大部分内容,包括在日常使用期间经常更改的部分。
建议创建一个新策略以避免过多的日志和对太多文件的监控。
第二种选择是使用在启用 SELinux 且文件使用 SELinux 类型标记的系统上的 keylime-ima-package 包提供的策略。此策略尝试最小化从安全角度来看与测量系统无关的部分,并且可以通过从 /etc/ima/ima-policy 进行更改来调整,因为这是 systemd 在启动时查找策略的位置。
我们可以在代理程序注册期间使用 --allowlist 参数指定预期的哈希值,并使用 --exclude 参数指定排除或忽略的文件,或者使用 Keylime 支持的新运行时策略参数。
一些 IMA 文档也建议使用 rootflags=i_version 以避免重新创建已计算的哈希值,但此参数似乎会在启动过程中导致问题。
演示
为了更好地理解 Keylime,我们可以进行一个小演示,该演示将练习一些主要组件,这些组件可以在规划部署时使用。此演示是 Keylime 文档 中描述的用于安全有效载荷的演示的扩展版本,只是它也显示了与 IMA、度量启动和 TPM 策略的集成。
一般来说,我们将看到
- 如何提取 IMA 哈希值并配置 Grub2
- 如何创建经过认证的有效载荷
- 如何生成撤销并隔离被入侵的节点
但首先,我们需要分配三个具有 TPM / vTPM 的节点。如果我们有 libvirt,我们需要安装 TPM 模拟器 swtpm,并在安装操作系统之前将 TPM 添加为额外的硬件。
其中一个节点将使用验证器系统角色安装,另外两个将使用代理系统角色安装。有关详细信息,请参阅前面的部分,只需记住在代理程序的配置文件中设置远程验证器的 IP 地址。
提取 IMA 哈希值
Linux 内核的默认 IMA 策略会测量很多文件,这将产生很多噪音和误报。建议设置自己的策略(有关详细信息,请查看 openSUSE wiki 的 IMA/EVM 页面),但今天我们将使用默认策略。
要启用它,请在代理程序节点中的 /etc/default/grub 中添加 ima_appraise=log ima_policy=tcb 到 GRUB_CMDLINE_LINUX_DEFAULT 变量中,并重新生成 grub.cfg
transactional-update grub.cfg reboot
返回后,我们需要生成系统的良好哈希值列表。启用后,IMA 系统将注册策略指示的所有文件,这甚至会注册位于 initrd 中的文件,这可能会导致与当前 sysroot 中的文件不匹配。我们需要记住这一点,应该通过调整允许列表、排除列表和策略文件来修复它。
现在让我们生成 IMA 允许列表。
OUTPUT=/tmp/allowlist.txt
ALGO=sha256sum
rm -f "$OUTPUT"
cd /
head -n 1 /sys/kernel/security/ima/ascii_runtime_measurements | awk '{ print $4 " boot_aggregate" }' | sed 's/.*://' >> "$OUTPUT"
find `ls / | grep -E -v "boot|dev|mnt|proc|run|.snapshots|srv|sys|tmp"` \( -fstype rootfs -o -xtype f -type l -o -type f \) -uid 0 -exec "$ALGO" '/{}' >> "$OUTPUT" \;
这基本上从 IMA 测量文件中提取此系统的 boot_aggregate 哈希值,并创建一个包含系统哈希值的巨大列表。如果需要,可以提取 initrd 的内容并将哈希值附加到允许列表文件中。只需记住删除用于提取 ramdisk 的目录的前缀。
mkdir /tmp/initrd && cd /tmp/initrd
lsinitrd --unpack $(readlink -f /boot/initrd)
find -type f -exec $ALGO "./{}" \; | sed "s| \./\./| /|" >> $OUTPUT
rm -fr /tmp/initrd
最终我们将提供一个工具来帮助生成这些哈希值,或者更好的是,将它们添加到文件系统扩展属性中。
现在,让我们在此示例中在 /root 中创建一个自定义脚本,并将哈希值聚合到列表中。
cat << EOF > /root/greets.sh #!/bin/sh echo "Hello!" EOF
chmod a+x /root/greets.sh
"$ALGO" /root/greets.sh >> "$OUTPUT"
将 allowlist.txt 文件复制到验证器节点。此外,在验证器节点中,我们可以创建一个排除列表的提案。现在我们将排除太多文件。在生产环境中应该严格限制这一点。
cat << EOF > exclude.txt /boot/.* /dracut-state.sh /etc/.* /root/.bash_history /root/.lesshst /root/.ssh/.* /.snapshots/.* /sysroot/.* /usr/bin/dracut.* /usr/etc/.* /usr/lib/.* /usr/share/.* /var/lib/.* /var/log/.* EOF
每一行都是一个 Python 正则表达式。
创建有效载荷
在验证器节点中,我们将创建有效载荷。对于此示例,我们将传递所有节点共享的 SSH 公钥和私钥、authorized_keys 以及在撤销时将隔离节点的 shell 脚本中的本地操作。本地操作脚本将使用一个参数调用,该参数将包含操作的基本信息,即 JSON 文档。
请注意,对于此演示,代理程序需要以 root 用户身份执行某些脚本(例如,将证书移动到 /root/.ssh 或调用 iptables)。在实际场景中,可能不是一个好主意需要这些权限,但现在我们将以 root 用户身份运行 Keylime 代理程序(仍然是上游配置中的默认设置,但我们的软件包为此选择 keylime:tss)。编辑 /etc/keylime.conf 并注释掉 run_as 参数。
mkdir payload ssh-keygen -q -b 2048 -t rsa -N "" -f payload/id_rsa
cat << EOF > payload/autorun.sh #!/bin/bash mkdir -p /root/.ssh/ cp id_rsa* /root/.ssh/ chmod 600 /root/.ssh/id_rsa* cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys EOF
cat << EOF > payload/action_list local_action_rm_ssh.sh EOF
cat << EOF > payload/local_action_rm_ssh.sh
#!/bin/bash
# Consider only revocation types
kind=\$(grep -o '"type":"[^"]*' \$1 | grep -o '[^"]*$')
[ "\$kind" != "revocation" ] && exit 0
echo "Action type: revocation"
# Directory where the payload is stored. It also is part of the
# secure directory
unzipped=/var/lib/keylime/secure/unzipped
agent_id=\$(grep -o '"agent_id":"[^"]*' \$1 | grep -o '[^"]*$')
ip=\$(grep -o '"ip":"[^"]*' \$1 | grep -o '[^"]*$')
echo "Compromised system: \${agent_id} (\${ip})"
if [ -f "\${unzipped}/\${agent_id}-cert.crt" ]; then
echo "Removing cerificates from inside the compromised system"
rm -f /root/.ssh/id_rsa
rm -f /root/.ssh/id_rsa.pub
rm -f /root/.ssh/authorized_keys
else
echo "Blocking compromised system"
iptables -A INPUT -s "\$ip" -j DROP
fi
EOF
入侵节点
现在我们可以注册节点并开始收集 TPM 引用和 IMA 日志。为此,首先我们将创建一个空的度量启动参考状态,以便 Keylime 可以重放事件日志并将计算出的 PCR 与来自引用的当前 PCR 进行比较。
echo "{}" > mb-refstate.json
keylime_tenant -v 127.0.0.1 \
-t <AGENT> \
-u <UUID> \
--cert default \
--include payload \
--allowlist allowlist.txt \
--exclude exclude.txt \
--mb_refstate mb-refstate.json \
-c add
如果对 keylime.ima - ERROR - IMA ERRORS 有任何投诉,我们应该调整某些列表,也许是排除列表,以删除任何瞬态文件,例如。在重新注册之前,我们需要删除(-c delete)并重新启动节点,以在内核中重新创建新的 IMA 日志文件。
如果我们没有第二个节点的不同允许列表,我们可以注册这个特定的节点而不使用 IMA
keylime_tenant -v 127.0.0.1 \
-t <AGENT> \
-u <UUID> \
--cert default \
--include payload \
--mb_refstate mb-refstate.json \
-c add
如果一切正常,我们应该在两个节点中的 /var/lib/keylime/secure/unzipped 中提取有效载荷,其中包含本地操作、证书和 autorun.sh 脚本。应该执行此脚本并部署 /root/.ssh 中的 SSH 密钥。
我们可以从验证器测试无密码 SSH 连接
ssh -i payload/id_rsa <AGENT>
以及从第二个节点
ssh <AGENT>
在第一个节点中,我们应该有之前创建的临时脚本 /root/greets.sh,可以安全地执行它。
./greets.sh
我们可以模拟攻击者更改此文件并再次执行它的效果
echo 'echo "Hacked!"' >> greets.sh ./greets.sh
验证器将在下一次请求中检测到文件中的更改,并将命令执行有效载荷中传递的所有本地操作。在这种情况下,我们只有一个,它将删除受影响节点中的 SSH 密钥,并且对于其余节点,它将命令一个 iptables,该 iptables 将丢弃从受影响节点发起的任何连接。
我们可以检查第一个节点中的效果,并看到 /root/.ssh 是空的,并且在第二个节点中,我们现在有一个新的 iptables 规则,实际上正在丢弃来自第一个节点的所有连接。
说明
验证器和代理程序的容器
自 6.5.1 以来,openSUSE 正在为控制平面服务(Keylime 验证器、注册器和租户命令行工具)以及 Rust 代理程序提供容器。
它们当前位于 OBS devel:microos:containers 项目中,并且很快将在 openSUSE:Factory 中可用。
这两个镜像都基于 Tumbleweed,并且将在发布后自动更新到 Keylime 的最新版本。
要安装验证器和注册器,我们需要按照项目 README 中记录的那样部署 "keylime-control-plane-image"。
也可以安装基于 Rust 的代理程序服务。安装和使用说明也在项目 README 中,但除非将其用作构建在其之上的新容器中执行的应用程序的健康状况监控的基础,否则此组件的实用性较小。通过一些额外的配置,此容器还可以用于监控运行系统的 IMA 哈希值,并导出主机的度量启动信息。
Python Keylime 代理程序
作为参考,如果我们使用旧的 Python Keylime 代理程序,演示的有效载荷应该是
mkdir payload ssh-keygen -q -b 2048 -t rsa -N "" -f payload/id_rsa
cat << EOF > payload/autorun.sh #!/bin/bash # this will make it easier for us to find our own cert ln -s \`ls *-cert.crt | grep -v Revocation\` mycert.crt mkdir -p /root/.ssh/ cp id_rsa* /root/.ssh/ chmod 600 /root/.ssh/id_rsa* cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys EOF
cat << EOF > payload/action_list local_action_rm_ssh EOF
cat << EOF > payload/local_action_rm_ssh.py
import os
import ast
from M2Crypto import X509
import keylime.secure_mount as secure_mount
from keylime import keylime_logging
logger = keylime_logging.init_logging("local_action_rm_ssh")
async def execute(event):
if event.get("type") != "revocation":
return
metadata = event.get("meta_data", {})
if isinstance(metadata, str):
metadata = ast.literal_eval(metadata)
serial = metadata.get("cert_serial")
if serial is None:
logger.error("Unsupported revocation message: %s", event)
# load up my own cert
secdir = secure_mount.mount()
ca = X509.load_cert(f"{secdir}/unzipped/mycert.crt")
# is this revocation meant for me?
if serial == ca.get_serial_number():
os.remove("/root/.ssh/id_rsa")
os.remove("/root/.ssh/id_rsa.pub")
os.remove("/root/.ssh/authorized_keys")
else:
logger.info("A node in the network has been compromised: %s", event["ip"])
os.system(f"iptables -A INPUT -s {event['ip']} -j DROP")
EOF
SSH
出于安全原因,sshd 服务不允许使用密码远程访问 root 用户。为了调试或评估 Keylime 服务,这可能有点不方便。首选解决方案是在安装期间使用 YaST 提供 ssh 密钥,此时需要输入 root 密码。或者在首次启动时使用 ignition。
或者,为了测试,可以禁用此安全功能
echo "PermitRootLogin yes" > /etc/ssh/sshd_config.d/root.conf systemctl restart sshd.service
SELinux
MicroOS 默认以强制模式启用了 SELinux。目前存在一个错误,需要更新 SELinux 策略才能接受 TPM2 工具和 Keylime 需要执行的一些操作。在修复该错误之前,我们需要禁用 SELinux。有关参考,请查看 MicroOS 的 SELinux 部分。
最简单的方法是在安装的提案页面上禁用 SELinux。或者编辑 /etc/default/grub,搜索 GRUB_CMDLINE_LINUX_DEFAULT 参数的行,并将 selinux=1 更改为 selinux=0。如前所述,重新生成 grub.cfg。
要验证 SELinux 是否已禁用,我们可以检查 sestatus。
Firewalld
如果我们安装了 firewalld,我们可以安装 keylime-firewalld 子包,并在我们的公共区域中注册它
firewall-cmd --zone=public --add-service=keylime --permanent firewall-cmd --zone=public --add-service=keylime
Keylime firewalld 服务具有所有可能的 Keylime 服务的列表,因此可以用于代理程序和验证器节点。