暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用seccomp强化Docker和Kubernetes安全

云原生CTO 2021-02-08
2581

       点击上方 云原生CTO,选择设为星标

               优质文章,每日送达

----------------------------------------------

     「【只做懂你de云原生干货知识共享】」

使用seccomp强化Docker和Kubernetes安全

关于容器安全性存在很多误解-许多人认为容器默认情况下是安全的,不幸的是,这不是事实。有很多工具可以帮助您提高容器的安全性,从而也可以提高Docker和Kubernetes的安全性。强化它们的方法之一是应用适当的seccomp配置文件。如果您不知道seccomp它是什么,请继续阅读并了解它是什么以及如何使用它来保护您的Docker和Kubernetes免受安全威胁!

seccomp是什么?

如果您使用Docker或Kubernetes已有一段时间,您可能会听说过term seccomp,但是有可能,您还没有真正深入研究这个晦涩的工具,对吗?

最简单,最容易理解的定义seccomp可能是“系统调用防火墙”。seccomp本质上是一种限制进程可能进行的系统调用的机制,因此可以阻止来自某些IP的数据包,也可以阻止进程向CPU发送系统调用。

太酷了,但是这如何帮助我们使系统更安全?Linux内核有很多syscall(数百个),但是任何给定的进程都不需要它们。但是,如果进程可能受到危害并被诱骗使用其中一些系统调用,则可能会导致整个系统出现严重的安全问题。因此,限制哪个系统调用进程可以大大减少内核的攻击面。

现在,如果您正在运行任何最新的Docker版本(1.10或更高版本),那么您已经在使用seccomp。您可以使用docker info或通过查看来检查该内容/boot/config-*:

~ $ docker info
...
 Security Options:
  apparmor
  seccomp
   Profile: default  # default seccomp profile applied by default
...

~ $ grep SECCOMP /boot/config-$(uname -r)
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP_FILTER=y
CONFIG_SECCOMP=y

好吧,太好了!我们已经拥有了seccomp,一切都是安全的,我们不需要弄乱任何东西,对吧?嗯,不完全是-您可能有很多理由想要弄脏您的手并深入研究seccomp...

为什么要麻烦创建一个?

seccompDocker中的默认配置文件通常可能“足够好”,如果您没有使用它的经验,那么“改进”或自定义它可能不是您时间的最佳选择。但是,出于某些原因,您可能有足够的动力来更改默认seccomp配置文件:

有时会发现安全漏洞。这是不可避免的,进一步限制默认seccomp配置文件可能会降低安全漏洞影响您的应用程序的机会。这样的事件之一是CVE 2016-0728,它允许用户使用keyctl()syscall提升特权。在此事件之后,此系统调用现在已被默认seccomp配置文件阻止,但将来可能会有更多此类漏洞利用...

限制seccomp配置文件的另一个原因是,如果某些子系统存在安全漏洞,攻击者将无法从您的容器中利用它,因为相关的系统调用已被阻止。该子系统可以是依赖项,库或您无法控制的系统的某些部分。您可能也没有办法解决该子系统中的问题,并防止问题被利用,您需要在不同的层(例如,seccomp配置文件)中将其阻止。

当您处理PII数据或构建关键任务应用程序(例如医疗保健或电网中使用的软件)时,潜在的利用和安全漏洞就变得更加重要。在这些情况下,任何一点安全改进措施和自定义seccomp配置文件都是值得的。

除了所有这些特定原因之外,限制容器可以使用的系统调用会限制可以使用的攻击媒介,例如Docker上游镜像中的后门或应用程序中的可利用错误。

自定义配置文件

现在,如果我们确定有充分的理由来更改seccomp个人资料,那么我们将如何实际去做呢?编写seccomp过滤器的一种方法是使用Berkeley数据包过滤器(BPF)语言。使用这种语言并不是很简单或不方便。幸运的是,我们不必使用它,而是可以编写由编译为profile的JSON libseccomp。这种配置文件的简单/最小示例如下所示:

{
    "defaultAction""SCMP_ACT_ERRNO",
    "syscalls": [
        {
            "names": [
                "accept",
                "chown",
                "kill",
                "mmap",
                ...
            ],
            "action""SCMP_ACT_ALLOW",
   "args": [],
   "comment""",
   "includes": {},
   "excludes": {}
        }
    ]


通常,首选使用白名单而不是黑名单,并明确列出允许系统调用的列表,并禁止其他任何调用。这正是上述配置文件的功能-默认情况下,它将使用「SCMP_ACT_ERRNO」导致「Permission denied」所有系统调用的操作。对于确实要允许的名称,我们列出了它们的名称并指定了「SCMP_ACT_ALLOW」操作。

这些JSON配置文件可以使用很多选项,并且可能变得非常复杂,因此上面的配置文件实际上已被精简到最低限度。要查看真实的配置文件看起来如何,可以在此处查看Dockers配置文件。

现在我们对seccomp配置文件有了更多的了解,让我们玩Docker。不过,在尝试应用任何自定义配置文件之前,让我们先做一点实验并覆盖seccomp默认值:

#运行时不使用seccomp配置文件:
~ $ docker run --rm -it --security-opt seccomp=unconfined alpine sh
# 重新启动 工作
#运行默认的seccomp配置文件
~ $ docker container run --rm -it alpine sh
#重启#不起作用

在上方,我们可以看到如果seccomp完全禁用-任何可用的syscall都会发生什么,这允许容器中的用户(除其他外)重新引导主机。在—security-opt seccomp=... 在此实例中用于禁用seccomp。这也是应用自定义配置文件的方式,因此让我们构建并应用我们自己的自定义配置文件。

这不是一个好主意,从头开始,所以我们将修改现有的docker的个人资料(上面提到的),我们将通过消除制约了一点chmod,fchmod和fchmodat系统调用,从而有效地拒绝向使用chmod命令。这可能不是最合理的更改或“改进”,但出于演示目的,它很好用:

#使用自定义seccomp配置文件运行(禁止chmod)
〜 $ docker容器运行--rm -it --security-opt seccomp = no-chmod.json alpine sh
/ # whoami

/ # chmod 777 -R / etc
chmod:/ etc:不允许操作

在此代码段中,我们从中加载自定义配置文件,no-chmod.json然后尝试进行chmod整本/etc。我们可以看到这在容器中导致了什么-在中尝试运行任何chmod结果Operation not permitted。

使用这个简单的“ no chmod”配置文件,很容易选择应阻止的系统调用。但是,总的来说,选择可以阻止或不能阻止的内容并不是那么简单。您可以进行有根据的猜测,但是通过阻塞系统调用可能会阻塞过多而又没有足够的风险,这会阻止您的应用程序正确运行,但还会丢失一些可以并且应该被阻塞的系统调用。

选择阻止哪个系统调用的唯一可行方法是调用跟踪。跟踪系统调用的一种方法是使用strace:

~ $ strace -c -f -S name chmod 2>&1 1>/dev/null | tail -n +3 | head -n -2 | awk '{print $(NF)}'
syscall
----------------
access
arch_prctl
brk
close
execve
fstat
mmap
mprotect
munmap
openat
pread64
read
write

上面的命令为我们提供了命令使用的所有系统调用的列表(chmod在本例中),我们可以从中选择阻止/允许的操作。如果这个strace命令对您来说太复杂了,那么它也strace -c ls将起作用,它会输出一些额外的信息,例如时间和呼叫次数。我们显然不能阻止所有这些操作,因为这会使我们的容器无法使用,因此最好查找所有这些操作,例如使用此syscall表。

那Kubernetes呢?

在标题和介绍中,我还提到了Kubernetes,但到目前为止,我们仅谈论Docker。那么,seccompKubernetes世界的情况如何?不幸的seccomp是,默认情况下,默认情况下不使用Kubernetes ,因此除了一些非常危险的系统调用之外,系统调用未被过滤。因此,使用Docker,您可以不用配置任何配置文件而只使用默认值,但是在Kubernetes中,实际上并没有阻止某些安全问题被利用的方法。

我们如何“解决”这个问题?这取决于您所使用的Kubernetes的版本-对于1.19之前的版本,您将需要对Pod应用注释。看起来像这样:

apiVersion: v1
kind: Pod
metadata:
  name: some-pod
  labels:
    app: some-pod
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: localhost/profiles/some-profile.json
spec:
    ...

对于1.19(我们将在此处重点介绍)及更高版本,seccomp配置文件是GA功能,您可以使用pod中的seccompProfilesection in securityContext。这样的pod的定义如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: some-pod
  labels:
    app: some-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/some-profile.json
  containers:
    ...

现在我们知道了如何在Kubernetes上解决它,现在该进行一些演示了。为此,我们将需要一个集群-在这里,我将使用KinD(Docker中的Kubernetes)来设置最小的本地集群。另外,seccomp在启动集群之前,我们还将需要所有配置文件,因为这些配置文件需要在集群节点上可用。因此,集群本身的定义如下:

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
  extraMounts:
  - hostPath: "./profiles"
    containerPath: "/var/lib/kubelet/seccomp/profiles"

这定义了单节点群集,该群集将本地profiles目录安装到位于的节点上/var/lib/kubelet/seccomp/profiles。那我们放在这个profiles目录里呢?就本示例而言,我们将使用3个配置文件:Dockers默认配置文件和先前使用的配置文件,另外还有一个所谓的“ audit” “ complain”配置文件。

我们将从审核配置文件开始。这个不允许/阻止任何系统调用,而只是syslog在某些命令/程序使用它们时将它们记录到日志中。这对于调试和探索应用程序的行为以及查找可能或无法阻止的系统调用都非常有用。此配置文件的定义实际上只是一行,看起来像这样:

# ./profiles/audit.json
{
    "defaultAction""SCMP_ACT_LOG"
}

我们将需要做的另一件事是-显然是pod。该Pod将具有单个Ubuntu容器,该容器将运行ls以触发一些系统调用,然后进入睡眠状态,因此它不会终止并重新启动:

# ./pods/audit.yaml
apiVersion: v1
kind: Pod
metadata:
  name: audit-seccomp
  labels:
    app: audit-seccomp
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/audit.json
  containers:
  - name: test-container
    image: ubuntu
    command: [ "/bin/bash""-c""--" ]
    args: [ "ls /; while true; do sleep 30; done;" ]
    securityContext:
      allowPrivilegeEscalation: false

顺便说一句,让我们构建集群并应用第一个配置文件:

~ $ tree .
.
├── kind.yaml
├── pods
│   ├── audit.yaml 
│   ├── default.yaml
│   └── no-chmod.yaml
└── profiles
    ├── audit.json
    └── no-chmod.json

~ $ kind create cluster --image kindest/node:v1.19.4 --config=kind.yaml
~ $ kubectl apply -f pods/audit.yaml
~ $ tail /var/log/syslog

Nov 25 19:38:18 kernel: [461698.749294] audit: ... syscall=21 compat=0 ip=0x7ff8f8412d5b code=0x7ffc0000    # access
Nov 25 19:38:18 kernel: [461698.749306] audit: ... syscall=257 compat=0 ip=0x7ff8f8412ec8 code=0x7ffc0000   # openat
Nov 25 19:38:18 kernel: [461698.749315] audit: ... syscall=5 compat=0 ip=0x7ff8f8412c99 code=0x7ffc0000     # fstat
Nov 25 19:38:18 kernel: [461698.749317] audit: ... syscall=9 compat=0 ip=0x7ff8f84130e6 code=0x7ffc0000     # mmap
Nov 25 19:38:18 kernel: [461698.749323] audit: ... syscall=3 compat=0 ip=0x7ff8f8412d8b code=0x7ffc0000     # close

我们在目录中使用KinD群集定义,pods目录和profiles目录执行上述示例。我们首先使用kind命令从定义中创建集群。然后,我们应用audit-seccomp使用audit.yaml配置文件的容器。最后,我们检查syslog消息以查看audit-seccomppod记录的审核消息。这些消息中的每一个都包含syscall=...,用于指定syscall ID(用于x86_64体系结构),可以将其转换为每行末尾注释中的名称。现在,我们确认它seccomp可以正常工作,我们可以应用真实配置文件(Dockers默认设置)。为此,我们将使用不同的pod:

# pods/default.yaml
apiVersion: v1
kind: Pod
metadata:
  name: default-seccomp
  labels:
    app: default-seccomp
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: test-container
    image: r.j3ss.co/amicontained
    command: [ "/bin/sh""-c""--" ]
    args: [ "amicontained" ]
    securityContext:
      allowPrivilegeEscalation: false

我们在这里做了一些更改。即,我们更改了seccompProfile指定RuntimeDefault类型的部分,还将映像更改为amicontained,这是一个容器自检工具,它将告诉我们哪些系统调用被阻止,以及一些其他有趣的安全信息。应用此pod后,我们可以在日志中看到以下内容:

~ $ kubectl apply -f pods/default.yaml
~ $ kubectl logs default-seccomp
Container Runtime: docker
Has Namespaces:
 pid: true
 user: false
AppArmor Profile: unconfined
Capabilities:
 BOUNDING -> chown dac_override fowner fsetid kill setgid setuid setpcap net_bind_service net_raw sys_chroot mknod audit_write setfcap
Seccomp: filtering
Blocked Syscalls (61):
 PTRACE SYSLOG SETPGID SETSID USELIB USTAT SYSFS VHANGUP PIVOT_ROOT _SYSCTL ACCT SETTIMEOFDAY MOUNT UMOUNT2 SWAPON SWAPOFF REBOOT SETHOSTNAME SETDOMAINNAME IOPL IOPERM CREATE_MODULE INIT_MODULE
    DELETE_MODULE GET_KERNEL_SYMS QUERY_MODULE QUOTACTL NFSSERVCTL GETPMSG PUTPMSG AFS_SYSCALL TUXCALL SECURITY LOOKUP_DCOOKIE CLOCK_SETTIME VSERVER MBIND SET_MEMPOLICY GET_MEMPOLICY KEXEC_LOAD ADD_KEY
    REQUEST_KEY KEYCTL MIGRATE_PAGES UNSHARE MOVE_PAGES PERF_EVENT_OPEN FANOTIFY_INIT NAME_TO_HANDLE_AT OPEN_BY_HANDLE_AT SETNS PROCESS_VM_READV PROCESS_VM_WRITEV KCMP FINIT_MODULE KEXEC_FILE_LOAD BPF
    USERFAULTFD PKEY_MPROTECT PKEY_ALLOC PKEY_FREE

这表明Dockers的默认配置文件将阻止上述61个系统调用。如果我们不包括该类型的seccompProfile部分,RuntimeDefault则只有22(如果您对此不信任我,可以自行测试)。我认为这是对安全性的极大改进,实际花费很少。如果我们确定默认值不够好或需要进行一些修改,则可以部署自定义配置文件。在这里,我们将使用“ no chmod”配置文件和以下窗格来证明这一点:

# pods/no-chmod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: no-chmod-seccomp
  labels:
    app: no-chmod-seccomp
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/no-chmod.json
  containers:
  - name: test-container
    image: ubuntu
    command: [ "/bin/bash""-c""--" ]
    args: [ "touch test; chmod +x test; while true; do sleep 30; done;" ]
    securityContext:
      allowPrivilegeEscalation: false

该pod与之前显示的“审核”pod非常相似。我们只是切换localhostProfile到指向不同的文件,然后将容器args更改为包括chmod命令,以便我们可以看到并确认修改后的seccomp配置文件按预期工作:

~ $ kubectl apply -f pods/no-chmod.yaml
~ $ kubectl logs no-chmod-seccomp
chmod: changing permissions of 'test': Operation not permitted

日志显示了预期的结果-seccomp配置文件阻止了chmod对测试文件的尝试并返回Operation not permitted。这表明根据个人喜好或需求调整配置文件非常简单。

不过,在修改这些默认配置文件时请务必小心-如果最终阻塞太多,而pod /容器无法启动,则pod会处于Error状态,但日志中将看不到任何东西,事件中也没有任何用处kubectl describe pod …,因此在调试seccomp相关问题时请记住这一点。

结论

即使在阅读本文之后,修改或创建自己的seccomp配置文件也可能不是您的重中之重。但是,重要的是要意识到这一强大的工具并能够在需要时使用它(例如,在Kubernetes中),因为默认情况下它没有默认实施,而这很容易成为大安全性问题。出于这个原因,我建议-至少-启用“审核”配置文件,以便您可以监视正在使用的syscall并使用该信息稍后创建自己的配置文件或验证默认设置是否适用于您的应用程序。

另外,如果您从本文中删除了任何内容,那么它应该seccomp是重要的安全层,并且永远不要运行容器uncontained。

参考文献

https://itnext.io/hardening-docker-and-kubernetes-with-seccomp-a88b1b4e2111

我等的船还不来 我等的人还不明白 寂寞默默沉没沉入海 回忆回来 你已不在「——伤心太平洋 任贤齐」

【一个懂你的云原生知识共享平台】

「欢迎扫描下方二维码关注」


文章转载自云原生CTO,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论