在Fargate上尝试共享PID命名空间

宣布了在ECS on Fargate中新增的Linux控制功能,现在可以共享PID(进程ID)命名空间。我立刻进行了尝试。之前在Fargate中保护难以实现的运行时保护现在可能会得到进展,但反过来,一些以前被隔离的内容可能会被突破,所以我也确认了相关的风险。

总结

当您在Fargate上设置PID命名空间共享(pidMode = task),

    • 他コンテナプロセスの監視/干渉ができる

いままで出来なかった監視コンテナ追加でのランタイム保護が可能になった

逆にセキュリティ上のリスクも上る

Fargateコンテナのrootユーザで出来る侵害が大幅に広がる

可能な限り一般ユーザ(non-root)でコンテナ実行

rootで動かす場合も、監視コンテナ以外にはSYS_PTRACEは絶対に付与してはいけない

他コンテナへのアクセス可否

root+SYS_PTRACEroot一般ユーザ例プロセス確認◯◯◯psコマンドプロセスKILL◯◯☓kill {pid}ファイルにアクセス◯◯☓/proc/{pid}/root でアクセスシステムコール監視◯☓☓プロセス起動、ファイルI/O ソケット等の監視環境変数(クレデンシャル)に
アクセス△※☓(?)☓※proc/{pid}/environ からは見えないが、システムコール経由で露出の可能性あり通信の監視◯※☓(?)☓※tcpdumpは出来ないが、システムコールの引数として見える

PID命名空间共享的含义是

在Linux中,进程ID(PID)通常从1开始,每次启动一个进程,都会自动分配一个唯一的ID。这就是PID(进程ID)的命名空间。
然而,在容器中,每个容器拥有单独的PID编号,从容器内部来看,进程以PID=1启动。当有子进程时,它们将在与主机不同的命名空间中分配编号,例如2、3等等。这就是PID命名空间的分离。
虽然这种隔离对于容器之间的隔离非常有用,但反过来,如果希望干扰其他容器,这样的隔离就会成为障碍。
ECS通过共享命名空间,特意打破了这一点,在任务中配置了相同的PID命名空间。
(在常规的Docker中已经可以实现,在Fargate中不能实现)

PID命名空间的共享有什么好处?

希望在生产环境中实施运行时保护,以监视和阻断运行进程是否受到侵害或者采取了可疑行为(例如访问无关文件、启动子进程等)。虽然在正常的Linux环境下可以使用AppArmor、SELinux、eBPF等手段,但在Fargate环境中无法使用这些方法。唯一可行的方案是通过ptrace来监视系统调用,但由于PID命名空间仅限于同一进程间使用,因此只能采用将监视进程变成原始进程(如nginx等)的父进程的不切实际的应用方法。

通过新添加的PID命名空间共享功能,现在可以看到其他容器的进程,因此可以执行类似于“将监视容器添加到任务以进行运行时保护”这样的方法。

考试环境

我在github的fargate-pid-ns-share-sample项目中放置了一个示例。这是将常见的Web(nginx)、App(php-fpm)和监控容器(alpine)的3个容器放入一个任务中,并在任务定义中设置了”pidMode”: “task”的实例。此外,监控容器(alpine)还添加了SYS_PTRACE能力。

考试成绩 (shì jì)

所有以下这一切由alpine容器的root用户操作。
对于系统调用监视,可以通过任务定义添加SYS_PTRACE权限,其他情况只要是root用户就可操作。

确认PID命名空间的共享状态。

我能够确认实际上能够共享。通常情况下,每个主要进程的PID都会变为1,但是这里的PID值却是7、19和54,而不是1。

$ ps axuw
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    7 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
   19 101       0:00 nginx: master process nginx -g daemon off;
   25 82        0:00 php-fpm: pool www
   26 82        0:00 php-fpm: pool www
   52 101       0:00 nginx: worker process
   53 101       0:00 nginx: worker process
   54 root      0:00 sleep infinity
  123 root      0:00 sh  ←これが今操作してるプロセス(@alpineコンテナ)
  124 root      0:00 ps axuw
※SSMの行は省略

监视他容器的系统调用

我在alpine容器中使用strace工具附加到php-fpm容器进程,确认可以跟踪系统调用。

他正在监视进程启动。

我在PHP中执行了shell_exec(’cat /etc/passwd’)。我清楚地看到了clone()→execve()的过程。

#pid 25 = php-fpmワーカープロセスにアタッチ
$ strace -f -p 25 -e execve,clone
strace: Process 25 attached
...
clone(child_stack=0x7fff85c11268, flags=CLONE_VM|CLONE_VFORK|SIGCHLDstrace: Process 222 attached
 <unfinished ...>
[pid   222] execve("/bin/sh", ["sh", "-c", "cat '/etc/passwd'"], 0x7f41081f45d0 /* 24 vars */ <unfinished ...>
[pid    25] <... clone resumed>)        = 222
[pid   222] <... execve resumed>)       = 0
[pid   222] execve("/bin/cat", ["cat", "/etc/passwd"], 0x7f940d2031d0 /* 24 vars */) = 0

文件访问监控

访问不存在的文件 hogehoge.php 的示例。

$ strace -p 25 -e trace=%file
strace: Process 25 attached
...
lstat("/var/www/html/hogehoge.php", 0x7fff85c11520) = -1 ENOENT (No such file or directory)
stat("/var/www/html", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0
stat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("", 0x7fff85c13740)                = -1 ENOENT (No such file or directory)

杀死他的容器进程

确认可以从alpine环境中杀死nginx和php的子进程。
当然,如果杀死必需容器的主进程,将导致任务终止。

$ ps axuw
PID   USER     TIME  COMMAND
...
    7 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
   19 101       0:00 nginx: master process nginx -g daemon off;
   25 82        0:00 php-fpm: pool www
   26 82        0:00 php-fpm: pool www  ←これをKill
   52 101       0:00 nginx: worker process
   53 101       0:00 nginx: worker process  ←これをKill
...

$ kill 26 #php-fpm子プロセスをKILL
$ kill 53 #nginx子プロセスをKILL

$ ps auxw
PID   USER     TIME  COMMAND
    7 root      0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
   19 101       0:00 nginx: master process nginx -g daemon off;
   25 82        0:00 php-fpm: pool www
   52 101       0:00 nginx: worker process
  125 82        0:00 php-fpm: pool www  ←ワーカーが再生成された
  126 101       0:00 nginx: worker process  ←ワーカーが再生成された

访问他的容器文件

通过/proc/{pid}/root路径,可以直接进行操作,包括写入。

#pid 7 = php-fpmのファイルシステム
$ ls /proc/7/root/var/www/html/
test.php

$ echo '<?php echo "test2";' > /proc/7/root/var/www/html/test2.php
$ cat /proc/7/root/var/www/html/test2.php
<?php echo "test2";

他访问容器的环境变量

普通的情况下,可以通过/proc/{pid}/environ来查看启动时的环境变量。但是,由于bug或者设计问题,在与其他容器的进程交互时无法正常工作。无法成功使用gdb,并且也想不到好的方法。不过,实际上在使用凭证进行外部通信时,可以通过系统调用读取相应的信息。由于泄露其他容器的凭证会造成严重的安全风险,所以除了监控容器之外,其他容器都应以普通用户身份运行,并且至少不要赋予SYS_PTRACE权限,这样才能确保安全运维。

在environ下,会显示出令人困惑的内容。

$ cat /proc/7/environ
 master process (/usr/local/etc/php-fpm.conf)

使用tcpdump来监视他的容器进程

尽管我尝试了一下,但是tcpdump似乎不行。由于网络命名空间是分离的,所以当然无法使用。
然而,只要系统调用可见,通信内容也是可见的,存在风险。

广告
将在 10 秒后关闭
bannerAds