假设这样一个场景:
生产环境中,Node 都需要通过堡垒机登录,但是 kubectl 是可以直接在个人电脑上登录的。
这种场景下,我想要通过 kubectl 登录到 K8S 集群里的 Node,可以实现吗?
可以的!
本质上是利用容器(runC)的弱隔离(共享内核,Cgruop 等实现进程隔离)实现的权限逃逸。
如果贵司使用的一些商业容器平台(如:openshift,rancher)等,可能默认安装时就会通过 PSP scc 或 policy 等预先屏蔽掉这层隐患。
但是如果是原生的 Kubernetes, 往往下面的办法是可行的。
先说本质,本质上就是:
容器(runC)是弱隔离
那么,加入你没有对容器的权限做进一步的限制,我是可以通过运行一个特权容器,直接进入到其所在的 node 上的。
适用于 K8S 1.25 之前的版本。
步骤很简单,就是创建上文说的这么一个特权容器,通过 nsenter
command 进入 node shell。示例 yaml 如下:
apiVersion: v1
kind: Pod
metadata:
labels:
run: nsenter-v0l86q
name: nsenter-v0l86q
namespace: default
spec:
containers:
- command:
- nsenter
- --target
- "1"
- --mount
- --uts
- --ipc
- --net
- --pid
- --
- bash
- -l
image: docker.io/library/alpine
imagePullPolicy: Always
name: nsenter
securityContext:
privileged: true
stdin: true
stdinOnce: true
tty: true
hostNetwork: true
hostPID: true
restartPolicy: Never
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- effect: NoExecute
operator: Exists
直接 kubectl apply -f node-shell.yaml
即可进入 node shell。
上面的 yaml,关键有这么几点:
进入 node shell 的命令:nsenter --target 1 --mount --uts --ipc --net --pid -- bash -l
,在 Linux 系统里, nsenter 是一个命令行工具,用于进入到另一个 namespace 。 譬如, nsenter -n -t 1 bash
就是进入到 pid 为 1 的进程所在的网络 namespace 里。
以及进入 node shell 的权限:
hostPID: true
共享 host 的 pidhostNetwork: true
共享 host 的网络privileged: true
: PSP 权限策略是 privileged
, 即完全无限制。进入 node shell 的 pod 后, 效果如下:
这里推荐 2 个工具,可以更方便地进入 node shell。
可以通过 kubectl 插件管理工具 krew 安装 node-shell.
如下:
# 安装工具
kubectl krew install node-shell
# 进入 node shell
Kubectl node-shell <node-name>
Kubernetes 图形化管理工具 - Lens 也有相关功能。
具体使用方法如下:
上文介绍了通过 kubectl 命令以 root 权限进入 node shell 的方法,非常简单,实际上在大多数的原生 Kubernetes 上都生效。
这个命令实际上是一定程度上利用了安全上的未加固配置。
这里最后还是建议大家除了对 OS 进行安全加固,对 Kubernetes 也要按照安全最佳实践进行安全加固。(典型的就是起码 PSP 等 policy 不要设置为 privileged
, 而是设置为 Baseline
或 Restricted
)
注意安全!🚧🚧🚧
EOF
本文由博客一文多发平台 OpenWrite 发布!