容器实战高手课
李程远
eBay 总监级工程师,云平台架构师
24647 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 31 讲
容器实战高手课
15
15
1.0x
00:00/00:00
登录|注册

20 | 容器安全(2):在容器中,我不以root用户来运行程序可以吗?

降低容器的安全风险
以非root用户启动和管理容器
使用User Namespace可以解决uid冲突问题
可以嵌套
隔离了一台Linux节点上的User ID和Group ID
在云平台上可能引起uid冲突
可以在Dockerfile中为容器镜像建立一个用户
给容器指定一个普通用户uid
rootless container的难点:容器网络的配置、Cgroup的配置
Docker和podman支持rootless container,降低容器的安全风险
User Namespace带来的好处:映射容器中root用户为宿主机上的普通用户,容器uid分配更容易
建议在容器中以非root用户运行进程
容器中root用户的Linux capabilities减少,但仍存在安全风险
方法三:rootless container
方法二:User Namespace
方法一:Run as non-root user
容器中的root用户有权限修改宿主机上的关键文件
容器中root用户的capabilities被限制,但仍可修改宿主机文件
思考题
重点小结
问题分析
问题再现
在容器中以非root用户运行程序的安全问题

该思维导图由 AI 生成,仅供参考

你好,我是程远。
上一讲里,我们学习了 Linux capabilities 的概念,也知道了对于非 privileged 的容器,容器中 root 用户的 capabilities 是有限制的,因此容器中的 root 用户无法像宿主机上的 root 用户一样,拿到完全掌控系统的特权。
那么是不是让非 privileged 的容器以 root 用户来运行程序,这样就能保证安全了呢?这一讲,我们就来聊一聊容器中的 root 用户与安全相关的问题。

问题再现

说到容器中的用户(user),你可能会想到,在 Linux Namespace 中有一项隔离技术,也就是 User Namespace。
不过在容器云平台 Kubernetes 上目前还不支持 User Namespace,所以我们先来看看在没有 User Namespace 的情况下,容器中用 root 用户运行,会发生什么情况。
首先,我们可以用下面的命令启动一个容器,在这里,我们把宿主机上 /etc 目录以 volume 的形式挂载到了容器中的 /mnt 目录下面。
# docker run -d --name root_example -v /etc:/mnt centos sleep 3600
然后,我们可以看一下容器中的进程"sleep 3600",它在容器中和宿主机上的用户都是 root,也就是说,容器中用户的 uid/gid 和宿主机上的完全一样。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

在容器中以root用户运行程序可能存在的安全问题一直备受关注。本文深入探讨了这一问题,并提出了两种解决方案。首先,通过指定普通用户uid或使用User Namespace来避免容器以root用户运行的方法。其次,分析了这两种方法可能存在的问题和局限性。通过实例和技术概念的讲解,读者可以深入了解容器中root用户运行程序的安全问题及解决方案。此外,文章还介绍了rootless container的概念,即以非root用户来创建和管理容器,进一步提升容器的安全性。总的来说,本文深入浅出,适合技术人员阅读。文章内容涵盖了容器安全性的重要议题,以及解决这些问题的实用方法,对于关注容器安全的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《容器实战高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(10)

  • 最新
  • 精选
  • 我来也
    最近在使用Helm部署gitlab服务的过程中,就发现了 postgresql 和 redis 组件默认是不以root用户执行的,而是一个 User ID 为1001的用户在执行. 这样做,就需要有个k8s的 initContainer 容器先以root用户权限去修改存储目录的权限. 否则后面服务的1001号用户可能就没有权限去写文件了. ------------------ 最近遇到一个问题,想咨询一下老师: 你们有使用过 容器资源可视化隔离方案(lxcfs) 么, 有没有什么坑? 通俗点就是:让容器中的free, top等命令看到容器的数据,而不是物理机的数据。 ------------------ 我遇到的问题是在容器内执行类似`go build/test`命令时,默认是根据当前CPU核数来调整构建的并发数. 这就导致了实际只给容器分配了1个核,但是它以为自己有16个核. 然后就开16个link进程,互相之间除了有竞争,导致CPU上下文切换频繁,更要命的是把磁盘IO给弄满了.影响了整台宿主机的性能. (由于项目比较大,需要构建的文件比较多,所以很容器就让宿主机的IO达到了云服务器SSD磁盘的限制 160MB/s) 我知道在我这个场景下,可以通过指定构建命令`-p`来控制构建的并发数. (https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies) 实际也这么尝试过,效果也不错. 但问题是,我的项目会很多,每个人构建命令的写法都完全不一样,如果每个地方都去指定参数,就会比较繁琐,且容易遗漏. ------------------ 后来,我看到一篇文章: 容器资源可视化隔离的实现方法 (https://mp.weixin.qq.com/s/SCxD4OiDYsmoIyN5XMk4YA) 之前也在其他专栏中看老师提到过 lxcfs. 我在想,老师在迁移上k8s的过程中,肯定也遇到过类似的问题,不知道老师是如何解决的呢?

    作者回复: @我来也 很好的问题。我们在最开始也考虑过使用lxcfs, 当时碰到的问题也是当一批java应用从虚拟机迁移到容器平台之后,发现jvm看到的是整个宿主机的资源。 不过后来,发现大部分语言和应用都是可以加参数或者做修改来适配容器化的,因此,我们的方向是让应用也必须考虑容器和云原生的设计,因为这个是大的趋势,应用这边也是愿意接受这个改变的。 还有一点,当时我们在试lxcfs的时候发现,如果容器需要的cpu不是整数,似乎lxcfs也不能支持(不知道最新的lxcfs是不是有所改变),同时在host上需要额外维护这个lxcfs的可靠性。 这样在大部分主要应用都愿意往容器化方向走的大环境下,我们就不再考虑lxcfs了。

    2020-12-31
    8
    14
  • Sun
    user limit 是session的?每个容器及时使用相同的user id ,也不会当做累计? User resource limits dictate the amount of resources that can be used for a particular session. The resources that can be controled are: maximum size of core files maximum size of a process's data segment maximum size of files created maximum size that may be locked into memory maximum size of resident memory maximum number of file descriptors open at one time maximum size of the stack maximum amount of cpu time used maximum number of processes allowed maximum size of virtual memory available It is important to note that these settings are per-session. This means that they are only effective for the time that the user is logged in (and for any processes that they run during that period). They are not global settings. In other words, they are only active for the duration of the session and the settings are not cumulative. For example, if you set the maximum number of processes to 11, the user may only have 11 processes running per session. They are not limited to 11 total processes on the machine as they may initiate another session. Each of the settings are per process settings during the session, with the exception of the maximum number of processes.

    作者回复: @Sun 很好的问题! 我在这里指的是pam_limits, 在/etc/security/limits.conf中限制某个用户资源之后,然后在pam *_auth 和 runuser中enable pam_limits 之后,那么同一个用户即使在不同的session里,资源的限制也是累计了。 你可以在CentOS的系统里试试。

    2021-01-07
    2
    2
  • Action
    老师 docker -u 参数 是不是就是 通过user namespace 进行隔离

    作者回复: -u 只是指定了在容器启动的时候缺省用的uid/gid, 这里的uid/gid和宿主机上的是一样的,并没有建立出新的user namespace.

    2021-03-04
    3
    1
  • Action
    "由于用户 uid 是整个节点中共享的,那么在容器中定义的 uid,也就是宿主机上的 uid,这样就很容易引起 uid 的冲突。"老师这句话怎么理解,容器内uid与宿主机uid是怎么样的关系呢

    作者回复: 当容器没有使用user namespace, 那么容器中进程所属的uid/gid, 就是宿主机里uid/gid。你可以运行一下课程中的例子,从宿主机上看看容器进程的uid。

    2021-03-04
  • 争光 Alan
    老师,感谢您的分享,学到了很多知识,也感谢解答了很多疑问,有个小小的请求:能公布个微信群之类的吗?把学员加一起相互讨论问题,交流心得

    作者回复: @争光 Alan, 我还是会定期回答这个专栏中的大家的提问的。如果你有什么问题,还是在可以在这里提问的。

    2021-02-21
  • 朱新威
    老师,我发现一个很有趣的现象,有点困惑; 在宿主机上: 以root用户运行capsh --print 发现Current字段包含许多capabilities 以非root用户运行capsh --print 发现Current 字段包含零个capabilities,说明非root用户启动的进程缺省没有任何capabilities docker容器内: root用户运行capsh --print 发现Current 字段包含14个capabilities,比宿主机上少了一些,对宿主机的/etc/shadow有读写权限 非root用户运行capsh --print 发现Current字段仍然包含14个capabilities,对宿主机的/etc/shadow没有读写权限 这就让我感觉有点困惑了,原本预期容器内非root用户运行capsh --print的capabilities应该为空呀,或者知道少于root用户的capabilities吧?
    2021-01-09
    1
    4
  • janey
    Kubernetes v1.25 添加了对容器 user namespaces 的支持
    2022-11-15归属地:江苏
    3
  • JianXu
    install slirp4netns and Podman on your machine by entering the following command: $ yum install slirp4netns podman -y We will use slirp4netns to connect a network namespace to the internet in a completely rootless (or unprivileged) way.
    2022-09-08归属地:上海
  • 自然
    有个场景:用jenkins 在 openjdk镜像里 maven 编译java项目, 一个 maven目录(在主机上,而且还有其他很多工具),一个项目源码目录 需要映射到 openjdk镜像里(普通用户启动docker),jenkins 里的pipline 是大家都可以写的。 如何防止 加载主机上目录 在docker镜像里 root用户 随意修改呢( 比如 我不想他删除 主机上的maven)?
    2022-07-22
  • sunnoy
    如果容器内的用户uid在宿主机上不存在呢,这个时候描述符的分配是怎么样的呢
    2022-04-24
收起评论
显示
设置
留言
10
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部