利用容器逃逸實現遠程登陸k8s集羣節點

某天,node

某魚說要吃瞄,git

因而......github

李國寶:邊緣計算k8s集羣SuperEdge初體驗

zhuanlan.zhihu.com
圖標docker

照着上一篇文章來講,我這邊邊緣計算集羣有一堆節點。shell

每一個節點都在不一樣的網絡環境下。api

他們的共同點都是能夠訪問內網,安全

部分是某雲學生主機,bash

部分是跑在家庭網絡環境下的虛擬機,服務器

甚至假設中還有一些是樹莓派之類的機器。網絡

因此他們另外一個共同點是,基本都沒有公網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:容器逃逸技術概覽

相關文章
相關標籤/搜索