Docker 和 Kubernetes 中的 root 与 privileged
我们大多数熟悉 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 用户运行、不以特权模式运行以及添加 SecurityContext
和 PodSecurityPolicy
来实现更高的容器安全。
“原文链接:https://itnext.io/docker-and-kubernetes-root-vs-privileged-9d2a37453dec
”