本文仅作为学习记录,非商业用途,侵删,如需转载需作者同意。

下面说下容器安全的模块。

容器的安全很大程度由容器的架构特性决定的:比如容器与宿主机共享Linux 内核,通过Namespace来做资源的隔离,通过 shim/runC 的方式来启动等。

这些容器架构特性,在选择使用容器之后,作为容器的用户,其实没有多少能力去对架构层面做安全上的改动了。
你可能会说用Kata Container、gVisor 就是安全“容器”了。不过,Kata 或者 gVisor 只是兼容了容器接口标准,而内部的实现完全是另外的技术了。

对于使用容器的用户,在运行容器的时候,在安全方面可以:

  • 赋予容器合理的capabilities
  • 在容器中以非root用户来运行程序

一、问题再现

缺省docker run 的方式启动容器后,容器中很多操作都是不允许的,即使是以root用户来运行程序也不行。

例子

# docker run --name iptables -it registry/iptables:v1 bash
[root@0b88d6486149 /]# iptables -L
iptables v1.8.4 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)[root@0b88d6486149 /]# id
uid=0(root) gid=0(root) groups=0(root)

看上面的返回结果,提示没有权限,容器中都已经是root了。

查阅资料,容器启动的时候有个 “privileged” 参数,我们用了这个参数后,iptables 就启动成功了。

# docker stop iptables;docker rm iptables
iptables
iptables
# docker run --name iptables --privileged -it registry/iptables:v1 bash
[root@44168f4b9b24 /]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destinationChain FORWARD (policy ACCEPT)
target     prot opt source               destinationChain OUTPUT (policy ACCEPT)
target     prot opt source               destination

使用 privileged 是否合理。代码 里看到,使用该参数就会获取所有的 capabilities

            if ec.Privileged {p.Capabilities = caps.GetAllCapabilities()}

二、基本概念

2.1、Linux capabilities

Linux capabilities 官方手册的描述。

在Linux capabilities 出现前,进程的权限分为两类:

  • 特权用户的进程,进程的有效用户ID 是0,简单来说就是root 用户
  • 非特权用户的进程,进程的有效用户ID 是非0 ,就是非root用户

特权用户进程可以执行Linux 系统上的所有操作
而非特权用户进程在执行某些操作的时候就会被内核限制

从kernel 2.2 开始,Linux 开始把特权做了更详细的划分,划分出来的每个单元就被称为 capability

所有的 capabilities 都在 Linux capabilities 的手册列出来了。

对于任意一个进程,在做任意一个特权操作的时候,都需要有这个特权操作对应的capability。

比如说,运行 iptables 命令,对应的进程需要有 CAP_NET_ADMIN 这个capability ,如果要mount 一个文件系统,那么对应的进程需要有 CAP_SYS_ADMIN 这个capability

CAP_SYS_ADMIN 这个capability 里允许了大量的特权操作,包括文件系统,交换空间,还有对各种设备的操作,以及系统调试相关的调用等。

在普通的Linux 节点上,非root 用户启动的进程缺省没有任何 Linux capability ,而root 用户启动的进程缺省包含了所有的 Linux capability。

==

做个实验,对于root用户启动的进程,把CAP_NET_ADMIN 这个capability 移除,看看是否有权限运行 iptables 命令。

可以使用 capsh 命令来移动某个 capability

# sudo /usr/sbin/capsh --keep=1 --user=root   --drop=cap_net_admin  --   -c './iptables -L;sleep 100'
Chain INPUT (policy ACCEPT)
target     prot opt source               destinationChain FORWARD (policy ACCEPT)
target     prot opt source               destinationChain OUTPUT (policy ACCEPT)
target     prot opt source               destination
iptables: Permission denied (you must be root).

如上图,可以看到root用户,如果把CAP_NET_ADMIN 移除了,那么执行 iptables 的时候就会看到"Permission denied (you must be root)."的提示信息。

同时我们可以通过/proc/ 文件系统找到对应进程的status,这样就能确认进程中的CAP_NET_ADMIN 是否已经被移除了。

# ps -ef | grep sleep
root     22603 22275  0 19:44 pts/1    00:00:00 sudo /usr/sbin/capsh --keep=1 --user=root --drop=cap_net_admin -- -c ./iptables -L;sleep 100
root     22604 22603  0 19:44 pts/1    00:00:00 /bin/bash -c ./iptables -L;sleep 100# cat /proc/22604/status | grep Cap
CapInh:            0000000000000000
CapPrm:          0000003fffffefff
CapEff:             0000003fffffefff
CapBnd:          0000003fffffefff
CapAmb:         0000000000000000

对于当前进程,直接影响某个特权操作是否可以被执行的参数,是"CapEff",也就是"Effective capability sets",这是一个 bitmap,每一个 bit 代表一项 capability 是否被打开。

在 Linux 内核capability.h里把 CAP_NET_ADMIN 的值定义成 12,所以我们可以看到"CapEff"的值是"0000003fffffefff",第 4 个数值是 16 进制的"e",而不是 f。

这表示 CAP_NET_ADMIN 对应的第 12-bit 没有被置位了(0xefff = 0xffff & (~(1 << 12))),所以这个进程也就没有执行 iptables 命令的权限了。

对于进程 status 中其他几个 capabilities 相关的参数,它们还需要和应用程序文件属性中的 capabilities 协同工作,这样才能得到新启动的进程最终的 capabilities 参数的值。


如果我们要启动一个程序,在Linux里的过程就是先通过fork()来创建出一个子进程,然后调用 execve() 系统调用来读取文件系统里的程序文件,把程序文件加载到进程的代码段中开始运行。

就像图中所描绘的那样,这个新运行的进程里相关的capabilities 参数的值,由它的父进程以及程序文件中的capabilities 参数值计算得来的。

文件中可以设置capabilities 参数值,并且这个值会影响到最后运行它的进程

比如我们把iptables的应用程序加上 CAP_NET_ADMIN 的capability ,那么即使非root用户也可以执行iptables了。


$ id
uid=1000(centos) gid=1000(centos) groups=1000(centos),10(wheel)
$ sudo setcap cap_net_admin+ep ./iptables
$ getcap ./iptables
./iptables = cap_net_admin+ep
$./iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destinationChain FORWARD (policy ACCEPT)
target     prot opt source               destination
DOCKER-USER  all  --  anywhere             anywhere
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
…

Linux capabilities 就是把Linux root 用户原来所有的特权做了细化,可以更加细粒度的给进程赋予不同的权限。

三、解决问题

privileged的容器就是允许容器中的进程可以执行所有的特权操作

容器缺省启动的时候,系统最多只允许15个capabilities runC spec 文档中的 security 部分。

也可以查看容器中 init 进程 status 里的cap 参数,看一下容器缺省的capabilities。

# docker run --name iptables -it registry/iptables:v1 bash
[root@e54694652a42 /]# cat /proc/1/status  |grep Cap
CapInh:            00000000a80425fb
CapPrm:          00000000a80425fb
CapEff:              00000000a80425fb
CapBnd:          00000000a80425fb
CapAmb:         0000000000000000

直接使用 privileged 参数把所有的capabilities 都给容器是很危险的事情。
容器中的进程有了 CAP_SYS_ADMIN 的特权之后,这些进程就可以在容器里直接访问磁盘设备,直接可以读取或者修改宿主机上的所有文件了。

所以在容器平台上是基本不允许把容器直接设置为privileged的,我们需要根据容器中进程需要的最少特权来赋予 capabilities。

开头的问题,iptables 需要CAP_NET_ADMIN 这个capabilities ,我们只要在运行Docker 的时候,给这个容器多加一个 NET_ADMIN 参数就可以了。

--cap-add NET_ADMIN

# docker run --name iptables --cap-add NET_ADMIN -it registry/iptables:v1 bash
[root@cfedf124dcf1 /]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destinationChain FORWARD (policy ACCEPT)
target     prot opt source               destinationChain OUTPUT (policy ACCEPT)
target     prot opt source               destination

四、重点小结

Linux capabilities 就是把Linux root 用户原来所有的特权做了细化,可以更加细粒度的给进程赋予不同的权限。

对于Linux 中每一个特权都有一个对应的capability,对于一个capability,有的对应一个权限操作,有的对应很多个特权操作。

每个Linux 进程有5个capabilities 集合参数,其中Effctive 集合里的capabilities 决定了当前进程可以做哪些特权操作。
而其他的集合参数会和应用程序文件的capabilities 集合参数来一起决定新启动程序的capabilities 集合参数。

对于容器的root用户,缺省只赋予了15个capabilities。
如果发现容器中的进程的权限不够,就需要分析它需要最小的capabilities集合,而不是直接赋予容器 privileged。

因为"privileged"包含了所有的 Linux capabilities, 这样"privileged"就可以轻易获取宿主机上的所有资源,这会对宿主机的安全产生威胁。所以,我们要根据容器中进程需要的最少特权来赋予 capabilities。

五、评论

1、
getcap $(which ping)
setcap -r $(which ping)

顺便举个之前使用过的例子:普通用户默认没有 tcpdump 抓包权限,可添加 net_raw、net_admin caps:
sudo setcap cap_net_raw,cap_net_admin+ep $(which tcpdump)

2、
getcap /usr/bin/ping 查看ping进程当前cap
setcap cap_net_admin,cap_net_raw+p /usr/bin/ping 设置ping进程cap

getcap setap capsh 等命令的解释的博客,很牛逼的博客
https://www.cnblogs.com/ryanyangcs/p/11798292.html

3、
问题:
selinux是不是实际上就是限制cap权限的操作

回答:
selinux 是通过对object, 例如进程\文件, 打上label来控制这些object的相互作用。

19 | 容器安全(1):我的容器真的需要privileged权限吗?相关推荐

  1. php 容器实现,PHP 依赖注入容器实现

    在看 Laravel 文档的时候发现入门指南的下一章便是核心架构,对于我这种按部就班往下读的同学这简直是劝退篇.各种之前没有接触过的概念砸得人头晕,容器便是其中之一.不过在拜读过几篇文章后也逐渐理解了 ...

  2. 小网站的容器化(下):网站容器化的各种姿势,先跟着撸一波代码再说!

    作者 | 王洪鹏 责编 | Carol 出品 | CSDN云计算(ID:CSDNcloud) 封图| CSDN下载于视觉中国 上篇文章:小网站的容器化(上) 中我们大致描述了下个人网站在日常维护中的痛 ...

  3. 容器-Docker《三》容器管理

    容器-Docker<三>容器管理 下载镜像只是相当于将软件下载下来安装好,但是并不代表把它运行起来,类似于root@ubuntu2204:~# apt install nginx = do ...

  4. 我的Go+语言初体验——在Docker建立一个可以用Go+语言开发的容器环境(以Ubuntu容器为例)

    前言 "我的Go+语言初体验" | 征文活动进行中...... 作为一名嵌入式软件工程师的我,在工作中使用高级语言开发的场景不多,但技术的迭代大部分偏向于应用层开发,身为程序员的一 ...

  5. Docker容器虚拟化(二)—容器管理、仓库管理、数据管理

    2019独角兽企业重金招聘Python工程师标准>>> Docker 容器管理 启动一个容器: [root@study ~]# docker run -it centos-7-x86 ...

  6. Spring IoC容器初始化源码(1)—容器初始化入口以及setConfigLocations设置容器配置信息【一万字】

      基于最新Spring 5.x,对于基于XML的Spring IoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图 ...

  7. linux有没有showtrees命令,容器与云|监控 Linux 容器性能的命令行神器

    ctop是一个新的基于命令行的工具,它可用于在容器层级监控进程.容器通过利用控制器组(cgroup)的资源管理功能,提供了操作系统层级的虚拟化环境.该工具从cgroup收集与内存.CPU.块输入输出的 ...

  8. 容器云系列之Docker容器监控工具WeaveScope

    容器监控工具很多,本文主要对比了cAdvisor.Weave Scope和Prometheus几种监控工具的特性和功能,并结合环境部署测试了各工具的使用. 容器监控工具很多,下表对比了cAdvisor ...

  9. Docker容器学习梳理--应用程序容器环境部署

    关于国内Docker镜像,可以参考:Docker容器学习梳理--基础知识(2) 的Docker镜像使用. 如果我们需要在Docker环境下部署tomcat.redis.mysql.nginx.php等 ...

最新文章

  1. pip安装kolla-ansible时报错Cannot install ‘PyYAML‘的解决方法
  2. Android API 中文(14) —— ViewStub
  3. 远控免杀专题11-Avoidz免杀
  4. python斐波那契前20递归_算法python实现经典递归问题(汉诺塔, 斐波那契数列,阶乘)...
  5. python 多维list 排序_一行代码的优雅| Python列表生成式
  6. android gif转jpg格式文件,android使用多张图片合成gif文件
  7. 读书笔记——计算机组成原理
  8. 敢问北极熊,路在何方?
  9. Error while waiting for device: The emulator process for AVD Pixel_2_XL_API_28 was killed.
  10. 【分论坛第一期大剧透】开源技术与新IT基础设施联袂共舞
  11. Openproj 在64位操作系统报错errno=193
  12. MATLAB/Simulink 基础入门讲解(二)【未完】
  13. Pollard-rho的质因数分解
  14. IDEA社区版安装与概述
  15. Python下载新浪微博视频(流式下载)
  16. APS生产计划排产在注塑行业的应用
  17. 可视化——Excel2进阶
  18. 基于改进二进制粒子群算法的配电网重构(matlab实现)
  19. 【项目实战】基于STM32单片机的智能小车设计(有代码)
  20. 超融合走向红海,下一代超融合是新蓝海?

热门文章

  1. 什么是特斯拉?他和爱迪生相爱相杀。
  2. 电脑微信聊天记录迁移微信文件迁移备份恢复
  3. Educational Codeforces Round 132 div.2 A-F题解
  4. python bz2模块
  5. 计算机操作系统原理复习笔记——考试版
  6. Unity3D 通用麻将胡牌算法
  7. 用python解析word文件(三):style
  8. SEO基础知识:什么是网站结构,为什么重要?
  9. SQL学习-2.8 子查询和临时表格
  10. stm32+hx711+蓝牙hc05 称重系统(蓝牙电子秤)