ฉันจะเข้าถึง API Kubernetes จากภายใน pod container ได้อย่างไร


119

ผมเคยดัดผมได้

https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1beta3/namespaces/default/

เป็น URL พื้นฐานของฉัน แต่ใน kubernetes 0.18.0 ทำให้ฉัน "ไม่ได้รับอนุญาต" สิ่งที่แปลกคือถ้าฉันใช้ที่อยู่ IP ภายนอกของเครื่อง API ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/) มันก็ใช้ได้ดี


คุณกำลังเรียกใช้คลัสเตอร์ของคุณที่ใด (GCE, AWS ฯลฯ ) และใช้ระบบปฏิบัติการพื้นฐานใด (debian, CoreOS ฯลฯ )
Robert Bailey

Vagrant / CoreOS ... ในที่สุดฉันจะย้ายไปที่ AWS / CoreOS
tslater

ที่ไหนทำ$KUBERNETES_SERVICE_HOSTและ$KUBERNETES_PORT_443_TCP_PORTตัวแปรมาจากไหน?
ruediste

ผมพบว่าคู่มือนี้จะเป็นที่น่าตื่นตาตื่นใจสำหรับ 101 ในบัญชีบริการบทบาทและ rolebindings developer.ibm.com/recipes/tutorials/... ส่วนสุดท้ายให้รายละเอียดว่าเราสามารถเข้าถึงแบบฟอร์ม k8 API ภายในพ็อดได้อย่างไร
viv

คำตอบ:


132

ในเอกสารอย่างเป็นทางการฉันพบสิ่งนี้:

https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod

เห็นได้ชัดว่าฉันไม่มีโทเค็นความปลอดภัยที่ฉันไม่ต้องการใน Kubernetes เวอร์ชันก่อนหน้า จากนั้นฉันคิดว่าสิ่งที่ฉันคิดว่าเป็นวิธีแก้ปัญหาที่ง่ายกว่าการเรียกใช้พร็อกซีหรือการติดตั้ง golang บนคอนเทนเนอร์ของฉัน ดูตัวอย่างนี้ที่รับข้อมูลจาก api สำหรับคอนเทนเนอร์ปัจจุบัน:

KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" \
      https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

ฉันยังใช้ไบนารีธรรมดา jq ( http://stedolan.github.io/jq/download/ ) เพื่อแยกวิเคราะห์ json เพื่อใช้ในสคริปต์ bash


5
สำหรับคลัสเตอร์ที่เพิ่งปรับใช้คุณอาจต้องการเปลี่ยนv1beta3เป็นv1
Eyal Levin

6
โปรดทราบว่าคำสั่ง curl นี้จะเชื่อมต่อกับ apiserver อย่างไม่ปลอดภัย (ทำให้ man-in-the-middle สามารถสกัดกั้นโทเค็นของผู้ถือได้) ดังนั้นคุณควรใช้คำสั่งนี้ก็ต่อเมื่อเครือข่ายระหว่าง pod และ apiserver เชื่อถือได้เต็มที่ มิฉะนั้นคุณควรส่ง--cacertแฟล็กไปยัง curl เพื่อให้ curl ตรวจสอบใบรับรองที่เสนอโดย apiserver
Robert Bailey

1
ฉันต้องใช้KUBERNETES_SERVICE_HOST=kubernetes.default, $KUBERNETES_443_TCP_PORT=443NAMESPACE == $ (</ var / run / secret / kubernetes.io / serviceaccount / namespace) . The URL was kubernetes.default: 443 / api / v1 / namespaces / $ NAMESPACE / pods / … “. โปรดทราบว่าเวอร์ชัน API ถูกตั้งค่าเป็น v1 แทน v1beta3 และเนมสเปซเริ่มต้นถูกแทนที่ด้วย $ NAMESPACE
ruediste

74

ทุกพ็อดจะมีการใช้บัญชีบริการโดยอัตโนมัติเพื่อให้สามารถเข้าถึง apiserver ได้ บัญชีบริการมีทั้งข้อมูลรับรองไคลเอ็นต์ในรูปแบบของโทเค็นผู้ถือและใบรับรองผู้ออกใบรับรองที่ใช้เพื่อลงนามในใบรับรองที่ผู้ให้บริการกำหนด ด้วยข้อมูลสองส่วนนี้คุณสามารถสร้างการเชื่อมต่อที่ปลอดภัยและรับรองความถูกต้องกับ apisever โดยไม่ต้องใช้curl -k(aka curl --insecure):

curl -v --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc/

2
ควรสังเกตว่าเพื่อให้ cacert และโทเค็นทั้งสองมีอยู่ในบัญชีบริการผู้ควบคุมการจำลองต้องได้รับ--root-ca-file=อาร์กิวเมนต์เมื่อเริ่มทำงาน (สิ่งนี้ได้รับการจัดการโดยอัตโนมัติในตัวติดตั้ง kubernetes ส่วนใหญ่) ดูรายละเอียดเพิ่มเติมได้ที่github.com/kubernetes/kubernetes/issues/10265
JKnight

7
ฉันกำลังเข้าถึงเซิร์ฟเวอร์ API จากพ็อดที่มีเนมสเปซอื่น ดังนั้นฉันจึงต้องใช้https://kubernetes.default/เป็นโฮสต์
ruediste

โฮสต์อย่างเป็นทางการมีkubernetes.default.svcเอกสารอยู่ที่kubernetes.io/docs/tasks/access-application-cluster/…
Martin Tapp

17

การใช้ไคลเอนต์ Python kubernetes ..

from kubernetes import client, config

config.load_incluster_config()
v1_core = client.CoreV1Api()

1
ขอบคุณ! นี่คือrepoขนาดเล็กที่มีตัวอย่างตามคำตอบของคุณเพื่อให้ง่ายต่อการเล่นกับโค้ดนี้
Omer Levi Hevroni

10

เวอร์ชัน wget:

KUBE_TOKEN=$(</var/run/secrets/kubernetes.io/serviceaccount/token)    
wget -vO- --ca-certificate /var/run/secrets/kubernetes.io/serviceaccount/ca.crt  --header "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME

6

ภาคผนวกที่สำคัญที่สุดของรายละเอียดที่กล่าวมาแล้วข้างต้นคือพ็อดที่คุณพยายามเข้าถึงเซิร์ฟเวอร์ API ควรมีความสามารถของ RBAC ในการทำเช่นนั้น

แต่ละเอนทิตีในระบบ k8s ถูกระบุโดยบัญชีบริการ (เช่นบัญชีผู้ใช้ที่ใช้สำหรับผู้ใช้) ตามความสามารถของ RBAC โทเค็นบัญชีบริการ (/var/run/secrets/kubernetes.io/serviceaccount/token) จะถูกเติม การเชื่อม kube-api (เช่น pykube) สามารถใช้โทเค็นนี้เป็นอินพุตเมื่อสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ kube-api หากพ็อดมีความสามารถ RBAC ที่ถูกต้องพ็อดจะสามารถสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ kube-api


5

ฉันพบปัญหานี้เมื่อพยายามเข้าถึง API จากภายในพ็อดโดยใช้ Go Code ด้านล่างนี้คือสิ่งที่ฉันนำไปใช้เพื่อให้ได้ผลหากมีคนเจอคำถามนี้ต้องการใช้ Go ด้วย

ตัวอย่างใช้ทรัพยากรพ็อดซึ่งคุณควรใช้client-goไลบรารีหากคุณกำลังทำงานกับอ็อบเจ็กต์ kubernetes ดั้งเดิม โค้ดนี้มีประโยชน์มากขึ้นสำหรับผู้ที่ทำงานกับ CustomResourceDefintions

serviceHost := os.GetEnv("KUBERNETES_SERVICE_HOST")
servicePort := os.GetEnv("KUBERNETES_SERVICE_PORT")
apiVersion := "v1" // For example
namespace := default // For example
resource := "pod" // For example
httpMethod := http.MethodGet // For Example

url := fmt.Sprintf("https://%s:%s/apis/%s/namespaces/%s/%s", serviceHost, servicePort, apiVersion, namespace, resource)

u, err := url.Parse(url)
if err != nil {
  panic(err)
}
req, err := http.NewRequest(httpMethod, u.String(), bytes.NewBuffer(payload))
if err != nil {
    return err
}

caToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
if err != nil {
    panic(err) // cannot find token file
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", string(caToken)))

caCertPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
if err != nil {
    return panic(err) // Can't find cert file
}
caCertPool.AppendCertsFromPEM(caCert)

client := &http.Client{
  Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
        RootCAs: caCertPool,
    },
  },
}

resp, err := client.Do(req)
if err != nil {
    log.Printf("sending helm deploy payload failed: %s", err.Error())
    return err
}
defer resp.Body.Close()

// Check resp.StatusCode
// Check resp.Status

4

จากภายในพ็อดสามารถเข้าถึงเซิร์ฟเวอร์ kubernetes api ได้โดยตรงที่ " https: //kubernetes.default " โดยค่าเริ่มต้นจะใช้ "บัญชีบริการเริ่มต้น" สำหรับการเข้าถึงเซิร์ฟเวอร์ api

ดังนั้นเราจึงต้องส่ง "ใบรับรอง ca" และ "โทเค็นบัญชีบริการเริ่มต้น" เพื่อตรวจสอบสิทธิ์กับเซิร์ฟเวอร์ API

ไฟล์ใบรับรองถูกเก็บไว้ที่ตำแหน่งต่อไปนี้ภายในพ็อด: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

และโทเค็นบัญชีบริการเริ่มต้นที่: /var/run/secrets/kubernetes.io/serviceaccount/token

คุณสามารถใช้nodejs kubbernetes ลูกค้า

let getRequestInfo = () => {
    return {
        url: "https://kubernetes.default",
        ca:   fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt').toString(),
        auth: {
            bearer: fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token').toString(),
        },
        timeout: 1500
    };
}

let initK8objs = () =>{
    k8obj = getRequestInfo();
    k8score = new Api.Core(k8obj),
    k8s = new Api.Api(k8obj);
}


3

ฉันมีปัญหาการตรวจสอบสิทธิ์ที่คล้ายกันใน GKE ซึ่งสคริปต์ python ก็ส่งข้อยกเว้น วิธีแก้ปัญหาที่ได้ผลสำหรับฉันคือให้สิทธิ์พ็อดผ่านบทบาท

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: fabric8-rbac
subjects:
  - kind: ServiceAccount
  # Reference to upper's `metadata.name`
  name: default
  # Reference to upper's `metadata.namespace`
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

สำหรับข้อมูลเพิ่มเติมโปรดป้อนคำอธิบายลิงก์ที่นี่



2

เมื่อเปิดใช้งาน RBAC บัญชีบริการเริ่มต้นจะไม่มีสิทธิ์ใด ๆ

ควรสร้างบัญชีบริการแยกต่างหากสำหรับความต้องการของคุณและใช้เพื่อสร้างพ็อดของคุณ

spec:
  serviceAccountName: secret-access-sa
  containers:
    ...

มันอธิบายได้ดีที่นี่https://developer.ibm.com/recipes/tutorials/service-accounts-and-auditing-in-kubernetes/


0
curl -v -cacert <path to>/ca.crt --cert <path to>/kubernetes-node.crt --key <path to>/kubernetes-node.key https://<ip:port>

เวอร์ชัน k8 ของฉันคือ 1.2.0 และในเวอร์ชันอื่น ๆ ก็ควรจะใช้งานได้เช่นกัน ^ ^


ข้างต้นถูกต้องหากคุณเปิดใช้งาน webhooks หรือ RBAC อื่น ๆ โดยเฉพาะอย่างยิ่ง> 1.2 ของ k8s
doktoroblivion

0

This is from the Kubernetes ในการดำเนินการ book.

คุณจำเป็นต้องดูแลการตรวจสอบ เซิร์ฟเวอร์ API บอกว่าคุณไม่ได้รับอนุญาตให้เข้าถึงเพราะ ไม่รู้ว่าคุณเป็นใคร

ในการตรวจสอบสิทธิ์คุณต้องมีโทเค็นการตรวจสอบสิทธิ์ โชคดีที่โทเค็นมีให้ผ่านความลับโทเค็นเริ่มต้นที่กล่าวถึงก่อนหน้านี้และถูกเก็บไว้ในไฟล์โทเค็นในไดรฟ์ข้อมูลลับ

คุณกำลังจะใช้โทเค็นการเข้าถึงเซิร์ฟเวอร์ของ API ขั้นแรกให้โหลดโทเค็นลงในตัวแปรสภาพแวดล้อม:

root@myhome:/# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

โทเค็นจะถูกเก็บไว้ในขณะนี้ในTOKEN สภาพแวดล้อม ตัวแปร คุณสามารถใช้เมื่อส่งคำขอไปยังเซิร์ฟเวอร์ API:

root@curl:/# curl -H "Authorization: Bearer $TOKEN"  https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/api/v1/namespaces/default/pods/$HOSTNAME
   {  "paths": 
      [    
        "/api",    
        "/api/v1",   
        "/apis",    
        "/apis/apps",    
        "/apis/apps/v1beta1",    
        "/apis/authorization.k8s.io",        
         ...    
        "/ui/",    
        "/version"  
      ]
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.