【容器安全系列Ⅴ】- Linux强制访问控制:AppArmor 和 SELinux
wptr33 2024-12-11 17:29 13 浏览
在本系列中,我们介绍了各种安全层,这些安全层不仅可以将容器与主机上的其他进程隔离开来,还可以将容器与其底层主机隔离开来。在这篇文章中,我们将讨论 AppArmor 和 SELinux 如何在我们之前讨论过的其他隔离层之外提供额外的限制。
强制访问控制系统
AppArmor 和 SELinux 是强制访问控制 (MAC) 系统的示例。这些系统与其他安全控制(通常称为自主访问控制(DAC)系统)的不同之处在于,用户通常无法更改其操作。
文件权限是 DAC 系统的一个示例。文件的所有者可以调整其权限,以允许主机上的任何人修改它。使用 MAC 系统时,用户可能无法修改对他们拥有的资源施加的约束。这些限制甚至包括 root 用户,尽管系统上的 root 用户只需禁用整个 MAC 系统即可绕过此限制。Linux 中的 MAC 系统允许你限制对各种系统资源的访问,以便即使是其他特权进程也无法访问它们。
虽然可以在任何 Linux 主机上同时使用 AppArmor 或 SELinux,但通常只启用其中一个MAC策略 ,这因不同发行版而异。默认情况下,Debian 衍生系统使用 AppArmor,而基于 Red Hat 的系统则使用 SELinux。
AppArmor
AppArmor 通过定义可应用于主机上运行的进程的不同配置文件来实现其控制能力。这些配置文件可以限制对许多资源的访问,包括文件、网络流量和 Linux capabilities。
在安装了 AppArmor 的系统上,我们可以开始探索如何使用 sudo aa-status 命令来使其发挥作用。这将显示有关 AppArmor 配置和状态的信息。
aa-status 的输出
从这个输出中,我们可以看到几个有趣的信息:
- AppArmor 已加载并正常工作。
- 系统上定义了 34 个配置文件。
- 目前,没有进程具有启用的 AppArmor 配置文件。
从容器化的角度来看,配置文件列表中最有趣的部分是 docker-default 。默认情况下,此配置文件在 Docker 中默认用于提供一些保护,且不会影响应用程序兼容性。但是,这意味着它并没有像它可能的那样被锁定,因此有必要为需要额外保护的应用程序创建更严格的配置文件。
为了演示当进程获取活动 AppArmor 配置文件时会发生什么,我们可以通过 docker run -d nginx 启动一个新的 Docker 容器,然后运行 aa-status 命令。可以看到,我们现在有五个进程(由我们的容器启动)定义了一个配置文件,还有五个进程处于强制模式,这意味着 AppArmor 将根据为每个进程定义的配置文件限制它们的操作。
应用于 NGINX 的 Docker 默认 AppArmor 配置文件
现在我们已经了解了 AppArmor 的基础知识,让我们看看可以使用自定义 AppArmor 配置文件执行哪些操作,以及如何将其应用于 Docker 容器。
使用 AppArmor 的自定义配置文件
AppArmor 允许你控制许多 Linux 资源,包括网络和文件访问。为了通过一个简单的示例来演示这一点,我们可以创建一个配置文件来阻止对容器内/etc目录的写入访问,即使运行容器的用户是 root 。
首先,我们将创建一个最小的配置文件来实现我们的目标。
#include <tunables/global>
profile docker-block-bin flags=(attach_disconnected, mediate_deleted) {
#include <abstractions/base>
file,
deny /etc/** wl,
}
这里的关键行是 deny /etc/** wl,它阻止对/etc和任何子目录的写入访问。我们将此配置文件写入 /etc/apparmor.d/containers/docker-block-etc ,然后使用命令 sudo apparmor_parser -r /etc/apparmor.d/containers/docker-block-etc 将其加载到内核中。一旦准备就绪,我们就可以用 Docker 进行测试了。
我们可以创建一个新容器并使用 --security-opt 标志将我们的 etc 阻止配置文件应用于它:
docker run --rm -it --name block-bin --security-opt "apparmor=docker-block-etc" ubuntu:22.04 /bin/bash
然后,我们可以从容器内部尝试向/etc写入文件.输出证明,尽管我们是 root 用户,但我们无无法写入该目录。
自定义 AppArmor 配置文件阻止写入 /etc
如果您需要为 Docker 容器开发更复杂的配置文件,有一些工具可以帮助简化该过程,例如 Bane。Bane 的优点是自动为所有 Docker 容器添加基本限制。它还为配置文件规范提供了简化的语法。
SELinux
SELinux 在 Linux 方面有着悠久的历史。美国国家安全局最初在 2000 年将其作为 Linux 内核的一系列补丁实施。从那时起,Linux 生态系统中的开发仍在继续,如今,SELinux 默认用于基于 Red Hat 的发行版等。
与 AppArmor 相比,SELinux 采用了完全不同的安全方法。SELinux 没有将离散配置文件应用于进程,而是标记 Linux 资源(例如文件和端口),并根据每个资源的标签和尝试访问资源的进程的属性来限制对它们的访问。
在安装了 SELinux 的系统上,我们可以使用 sestatus 命令来查看它的配置方式。
sestatus 的输出
此命令返回有关如何在此主机上配置 SELinux 的关键信息。
第一行表示已启用 SELinux。Loaded policy name 告诉我们我们在 targeted 模式下运行(这意味着 SELinux 将应用于主机上的分发提供商(例如 Red Hat)选择的特定进程),而不是 mls 模式,后者更严格,并且对每个进程施加限制。通常,mls 模式不适用于通用系统,因为管理所有进程的标记和权限很复杂。
下一行是:Current mode: enforcing.在这里,可能的选项是:enforcing、 permissive 和 disabled。permissive模式对于设置 SELinux 很有用,因为它不会阻止操作。相反,它将记录在系统处于enforcing模式时可能发生的任何拒绝。
现在我们已经注意到在此主机上启用了 SELinux,我们可以探索有关当前配置的更多详细信息。运行 sudo semanage login -l 将向我们展示如何配置 SELinux 以处理标准用户进程。
semanage login -l 的输出
从这个输出中,我们可以看到 SELinux 认为普通用户(用__default__表示)和 root 用户是不受限制的,这意味着它不会对他们施加限制。
您可以使用标准系统工具和-Z开关来查看 SELinux 使用的标签。例如,pf -efZ 将显示有关应用于不同进程的标签的信息。在下面的示例中,我们可以看到 dockerd 和 containerd 进程的标签应用了 container_runtime_t 类型,并且标准用户使用的 bash 和 ssh 进程具有 unconfined_t 类型。
进程上的 SELinux 属性
我们还可以使用类似 ls -alZ .
文件上的 SELinux 属性
容器 SELinux 策略
在 Fedora 或 Red Hat 等 Linux 发行版下运行 Docker 时,通用的 SELinux 策略将应用于所有新容器。与 Docker 的默认 AppArmor 配置文件一样,此常规配置文件必须在提供的保护中做出权衡,因为它将相同的策略应用于每个容器。
要查看此策略的效果,我们可以运行类似 docker run --rm -it --name home_container -v /home/rorym:/hosthome fedora /bin/bash 启动名为“home_container”的新容器,该容器将我们的主目录挂载到容器中。如果我们尝试在容器内的 /hosthome 目录中创建一个文件,即使我们以 root 用户身份运行,我们也会被阻止。
SELinux 阻止对主机上 /home 的访问
为了确认 SELinux 是否阻止了访问,我们可以运行同一个容器并将 --security-opt label:disable 添加到命令中,这实际上禁用了该容器的 SELinux。如果我们随后尝试在 /hosthome 目录中创建一个文件,我们可以看到它是成功的。
禁用了 SELinux 的容器
如果我们想创建一个自定义的 SELinux 策略来允许我们访问我们的主目录,一种选择是使用 udica 之类的工具。此工具分析有关正在运行的容器的数据,以创建 SELinux 策略,然后可以加载和使用该策略。
首先,让我们检查我们的容器,并通过运行命令 docker inspect home_container | sudo udica home_container 将结果传递给 udica。完成此操作后,udica 将指示我们加载新的 SELinux 模块(它已创建),然后在指定新策略的同时重新启动我们的容器。使用此策略启动容器后,我们可以看到可以根据需要写入主目录。
通过UDICA定制标签的容器
结论
强制访问控制系统可以为容器提供额外的保护层。但是,它还需要努力学习如何有效地使用它们,并且自定义它们以大规模使用容器是一项艰巨的任务。因此,组织通常需要评估其风险状况,以确定使用它们是否有意义。在本系列的下一部分中,我们将介绍使用 seccomp 配置文件进行低级容器强化的另一种选择。
相关推荐
- 每天一个编程技巧!掌握这7个神技,代码效率飙升200%
-
“同事6点下班,你却为改BUG加班到凌晨?不是你不努力,而是没掌握‘偷懒’的艺术!本文揭秘谷歌工程师私藏的7个编程神技,每天1分钟,让你的代码从‘能用’变‘逆天’。文末附《Python高效代码模板》,...
- Git重置到某个历史节点(Sourcetree工具)
-
前言Sourcetree回滚提交和重置当前分支到此次提交的区别?回滚提交是指将改动的代码提交到本地仓库,但未推送到远端仓库的时候。...
- git工作区、暂存区、本地仓库、远程仓库的区别和联系
-
很多程序员天天写代码,提交代码,拉取代码,对git操作非常熟练,但是对git的原理并不甚了解,借助豆包AI,写个文章总结一下。Git的四个核心区域(工作区、暂存区、本地仓库、远程仓库)是版本控制的核...
- 解锁人生新剧本的密钥:学会让往事退场
-
开篇:敦煌莫高窟的千年启示在莫高窟321窟的《降魔变》壁画前,讲解员指着斑驳色彩说:"画师刻意保留了历代修补痕迹,因为真正的传承不是定格,而是流动。"就像我们的人生剧本,精彩章节永远...
- Reset local repository branch to be just like remote repository HEAD
-
技术背景在使用Git进行版本控制时,有时会遇到本地分支与远程分支不一致的情况。可能是因为误操作、多人协作时远程分支被更新等原因。这时就需要将本地分支重置为与远程分支的...
- Git恢复至之前版本(git恢复到pull之前的版本)
-
让程序回到提交前的样子:两种解决方法:回退(reset)、反做(revert)方法一:gitreset...
- 如何将文件重置或回退到特定版本(怎么让文件回到初始状态)
-
技术背景在使用Git进行版本控制时,经常会遇到需要将文件回退到特定版本的情况。可能是因为当前版本出现了错误,或者想要恢复到之前某个稳定的版本。Git提供了多种方式来实现这一需求。...
- git如何正确回滚代码(git命令回滚代码)
-
方法一,删除远程分支再提交①首先两步保证当前工作区是干净的,并且和远程分支代码一致$gitcocurrentBranch$gitpullorigincurrentBranch$gi...
- [git]撤销的相关命令:reset、revert、checkout
-
基本概念如果不清晰上面的四个概念,请查看廖老师的git教程这里我多说几句:最开始我使用git的时候,我并不明白我为什么写完代码要用git的一些列指令把我的修改存起来。后来用多了,也就明白了为什么。gi...
- 利用shell脚本将Mysql错误日志保存到数据库中
-
说明:利用shell脚本将MYSQL的错误日志提取并保存到数据库中步骤:1)创建数据库,创建表CreatedatabaseMysqlCenter;UseMysqlCenter;CREATET...
- MySQL 9.3 引入增强的JavaScript支持
-
MySQL,这一广泛采用的开源关系型数据库管理系统(RDBMS),发布了其9.x系列的第三个更新版本——9.3版,带来了多项新功能。...
- python 连接 mysql 数据库(python连接MySQL数据库案例)
-
用PyMySQL包来连接Python和MySQL。在使用前需要先通过pip来安装PyMySQL包:在windows系统中打开cmd,输入pipinstallPyMySQL ...
- mysql导入导出命令(mysql 导入命令)
-
mysql导入导出命令mysqldump命令的输入是在bin目录下.1.导出整个数据库 mysqldump-u用户名-p数据库名>导出的文件名 mysqldump-uw...
- MySQL-SQL介绍(mysql sqlyog)
-
介绍结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同...
- MySQL 误删除数据恢复全攻略:基于 Binlog 的实战指南
-
在MySQL的世界里,二进制日志(Binlog)就是我们的"时光机"。它默默记录着数据库的每一个重要变更,就像一位忠实的史官,为我们在数据灾难中提供最后的救命稻草。本文将带您深入掌握如...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
-
- 每天一个编程技巧!掌握这7个神技,代码效率飙升200%
- Git重置到某个历史节点(Sourcetree工具)
- git工作区、暂存区、本地仓库、远程仓库的区别和联系
- 解锁人生新剧本的密钥:学会让往事退场
- Reset local repository branch to be just like remote repository HEAD
- Git恢复至之前版本(git恢复到pull之前的版本)
- 如何将文件重置或回退到特定版本(怎么让文件回到初始状态)
- git如何正确回滚代码(git命令回滚代码)
- [git]撤销的相关命令:reset、revert、checkout
- 利用shell脚本将Mysql错误日志保存到数据库中
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)