docker容器内的默认用户的目的是什么?

时间:2018-10-22 11:00:37

标签: docker dockerfile

最近,我们被要求从镜像中删除不必要的用户,以符合PCI DSS要求2.1:

  

2.1在网络上安装系统之前,请始终更改供应商提供的默认值,并删除或禁用不必要的默认帐户。

此要求的基本原理是不要多于必要的实体,并减少可能的攻击媒介。一方面,访问者要求我们执行的操作非常合理。另一方面,容器已经在受限的命名空间环境中运行。

让我们用一些例子来描述它。 第一个是最笨的-以root身份运行,不强制执行安全性等操作。

$ docker run --rm -ti alpine
/ # cat /etc/passwd
root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
/ # su -s /bin/sh nobody
~ $ whoami
nobody
~ $ su
su: must be suid to work properly

此示例表明,我们可以轻松地从root用户切换到容器内的常规用户,这意味着任何可以侵入主机的人都可以以root用户身份进入容器并切换到代表主容器进程正在运行的用户。显然,您无法su以普通用户身份运行。当然,您可以自由使用setcap,以便为非特权用户提供更多的自由。

$ docker run --rm -ti alpine                                                
/ # apk add libcap; setcap cap_net_raw=+ep /bin/busybox
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
(1/1) Installing libcap (2.25-r1)
Executing busybox-1.28.4-r1.trigger
OK: 4 MiB in 14 packages
/ # getcap /bin/busybox
/bin/busybox = cap_net_raw+ep

但是让我们添加一些标志(实际上,这是我们所有容器的默认设置):

$ docker run --rm -ti --cap-drop all --security-opt no-new-privileges alpine
/ # su -s /bin/sh nobody
su: can't set groups: Operation not permitted
/ # apk add libcap
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
(1/1) Installing libcap (2.25-r1)
Executing busybox-1.28.4-r1.trigger
ERROR: busybox-1.28.4-r1.trigger: script exited with error 127
OK: 4 MiB in 14 packages
/ # setcap cap_net_raw=+ep /bin/busybox
unable to set CAP_SETFCAP effective capability: Operation not permitted

现在让我们做这种事情。我们可以从/etc/passwd中不存在的某个人的任意用户运行一个容器吗?

$ docker run --rm -ti --cap-drop all --security-opt no-new-privileges --user 60000:60000 alpine
/ $ whoami
whoami: unknown uid 60000
/ $ id
uid=60000 gid=60000

好的,这意味着我们可以有效地运行任何uid:gid对容器,无论它实际上是否存在于容器中。

现在,如果我们从容器中完全删除有关用户的信息,将会发生什么:

$ docker build -f- .<<EOF
FROM alpine
RUN rm -f /etc/shadow /etc/group /etc/passwd
EOF
Sending build context to Docker daemon  2.607kB
Step 1/2 : FROM alpine
 ---> 196d12cf6ab1
Step 2/2 : RUN rm -f /etc/shadow /etc/group /etc/passwd
 ---> Using cache
 ---> 7c22df16e0dd
Successfully built 7c22df16e0dd

$ docker run --rm -ti --user 60000:60000 7c22df16e0dd 
/ $ touch /etc/passwd /etc/group
touch: /etc/passwd: Permission denied
touch: /etc/group: Permission denied
/ $ adduser lol
adduser: permission denied (are you root?)
/ $ whoami
whoami: unknown uid 60000
/ $ id
uid=60000 gid=60000

但是如果删除--user 60000:60000,我们将把自己标识为有效的根:

$ docker run --rm -ti 7c22df16e0dd 
/ # touch /etc/passwd /etc/group
/ # adduser lol
passwd: unknown uid 0
/ # cat /etc/passwd
lol:x:1000:1000:Linux User,,,:/home/lol:/bin/sh
/ # su lol
/ $ whoami
lol

现在,让我们检查一下默认passwdgroup文件中是否存在与用户相关的任何内容。显然没有任何过程。但是对于文件:

$ docker run --rm -ti alpine:3.8
/ # for user in `cat /etc/passwd | grep -v -E ^root | cut -d ':' -f 1`; do find / -xdev -user $user;done
/ # 

$ docker run --rm -ti debian:9  
root@4fac719bb234:/# for user in `cat /etc/passwd | grep -v -E ^root | cut -d ':' -f 1`; do find / -xdev -user $user;done
root@4fac719bb234:/# 

$ docker run --rm -ti centos:7
[root@fa1242222f1e /]# for user in `cat /etc/passwd | grep -v -E ^root | cut -d ':' -f 1`; do echo "=== $user ==="; find / -xdev -user $user;done
=== bin ===
=== daemon ===
=== adm ===
=== lp ===
=== sync ===
=== shutdown ===
=== halt ===
=== mail ===
=== operator ===
=== games ===
=== ftp ===
=== nobody ===
=== systemd-network ===
/run/systemd/netif
/run/systemd/netif/leases
/run/systemd/netif/links
=== dbus ===

CentOS容器是唯一拥有非root用户拥有文件的容器。

一些想法和观察:

  1. --read-only --cap-drop all --security-opt no-new-privileges--user大于0运行uid:giduid:gid的容器似乎足以保护它免于获得额外的特权。
  2. root对可以是任何一对数字。
  3. Linux Standard Base仅将bin列为必需用户,其中daemonroot标记为旧用户,还有一堆可选用户,如果使用base,则没有任何意义容器图片。

问题是:

  1. 为什么所有这些用户(尤其是LSB中列出的用户)都存在于基本映像中,并且它们会增加什么风险?
  2. 除了/etc/passwd以外,我们是否可以全部删除,而保留创建其他用户作为应用程序开发人员/程序包创建者/等等的职责?
  3. 完全删除/etc/grouproot有意义吗,请记住,默认情况下,无论这些文件是否存在于系统中,容器都隐式地以uid:gid的身份运行,并且我们仍然可以使用uid> 0和gid> 0的任何{{1}}对,这实际上意味着以非root用户身份运行?

1 个答案:

答案 0 :(得分:0)

对于容器而言,此要求对我来说意义不大。 / etc / passwd文件中列出的用户是uid到username的映射。他们没有任何登录凭据,该凭据由/ etc / shadow控制。除非您自己明确启动一个容器,否则容器内不会运行任何登录名或类似的守护程序。使用uid到名称的映射具有以下优点:目录列表命令将显示用户名而不是uid。它还可以帮助应用程序安装脚本按用户名以不同用户身份运行命令,以确保安全。

顺便说一句,如果您需要安全性,我建议在容器内定义一个用户来运行您的应用程序,假设您的应用程序可以由非root用户运行。尽管容器内的root用户的权限比普通root用户要少(以防止逃脱容器的能力),但非root用户甚至受到更大的限制。无论您在容器内部运行命令的任何用户,都应在/ etc / passwd文件中定义。就是说,即使您的应用程序在容器中以root用户身份运行,该用户也受到限制,功能降低,并且被隔离到一个几乎没有破坏能力的命名空间中。就我所知,这些风险是理论上的,或者需要额外的安全漏洞才能利用。因此,如果发现将来的漏洞,以非root用户身份运行应用程序将增加一层安全性。

总的来说,这就像是熟练锁定Linux服务器和VM的人员提出的要求,但是却无法理解为什么在多用户主机上有意义的策略在容器环境中却没有意义。我会挑战它们以显示/ etc / passwd条目带来了哪些利用,而这又不涉及通过添加/ etc / shadow条目和sshd守护进程等方式将容器像VM一样对待。


要回答具体问题:

  
      
  1. 为什么所有这些用户(尤其是LSB中未列出的用户)都存在于基本映像中,并且会增加哪些风险?
  2.   

这些来自用于基本映像分发的最小OS文件系统的tar文件。我怀疑它们应该存在,并且存在依赖于这些用户的软件包安装程序。删除它们并没有真正的价值,但是破坏安装程序的确有风险。

  
      
  1. 我们可以删除除root以外的所有用户,而保留创建其他用户作为应用程序开发人员/程序包创建者/等等的练习吗?
  2.   

可以吗?是。但是对我来说,这是一个在不增加价值的情况下将潜在故障引入现有系统的安全性示例。当/ etc / passwd文件中不存在uid时,我已经看到一些应用程序中断,因此,我建议不要在没有大量测试的情况下将命令作为未列出的uid运行。

  
      
  1. 完全删除/ etc / passwd和/ etc / group是否有意义,请记住,无论系统中是否存在这些文件,默认情况下容器默认都是以root身份运行,我们仍然可以使用是否有任何uid:gid对,其中uid> 0和gid> 0,这实际上意味着以非root用户身份运行?
  2.   

我相当确定这会导致事情中断。您可以在您的环境中尝试此操作,但配置不受支持。请注意,可能在文件系统中安装了一些配置了suid / sgid功能的二进制文件,使用户能够访问这些uid / gid可能会引入安全漏洞,这些漏洞可通过维护当前使用的uid / gid的映射并以一个新的uid / gid。您猜到,执行此操作的内置功能是/ etc / passwd。