Docker 和 Kubernetes 中的 root 与 privileged

k8s技术圈

共 2656字,需浏览 6分钟

 ·

2020-11-16 23:39

我们大多数熟悉 Unix 类系统的人,都习惯于通过使用 sudo 来随意提升自己的权限,成为 root 用户。我们在使用 Docker 容器的过程中知道,他提供了一个 --privileged 的参数,其实它与随意使用 sudo 有很大的不同,它可能会让你的应用程序面临不必要的风险,下面我们将向你展示这与以 root 身份运行的区别,以及特权的实际含义。

作为 Root 运行

Docker 允许在其宿主机上隔离一个进程、capabilities 和文件系统,但是大多数容器实际上都是默认以 root 身份运行。这里我们拿 DockerHub 上几个比较流行的镜像来进行说明。

Postgres:

$ docker run -it postgres
# whoami
root
# id -u
0

Couchbase:

$ docker run -it couchbase sh
# whoami
root
# id -u
0

Alpine:

$ docker run -it alpine sh
# whoami
root
# id -u
0

我们可以看到这几个镜像默认都是以 root 身份运行,这样当然更容易调试,特别是当你要 exec 到容器中时,但最好的情况还是应该避免以 root 身份运行。

避免以 root 运行

虽然在容器内以 root 身份运行是很正常的,但如果你想加固你的容器,还是应该避免这样做。首先,,其次,容器将成为运行 Docker 命令的同一用户命名空间的一部分,如果容器能够逃逸,它将可以访问相同的资源,比如 volumes 和 sockets。

这里我们有两种方法可以避免以 root 身份运行。

  • 通过在 Dockerfile 文件中指定 user 用户:
// DockerfileFROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
  • 运行容器的时候覆盖用户 ID:
$ docker run -it --user 4000 postgres sh
# whoami
whoami: cannot find name for user ID 4000
# id -u
4000

特权模式

--privileged 标志可以将我们前面看到的0的用户 ID 直接映射到主机的用户 ID 0上,使其可以不受限制地访问任何自己的系统调用。在正常的操作中,即使容器内有 root,Docker 也会限制容器的 Linux Capabilities 的,这种限制包括像 CAP_AUDIT_WRITE 这样的东西,它允许覆盖内核的审计日志--你的容器化工作负载很可能不需要这个 Capabilities。所以特权只应该在你真正需要它的特定设置中使用,简而言之,它给容器提供了几乎所有主机(作为root)可以做的事情的权限

本质上,它就是一个免费的通行证,可以逃避容器所包含的文件系统、进程、sockets  套接字等,当然它有特定的使用场景,比如在很多 CI/CD 系统中需要的 Docker IN Docker 模式(在 Docker 容器内部需要 Docker 守护进程),以及需要极端网络的地方。即便如此,也有一些方法可以避免使用特权模式,例如,我们可以使用谷歌创建的名为 Kaniko 的工具来替代特权模式的容器。

下面让我们看一个使用 Ubuntu 镜像的例子。

在没有特权的情况下:

$ docker run -it ubuntu sh
# whoami
root # 注意这里,仍然是 root 用户
# id -u
0
# hostname
382f1c400bd
# sysctl kernel.hostname=Attacker
sysctl: setting key "kernel.hostname": Read-only file system  # Yet we can't do this

特权模式:

$ docker run -it --privileged ubuntu sh
# whoami
root. # Root again
# id -u
0
# hostname
86c62e9bba5e
# sysctl kernel.hostname=Attacker
kernel.hostname = Attacker # Except now we are privileged
# hostname
Attacker

如果我们在 Kubernetes 中要使用的话可以使用 SecurityContext 来进行配置:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      privileged: true

此外 Kubernetes 还包含一个名为 PodSecurityPolicy 的资源对象,它是一个准入控制器(Kubernetes 在允许容器进入集群之前会它进行检查),强烈建议的一项策略就是配置不允许特权模式的 Pod。

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: example
spec:
  privileged: false  # 禁止特权模式

总结

最后希望你对 root 用户和 --privileged 标志以及它们与宿主机的关系有了更多的认识。我们可以通过不以 root 用户运行、不以特权模式运行以及添加 SecurityContextPodSecurityPolicy 来实现更高的容器安全。

原文链接:https://itnext.io/docker-and-kubernetes-root-vs-privileged-9d2a37453dec


 点击屏末  | 即刻学习

浏览 160
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报