利用容器逃逸實現遠程登錄k8s集群節點


某天,

某魚說要吃瞄,

於是......

李國寶:邊緣計算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:容器逃逸技術概覽


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM