{"value":"#### **概述**\nSELinux,全称Security-Enhanced Linux,是一个为系统提供强制访问控制机制的安全模块,安装并启用SELinux模块的操作系统会为每个进程和系统资源打上一个特殊的安全标记,称为SELinux上下文,并根据SELinux上下文信息以允许或拒绝访问行为。\n\n根据国家网络安全等级保护基本要求,第三级系统在安全计算环境层面“应对重要主体和客体设置安全标记,并控制主体对有安全标记信息资源的访问”,因此需要通过国家等保三级测评的系统均需要在系统内开启SELinux。\n\n注:亚马逊官方系统镜像Amazon Linux 2022已默认开启了Enforcing策略的SELinux。\n\n随着SELinux的应用越来越广泛,由SELinux配置不当导致的系统故障也随之增多,严重情况下可能导致系统启动失败,本文先从如何紧急恢复SELinux故障的EC2主机入手,然后围绕 [SELinux常见三大问题根源](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-troubleshooting-top_three_causes_of_problems)之一的“标签故障”,介绍在AWS上进行故障排查的方法及思路。\n\n#### **EC2紧急恢复的两种方法**\n\n##### **EC2串行控制台访问**\n\n如果故障主机满足[串行控制台访问前置条件](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-serial-console.html#sc-prerequisites),并且启用了串行控制台访问,则可以直接使用EC2串行控制台访问进行紧急恢复以及故障排查,串行控制台不要求您的EC2实例具有任何联网功能。使用串行控制台,您可以向实例输入命令,就像键盘和显示器直接连接到实例的串行端口一样。串行控制台会话在实例重启和停止期间持续。在重新启动期间,您可以从一开始就查看所有启动消息。串行控制台默认未启用,需要明确授权以后方可使用,具体方法如下:\n\n1、授予账户可执行串行控制台的权限,建议的IAM策略如下:\n\n```\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": [\n \"ec2:GetSerialConsoleAccessStatus\",\n \"ec2:EnableSerialConsoleAccess\",\n \"ec2:DisableSerialConsoleAccess\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}\n\n```\n\n配置此策略后,账户将可以在连接EC2实例时,看到“EC2串行控制台访问”的选项,初始默认为“禁止”,需要点击“管理”,设置为“允许”,完毕,账号即可对EC2进行串行控制台访问.\n\n2、在串行控制台登陆EC2服务器前,我们还需要为EC2建立允许在串行控制台使用密码登陆的用户及口令。使用默认的SSH方式远程登录EC2服务器,登录以后使用passwd设定密码,下面使用root为例:\n\n```\n[ec2-user ~]$ sudo passwd root \n```\n\n3、禁用SELinux以进行紧急恢复,对于因SELinux导致的系统故障,我们可以先禁用SELinux以进行紧急恢复及故障排查。串行控台登录服务器以后,直接修改 /etc/selinux/config 并将SELINUX=disabled,然后重启服务器,即可生效。\n\n##### **救援实例**\n\n对于不支持串行控制台访问的服务器,或支持但前期未启用的,我们还可以使用救援实例对SELinux故障主机进行紧急恢复。具体操作如下:\n\n1. 在Virtual Private Cloud (VPC)中[启动新的Amazon EC2实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/LaunchingAndUsingInstances.html),且使用与受损实例相同的 Amazon系统映像 (AMI)并与其位于同一可用区中。新实例将成为您的“救援”实例。或者,也可以使用您可以访问的现有实例,但前提是该实例使用与受损实例相同的 AMI,并且二者位于同一可用区中.\n2. 从受损实例中[分离Amazon Elastic Block Store (Amazon EBS)根卷](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-detaching-volume.html)(/dev/xvda 或/dev/sda1)。记下设备名称,以确保稍后重新连接时它是相同的\n3. 将EBS卷作为辅助设备(/dev/sdf)附加到救援实例。\n4. 使用SSH连接到您的救援实例。\n5. 成为根用户,使用lsblk 标识正确的设备名称,然后将其保存以在整个过程中使用:\n6. \n```\n$ sudo -i\n# lsblk\n# rescuedev=/dev/xvdf1\n```\n\n**注意**:设备(/dev/xvdf1)可能会以不同的[设备名称](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html)附加到救援实例。使用 lsblk 命令查看可用磁盘设备及其挂载点,以确定正确的设备名称。\n\n6、选择要使用的适当临时挂载点,并确保它存在,请使用/mnt,除非该挂载点已在使用\n\n```\n# rescuemnt=/mnt\n# mkdir -p $rescuemnt\n```\n\n7、从附加的卷挂载根文件系统:\n\n```\n# mount $rescuedev $rescuemnt\n```\n\n**注意**:如果卷挂载失败,请检查 dmesg | tail。如果日志显示 UUID 冲突,请使用选项 -o nouuid。\n\n8、修改SELinux配置文件\n\n```\n# cd /mnt/rescuemnt\n# vi ./etc/selinux/config\n```\n\n9、完成后,卸载辅助设备:\n\n```\n# exit\n# umount $rescuemnt\n```\n\n10、将辅助卷(/dev/sdf)与救援 EC2 实例分离,然后以/dev/xvda 或 /dev/sda1(根卷)的形式将其附加到原始实例。确保这与步骤 2 中看到的相同。/11、启动EC2实例,然后验证实例是否正常重启。\n\n#### **SELinux日志分析**\n\n系统恢复以后,我们第一步是分析SELinux拦截日志,分析SELinux到底是拦截了哪些进程才导致的系统异常。默认情况下,SELinux拦截日志均记录在/var/log/audit/audit.log*及/var/log/messages*文件中,对于audit和message,我们均可以通过关键词“AVC”(Access Vector Cache,访问矢量缓存)筛选除SELinux拦截的日志,以下是当 Apache HTTP 服务器(在 httpd_t 域中运行)尝试访问 /var/www/html/file1 文件(标有 samba_share_t 类型)时发生的 AVC 拒绝日志(以及关联的系统调用)示例(具体日志格式含义,可参考 [RedHat官方链接 ](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-troubleshooting-fixing_problems#sect-Security-Enhanced_Linux-Fixing_Problems-Raw_Audit_Messages)):\n\n```\ntype=AVC msg=audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm=\"httpd\" \npath=\"/var/www/html/file1\" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 \ntcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file \n\ntype=SYSCALL msg=audit(1226874073.147:96): arch=40000003 syscall=196 success=no exit=-13 \na0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 uid=48 \ngid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm=\"httpd\" \nexe=\"/usr/sbin/httpd\" subj=unconfined_u:system_r:httpd_t:s0 key=(null) \n```\n\n通过分析SELinux拦截日志,可识别出故障发生时SELinux拦截掉的进程及路径文件信息。\n\n注:如果通过分析日志无法直观识别出被拦截的异常进程,由于audit及message都默认有归档功能,还可以将故障时间点的拦截日志与正常时间段拦截日志进行对比分析,识别出故障发生时被额外拦截的进程。\n\n#### **进程上下文标签重置**\n\n分析上下文标签有两种方式:一种是直接对拦截日志中主客体的上下文各个字段进行分析,包括分析SELinux用户、角色、类型、以及级别,这方面的分析需要管理员对SELinux有非常深刻的理解,要求较高。\n\n作为一种简单但更实用的排查方法,对于仅仅启用默认SELinux策略的系统,我们可以使用rhel-autorelabel服务将系统进程上下文标签进行恢复重置,然后通过对比重置前后的文件标签属性,识别出进程上下文标签的异常。\n\n对于文件标签属性,我们有两种方法进行对比,一种手动对比,我们可使用系统命令“ls -z file”查看并记录重置前后file的上下文标签值。这种对比方法适用于小量文件的对比;另一种是在系统安装AIDE文件完整性校验工具,将需要对比的文件加入aide.conf文件中,自动化进行对比。AIDE使用方法参考如下:\n\n```\ncp /etc/aide.conf /etc/aide.conf_bak(可选,备份原始conf文件)\nvi /etc/aide.conf (可选,在默认的基础上增加需要对比的文件,来源可以是日志分析识别到的一个或多个异常进程)\naide --init \nmv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz\naide --check\n```\n\n启用rhel-autorelabel服务的操作命令如下:\n\n```\nsystemctl enable rhel-autorelabel\ntouch /.autorelabel\nreboot\n#系统重启后,将会对文件重打SELinux上下文标签\n```\n\n#### **故障原因验证**\n在通过标签重置,并对比分析识别到标签故障具体原因后,我们可以尝试系统命令chcon 将异常进程的上下文标签修改为正确或错误的值,验证异常现象是否消失或复现,从而确定故障的根本原因。\n\n#### **总结**\n\n本文围绕“标签故障”这一SELinux常见故障根源,讨论了SELinux故障分析的思路和方法,但在实际环境中,系统故障的原因有多种,甚至SELinux故障仍有许多可能性,因此还需要查阅系统日志文件及官方文档进行详细分析。\n\n#### **本篇作者**\n\n\n![image.png](https://dev-media.amazoncloud.cn/3f7850d480884c9f978c6913c5964edc_image.png)\n\n#### **王俊峰**\n亚马逊云科技专业服务团队安全顾问,负责云安全合规、云安全解决方案等的咨询设计及落地实施,致力于为客户上云提供安全最佳实践,并解决客户上云中碰到的安全需求。\n\n","render":"<h4><a id=\"_0\"></a><strong>概述</strong></h4>\n<p>SELinux,全称Security-Enhanced Linux,是一个为系统提供强制访问控制机制的安全模块,安装并启用SELinux模块的操作系统会为每个进程和系统资源打上一个特殊的安全标记,称为SELinux上下文,并根据SELinux上下文信息以允许或拒绝访问行为。</p>\n<p>根据国家网络安全等级保护基本要求,第三级系统在安全计算环境层面“应对重要主体和客体设置安全标记,并控制主体对有安全标记信息资源的访问”,因此需要通过国家等保三级测评的系统均需要在系统内开启SELinux。</p>\n<p>注:亚马逊官方系统镜像Amazon Linux 2022已默认开启了Enforcing策略的SELinux。</p>\n<p>随着SELinux的应用越来越广泛,由SELinux配置不当导致的系统故障也随之增多,严重情况下可能导致系统启动失败,本文先从如何紧急恢复SELinux故障的EC2主机入手,然后围绕 <a href=\"https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-troubleshooting-top_three_causes_of_problems\" target=\"_blank\">SELinux常见三大问题根源</a>之一的“标签故障”,介绍在AWS上进行故障排查的方法及思路。</p>\n<h4><a id=\"EC2_9\"></a><strong>EC2紧急恢复的两种方法</strong></h4>\n<h5><a id=\"EC2_11\"></a><strong>EC2串行控制台访问</strong></h5>\n<p>如果故障主机满足<a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-serial-console.html#sc-prerequisites\" target=\"_blank\">串行控制台访问前置条件</a>,并且启用了串行控制台访问,则可以直接使用EC2串行控制台访问进行紧急恢复以及故障排查,串行控制台不要求您的EC2实例具有任何联网功能。使用串行控制台,您可以向实例输入命令,就像键盘和显示器直接连接到实例的串行端口一样。串行控制台会话在实例重启和停止期间持续。在重新启动期间,您可以从一开始就查看所有启动消息。串行控制台默认未启用,需要明确授权以后方可使用,具体方法如下:</p>\n<p>1、授予账户可执行串行控制台的权限,建议的IAM策略如下:</p>\n<pre><code class=\"lang-\">{\n "Version": "2012-10-17",\n "Statement": [\n {\n "Effect": "Allow",\n "Action": [\n "ec2:GetSerialConsoleAccessStatus",\n "ec2:EnableSerialConsoleAccess",\n "ec2:DisableSerialConsoleAccess"\n ],\n "Resource": "*"\n }\n ]\n}\n\n</code></pre>\n<p>配置此策略后,账户将可以在连接EC2实例时,看到“EC2串行控制台访问”的选项,初始默认为“禁止”,需要点击“管理”,设置为“允许”,完毕,账号即可对EC2进行串行控制台访问.</p>\n<p>2、在串行控制台登陆EC2服务器前,我们还需要为EC2建立允许在串行控制台使用密码登陆的用户及口令。使用默认的SSH方式远程登录EC2服务器,登录以后使用passwd设定密码,下面使用root为例:</p>\n<pre><code class=\"lang-\">[ec2-user ~]$ sudo passwd root \n</code></pre>\n<p>3、禁用SELinux以进行紧急恢复,对于因SELinux导致的系统故障,我们可以先禁用SELinux以进行紧急恢复及故障排查。串行控台登录服务器以后,直接修改 /etc/selinux/config 并将SELINUX=disabled,然后重启服务器,即可生效。</p>\n<h5><a id=\"_45\"></a><strong>救援实例</strong></h5>\n<p>对于不支持串行控制台访问的服务器,或支持但前期未启用的,我们还可以使用救援实例对SELinux故障主机进行紧急恢复。具体操作如下:</p>\n<ol>\n<li>在Virtual Private Cloud (VPC)中<a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/LaunchingAndUsingInstances.html\" target=\"_blank\">启动新的Amazon EC2实例</a>,且使用与受损实例相同的 Amazon系统映像 (AMI)并与其位于同一可用区中。新实例将成为您的“救援”实例。或者,也可以使用您可以访问的现有实例,但前提是该实例使用与受损实例相同的 AMI,并且二者位于同一可用区中.</li>\n<li>从受损实例中<a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-detaching-volume.html\" target=\"_blank\">分离Amazon Elastic Block Store (Amazon EBS)根卷</a>(/dev/xvda 或/dev/sda1)。记下设备名称,以确保稍后重新连接时它是相同的</li>\n<li>将EBS卷作为辅助设备(/dev/sdf)附加到救援实例。</li>\n<li>使用SSH连接到您的救援实例。</li>\n<li>成为根用户,使用lsblk 标识正确的设备名称,然后将其保存以在整个过程中使用:</li>\n<li></li>\n</ol>\n<pre><code class=\"lang-\">$ sudo -i\n# lsblk\n# rescuedev=/dev/xvdf1\n</code></pre>\n<p><strong>注意</strong>:设备(/dev/xvdf1)可能会以不同的<a href=\"https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html\" target=\"_blank\">设备名称</a>附加到救援实例。使用 lsblk 命令查看可用磁盘设备及其挂载点,以确定正确的设备名称。</p>\n<p>6、选择要使用的适当临时挂载点,并确保它存在,请使用/mnt,除非该挂载点已在使用</p>\n<pre><code class=\"lang-\"># rescuemnt=/mnt\n# mkdir -p $rescuemnt\n</code></pre>\n<p>7、从附加的卷挂载根文件系统:</p>\n<pre><code class=\"lang-\"># mount $rescuedev $rescuemnt\n</code></pre>\n<p><strong>注意</strong>:如果卷挂载失败,请检查 dmesg | tail。如果日志显示 UUID 冲突,请使用选项 -o nouuid。</p>\n<p>8、修改SELinux配置文件</p>\n<pre><code class=\"lang-\"># cd /mnt/rescuemnt\n# vi ./etc/selinux/config\n</code></pre>\n<p>9、完成后,卸载辅助设备:</p>\n<pre><code class=\"lang-\"># exit\n# umount $rescuemnt\n</code></pre>\n<p>10、将辅助卷(/dev/sdf)与救援 EC2 实例分离,然后以/dev/xvda 或 /dev/sda1(根卷)的形式将其附加到原始实例。确保这与步骤 2 中看到的相同。/11、启动EC2实例,然后验证实例是否正常重启。</p>\n<h4><a id=\"SELinux_94\"></a><strong>SELinux日志分析</strong></h4>\n<p>系统恢复以后,我们第一步是分析SELinux拦截日志,分析SELinux到底是拦截了哪些进程才导致的系统异常。默认情况下,SELinux拦截日志均记录在/var/log/audit/audit.log<em>及/var/log/messages</em>文件中,对于audit和message,我们均可以通过关键词“AVC”(Access Vector Cache,访问矢量缓存)筛选除SELinux拦截的日志,以下是当 Apache HTTP 服务器(在 httpd_t 域中运行)尝试访问 /var/www/html/file1 文件(标有 samba_share_t 类型)时发生的 AVC 拒绝日志(以及关联的系统调用)示例(具体日志格式含义,可参考 <a href=\"https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-troubleshooting-fixing_problems#sect-Security-Enhanced_Linux-Fixing_Problems-Raw_Audit_Messages\" target=\"_blank\">RedHat官方链接 </a>):</p>\n<pre><code class=\"lang-\">type=AVC msg=audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd" \npath="/var/www/html/file1" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0 \ntcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file \n\ntype=SYSCALL msg=audit(1226874073.147:96): arch=40000003 syscall=196 success=no exit=-13 \na0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 uid=48 \ngid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm="httpd" \nexe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null) \n</code></pre>\n<p>通过分析SELinux拦截日志,可识别出故障发生时SELinux拦截掉的进程及路径文件信息。</p>\n<p>注:如果通过分析日志无法直观识别出被拦截的异常进程,由于audit及message都默认有归档功能,还可以将故障时间点的拦截日志与正常时间段拦截日志进行对比分析,识别出故障发生时被额外拦截的进程。</p>\n<h4><a id=\"_113\"></a><strong>进程上下文标签重置</strong></h4>\n<p>分析上下文标签有两种方式:一种是直接对拦截日志中主客体的上下文各个字段进行分析,包括分析SELinux用户、角色、类型、以及级别,这方面的分析需要管理员对SELinux有非常深刻的理解,要求较高。</p>\n<p>作为一种简单但更实用的排查方法,对于仅仅启用默认SELinux策略的系统,我们可以使用rhel-autorelabel服务将系统进程上下文标签进行恢复重置,然后通过对比重置前后的文件标签属性,识别出进程上下文标签的异常。</p>\n<p>对于文件标签属性,我们有两种方法进行对比,一种手动对比,我们可使用系统命令“ls -z file”查看并记录重置前后file的上下文标签值。这种对比方法适用于小量文件的对比;另一种是在系统安装AIDE文件完整性校验工具,将需要对比的文件加入aide.conf文件中,自动化进行对比。AIDE使用方法参考如下:</p>\n<pre><code class=\"lang-\">cp /etc/aide.conf /etc/aide.conf_bak(可选,备份原始conf文件)\nvi /etc/aide.conf (可选,在默认的基础上增加需要对比的文件,来源可以是日志分析识别到的一个或多个异常进程)\naide --init \nmv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz\naide --check\n</code></pre>\n<p>启用rhel-autorelabel服务的操作命令如下:</p>\n<pre><code class=\"lang-\">systemctl enable rhel-autorelabel\ntouch /.autorelabel\nreboot\n#系统重启后,将会对文件重打SELinux上下文标签\n</code></pre>\n<h4><a id=\"_138\"></a><strong>故障原因验证</strong></h4>\n<p>在通过标签重置,并对比分析识别到标签故障具体原因后,我们可以尝试系统命令chcon 将异常进程的上下文标签修改为正确或错误的值,验证异常现象是否消失或复现,从而确定故障的根本原因。</p>\n<h4><a id=\"_141\"></a><strong>总结</strong></h4>\n<p>本文围绕“标签故障”这一SELinux常见故障根源,讨论了SELinux故障分析的思路和方法,但在实际环境中,系统故障的原因有多种,甚至SELinux故障仍有许多可能性,因此还需要查阅系统日志文件及官方文档进行详细分析。</p>\n<h4><a id=\"_145\"></a><strong>本篇作者</strong></h4>\n<p><img src=\"https://dev-media.amazoncloud.cn/3f7850d480884c9f978c6913c5964edc_image.png\" alt=\"image.png\" /></p>\n<h4><a id=\"_150\"></a><strong>王俊峰</strong></h4>\n<p>亚马逊云科技专业服务团队安全顾问,负责云安全合规、云安全解决方案等的咨询设计及落地实施,致力于为客户上云提供安全最佳实践,并解决客户上云中碰到的安全需求。</p>\n"}