某天,
某魚說要吃瞄,
於是......
李國寶:邊緣計算k8s集群SuperEdge初體驗
zhuanlan.zhihu.com
圖標
照着上一篇文章來說,我這邊邊緣計算集群有一堆節點。
每個節點都在不同的網絡環境下。
他們的共同點都是可以訪問內網,
部分是某雲學生主機,
部分是跑在家庭網絡環境下的虛擬機,
甚至假設中還有一些是樹莓派之類的機器。
所以他們另一個共同點是,基本都沒有公網IP。
這樣一來,我要實現遠程登錄到某些節點搞事的時候,
只有內網穿透這一條路子了。
使用frp進行內網穿透 - 少數派
sspai.com
圖標
https://github.com/fatedier/frp
github.com
內網穿透倒沒什么,在公司使用這貨長期跑了兩年垮大洋穿透也很穩定。
只是...
只是...
只是...
要一台台機器配置一次,要維護一個穩定的公網服務器作為橋接。
就是...麻煩了點。
然后想了下。
當前的kube superedge邊緣計算集群本身就實現了4層和7層的內網穿透,
理論上直接使用它的能力也可以做到遠程登錄的。
於是開始研究了一下怎么實現在只有kubectl環境的機器上,
直接登錄k8s容器集群的node節點。
搜了一波之后首先發現的是這個項目。
A kubectl plugin to SSH into Kubernetes nodes using a SSH jump host Pod
github.com
看描述和需求來說,完全符合我的要求。
$ kubectl krew install ssh-jump
照着教程配置好插件,裝好環境之后實踐了一下。
....
一切都好,就是連不上去。
蛋疼了...
接着又找了一波,發現了一個Redhat老哥的博客。
A consistent, provider-agnostic way to SSH into any Kubernetes node
完美。
我想要的就是這個。
看了下插件代碼。luksa/kubectl-plugins看了下插件代碼。
https://github.com/luksa/kubectl-plugins/blob/master/kubectl-ssh
github.com
#!/usr/bin/env bash
set -e
ssh_node() {
node=$1
if [ "$node" = "" ]; then
node=$(kubectl get node -o name | sed 's/node\///' | tr '\n' ' ')
node=${node::-1}
if [[ "$node" =~ " " ]]; then
echo "Node name must be specified. Choose one of: [$node]"
exit 1
else
echo "Single-node cluster detected. Defaulting to node $node"
fi
fi
pod=$(
kubectl create -o name -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
generateName: ssh-node-
labels:
plugin: ssh-node
spec:
nodeName: $node
containers:
- name: ssh-node
image: busybox
imagePullPolicy: IfNotPresent
command: ["chroot", "/host"]
tty: true
stdin: true
stdinOnce: true
securityContext:
privileged: true
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
hostNetwork: true
hostIPC: true
hostPID: true
restartPolicy: Never
EOF
)
deletePod() {
kubectl delete $pod --wait=false
}
trap deletePod EXIT
echo "Created $pod"
echo "Waiting for container to start..."
kubectl wait --for=condition=Ready $pod >/dev/null
kubectl attach -it $pod -c ssh-node
}
ssh_pod() {
# TODO: improve this
if [ "$1" == "" ]; then
echo "Pod name must be specified."
exit 1
fi
kubectl exec -it "$@" bash || (
echo "Running bash in pod failed; trying with sh"
kubectl exec -it "$@" sh
)
}
print_usage() {
echo "Provider-agnostic way of opening a remote shell to a Kubernetes node."
echo
echo "Enables you to access a node even when it doesn't run an SSH server or"
echo "when you don't have the required credentials. Also, the way you log in"
echo "is always the same, regardless of what provides the Kubernetes cluster"
echo "(e.g. Minikube, Kind, Docker Desktop, GKE, AKS, EKS, ...)"
echo
echo "You must have cluster-admin rights to use this plugin."
echo
echo "The primary focus of this plugin is to provide access to nodes, but it"
echo "also provides a quick way of running a shell inside a pod."
echo
echo "Examples: "
echo " # Open a shell to node of a single-node cluster (e.g. Docker Desktop)"
echo " kubectl ssh node"
echo
echo " # Open a shell to node of a multi-node cluster (e.g. GKE)"
echo " kubectl ssh node my-worker-node-1"
echo
echo " # Open a shell to a pod"
echo " kubectl ssh pod my-pod"
echo
echo "Usage:"
echo " kubectl ssh node [nodeName]"
echo " kubectl ssh pod [podName] [-n namespace] [-c container]"
exit 0
}
if [ "$1" == "--help" ]; then
print_usage
fi
if [[ "$1" == node/* ]]; then
ssh_node ${1:5}
elif [ "$1" == "node" ]; then
ssh_node $2
elif [[ "$1" == pod/* ]]; then
ssh_pod "$@"
elif [ "$1" == "pod" ]; then
shift
ssh_pod "$@"
else
print_usage
fi
認真看了一下這個腳本。
直呼人才啊。
果然是玩Linux的老哥啊。
牛逼啊。
太牛逼了。
太有趣了。
額。
講人話。
這個腳本使用busybox鏡像啟動了容器實例,
通過chroot到 /host + 把宿主機所有文件掛在到容器實例的方式,
實現了在容器實例直接對宿主機系統一對一“Copy”(可能表達不太准確),
進而實現直接在這個容器實例中操作宿主機的所有資源。
是的,所有資源。
是的,所有資源。
是的,所有資源。
着這里直接能看到其他程序的進程,
免密碼直接操作其他用戶的數據。
所謂,
這就是容器逃逸。
然后....
我們的目的確實也達到了。
通過這種方式確實可以直接實現登錄任意一台k8s node節點,
再也不需要密碼和授權。
總結。
很好玩。
不明鏡像確實有風險。
這個世界一直都不太安全。
參考資料:
docker 容器逃逸漏洞(CVE-2020-15257)風險通告
容器逃逸技術概覽 - DockOne.io
rambo1412:容器逃逸技術概覽