lxd podman
在进入本文的主要主题Podman和容器之前,我需要对Linux审计功能有所了解。
什么是审计?
Linux内核具有一个有趣的安全功能,称为audit 。 它允许管理员监视系统上的安全事件,并将它们记录到audit.log中,该事件可以本地或远程存储在另一台计算机上,以防止黑客试图掩盖自己的足迹。
/ etc / shadow文件是一个常见的安全文件,需要注意,因为在该文件中添加一条记录可以使攻击者获得对系统的返回访问权限。 管理员想知道是否有任何进程修改了该文件。 您可以通过执行以下命令来执行此操作:
# auditctl -w /etc/shadow
现在让我们看看如果我修改/ etc / shadow文件会发生什么:
# touch /etc/shadow
# ausearch -f /etc/shadow -i -ts recent
type=PROCTITLE msg=audit(10/10/2018 09:46:03.042:4108) : proctitle=touch /etc/shadow
type=SYSCALL msg=audit(10/10/2018 09:46:03.042:4108) : arch=x86_64 syscall=openat
success=yes exit=3 a0=0xffffff9c a1=0x7ffdb17f6704 a2=O_WRONLY|O_CREAT|O_NOCTTY|
O_NONBLOCK a3=0x1b6 items=2 ppid=2712 pid=3727 auid=dwalsh uid=root gid=root
euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts1 ses=3 comm=touch
exe=/usr/bin/touch subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
审计记录中有很多信息,但是我强调指出,它记录了root修改了/ etc / shadow文件,并且该进程的审计UID( auid )的所有者是dwalsh 。
内核是这样做的吗?
跟踪登录UID
loginuid ,存储在/ proc / self / loginuid中 ,它是系统上每个进程的proc结构的一部分。 该字段只能设置一次; 设置后,内核将不允许任何进程将其重置。当我登录系统时,登录程序将为我的登录过程设置loginuid字段。
我的UID dwalsh是3267。
$ cat /proc/self/loginuid
3267
现在,即使我成为root用户,我的登录UID也保持不变。
$ sudo cat /proc/self/loginuid
3267
请注意,从初始登录过程派生并执行的每个过程都会自动继承loginuid。 这就是内核如何知道登录的人是dwalsh的方式。
货柜
现在让我们看一下容器。
sudo podman run fedora cat /proc/self/loginuid
3267
甚至容器进程也保留了我的loginuid。 现在让我们尝试使用Docker。
sudo docker run fedora cat /proc/self/loginuid
4294967295
为什么会有所不同?
Podman对容器使用传统的fork / exec模型,因此容器过程是Podman过程的后代。 Docker使用客户端/服务器模型。 我执行的docker命令是Docker客户端工具,它通过客户端/服务器操作与Docker守护进程通信。 然后,Docker守护程序创建容器并处理stdin / stdout与Docker客户端工具的通信。
进程的默认loginuid(在设置他们的loginuid之前)是4294967295。由于容器是Docker守护程序的后代,而Docker守护程序是init系统的子代,因此我们看到systemd,Docker守护程序和容器都处理了所有具有相同的登录标识4294967295,该审计称为未设置的审计UID。
cat /proc/1/loginuid
4294967295
如何滥用?
让我们看看如果Docker启动的容器进程修改/ etc / shadow文件会发生什么。
$ sudo docker run --privileged -v /:/host fedora touch /host/etc/shadow
$ sudo ausearch -f /etc/shadow -i
type=PROCTITLE msg=audit(10/10/2018 10:27:20.055:4569) : proctitle=/usr/bin/coreutils
--coreutils-prog-shebang=touch /usr/bin/touch /host/etc/shadow
type=SYSCALL msg=audit(10/10/2018 10:27:20.055:4569) : arch=x86_64 syscall=openat
success=yes exit=3 a0=0xffffff9c a1=0x7ffdb6973f50 a2=O_WRONLY|O_CREAT|O_NOCTTY|
O_NONBLOCK a3=0x1b6 items=2 ppid=11863 pid=11882 auid=unset uid=root gid=root
euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset
comm=touch exe=/usr/bin/coreutils subj=system_u:system_r:spc_t:s0 key=(null)
在Docker情况下,未设置auid(4294967295); 这意味着安全员可能知道某个进程修改了/ etc / shadow文件,但是身份丢失了。
如果该攻击者随后删除了Docker容器,则在谁修改了/ etc / shadow文件的系统上将没有任何跟踪。
现在,让我们看一下Podman的完全相同的场景。
$ sudo podman run --privileged -v /:/host fedora touch /host/etc/shadow
$ sudo ausearch -f /etc/shadow -i
type=PROCTITLE msg=audit(10/10/2018 10:23:41.659:4530) : proctitle=/usr/bin/coreutils
--coreutils-prog-shebang=touch /usr/bin/touch /host/etc/shadow
type=SYSCALL msg=audit(10/10/2018 10:23:41.659:4530) : arch=x86_64 syscall=openat
success=yes exit=3 a0=0xffffff9c a1=0x7fffdffd0f34 a2=O_WRONLY|O_CREAT|O_NOCTTY|
O_NONBLOCK a3=0x1b6 items=2 ppid=11671 pid=11683 auid=dwalsh uid=root gid=root
euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=3 comm=touch
exe=/usr/bin/coreutils subj=unconfined_u:system_r:spc_t:s0 key=(null)
由于Podman使用传统的fork / exec,因此可以正确记录所有内容。
这只是观察/ etc / shadow文件的简单示例,但是审核系统对于观察系统上的进程有非常强大的功能。 通过使用fork / exec容器运行时来启动容器(而不是客户端/服务器容器运行时),可以通过审核日志记录维护更好的安全性。
最后的想法
启动容器时,关于fork / exec模型与客户端/服务器模型还有许多其他不错的功能。 例如,系统功能包括:
- SD_NOTIFY:如果将Podman命令放入systemd单元文件中,则容器进程可以通过Podman在服务堆栈上返回通知,该服务已准备好接收任务。 这是在客户端/服务器模式下无法完成的工作。
- 套接字激活:您可以将已连接的套接字从systemd传递到Podman,然后传递到容器进程中以使用它们。 在客户端/服务器模型中这是不可能的。
我认为,最好的功能是以非root用户身份运行Podman和容器 。 这意味着您永远不会在主机上授予用户root特权,而在客户机/服务器模型(如Docker使用)中,您必须打开以root用户身份运行的特权守护程序的套接字以启动容器。 在那里,您只能选择守护程序中实现的安全机制,而不是主机操作系统中实现的安全机制,这是一个危险的主张。
翻译自: https://opensource.com/article/18/10/podman-more-secure-way-run-containers
lxd podman