Seccomp
2 分钟阅读
简要概述
Seccomp(Secure Computing)是自 2.6.12 版本后内核的一个特性,它背后思想是限制进程可以使用的系统调用。
Linux 内核有几百个系统调用,但大多数进程并不需要它们,然而,如果一个进程受到入侵并被使用本身功能之外的其他系统调用,可能导致安全漏洞,从而危及整个系统的安全性。通过限制可以调用哪些系统调用,它是构建应用程序沙盒的关键组件。
目前存在两种主要的模式,分别是严格模式(Strict Mode)和过滤器模式(Filter Mode):
- 严格模式
除了最基本的 read ,write ,_exit ,_sigreturn 四个之外,一旦出现其他的系统调用,进程会被立刻终止 (SIGKILL)。
- 过滤器模式
允许应用程序定义一组自定义的系统调用过滤规则,过滤器模式使用BPF(Berkeley Packet Filter)语言来编写,适用于需要更精细控制的场景。
在应用中使用
严格模式
- 未使用 seccomp 编译执行
cat << EOF >> /tmp/test1.c
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/socket.h>
int main(int argc, char* argv[]) {
printf("Install seccomp\n");
printf("Creating socket\n");
int sock = socket(AF_INET, SOCK_STREAM, 0);
return 0;
}
EOF
$ gcc -o test1 test1.c
$ ./test1
Install seccomp
Creating socket
$
此时编译执行成功。
- 添加 seccomp 代码使用严格模式
cat << EOF >> /tmp/test2.c
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <linux/seccomp.h>
int main(int argc, char* argv[]) {
printf("Install seccomp\n");
// 使用 Seccomp 严格模式
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
printf("Creating socket\n");
int sock = socket(AF_INET, SOCK_STREAM, 0);
return 0;
}
EOF
$ gcc -o test2 test2.c
$ ./test2
Install seccomp
Creating socket
Killed
$
此时编译成功,执行应用在调用创建 socket 时马上被 KILL。
过滤器模式
cat << EOF >> /tmp/test3.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <stddef.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
int main() {
printf("Install seccomp\n");
// 使用 Seccomp 过滤器模式
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER);
// 定义允许的系统调用规则
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)), // 载入系统调用号
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), // 允许socket系统调用
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), // 其他系统调用将导致程序终止
};
struct sock_fprog prog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter,
};
// 设置 NO_NEW_PRIVS 标志
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
// 加载 Seccomp 规则
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
printf("Creating socket\n");
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
printf("Socket created successfully\n");
return 0;
}
EOF
$ gcc -o test3 test3.c
$ ./test3
Install seccomp
Creating socket
Socket created successfully
$
此时编译执行成功。
在 Kubernetes 上使用
配置 Pod securityContext 启用
其中可配置的参数参考 Pod SeccompProfile。
---
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/kube-image-repo/busybox:1.35.0
name: nginx
resources: {}
args:
- /bin/sh
- -c
- "sleep 3600"
securityContext:
allowPrivilegeEscalation: false
securityContext:
runAsNonRoot: false
runAsUser: 99
seccompProfile:
type: Localhost
localhostProfile: profiles/audit.json
这里使用了宿主 “profiles/audit.json” 上的 seccomp 配置,这里的路径是在 kubelet 工作目录下,如:"/var/lib/kubelet"。
启用容器默认 seccomp 策略
在 kubelet 添加以下启动参数,同时 feature 未被禁用:
--seccomp-default=true
启用 RuntimeDefault 作为所有工作负载的默认 seccomp 配置文件。
检查当前 seccomp 启用的容器
crictl inspect 2b6a707db3c26 | jq .info.runtimeSpec.linux.seccomp
如果结果为 “null” 则说明该容器未使用到 seccomp 技术。
null
特别的当启用特权模式的 Pod 是无法使用 seccomp 的,既然:
securityContext:
privileged: true
最后修改 2023.12.06: chore: update seccomp (26cd6cd)