Bagaimana cara saya mengakses Kubernetes api dari dalam pod container?

119

Saya dulu bisa menggulung

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

sebagai URL dasar saya, tetapi di kubernetes 0.18.0 memberi saya "tidak sah". Hal yang aneh adalah jika saya menggunakan alamat IP eksternal dari mesin API ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/), itu berfungsi dengan baik.

tslater.dll
sumber
Di mana Anda menjalankan cluster Anda (GCE, AWS, dll) dan menggunakan OS dasar apa (debian, CoreOS, dll)?
Robert Bailey
Vagrant / CoreOS ... saya akhirnya akan memindahkannya ke AWS / CoreOS
tslater
Dari mana datangnya variabel $KUBERNETES_SERVICE_HOSTdan $KUBERNETES_PORT_443_TCP_PORT?
ruediste
Saya menemukan panduan ini luar biasa untuk 101 di akun layanan, peran, dan rolebindings developer.ibm.com/recipes/tutorials/… . Bagian terakhir menjelaskan bagaimana kita dapat mengakses formulir k8 API di dalam pod.
viv

Jawaban:

132

Dalam dokumentasi resmi saya menemukan ini:

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

Sepertinya saya kehilangan token keamanan yang tidak saya perlukan di versi Kubernetes sebelumnya. Dari situ, saya menemukan apa yang menurut saya merupakan solusi yang lebih sederhana daripada menjalankan proxy atau memasang golang di container saya. Lihat contoh ini yang mendapatkan informasi, dari api, untuk penampung saat ini:

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

Saya juga menggunakan include biner sederhana, jq ( http://stedolan.github.io/jq/download/ ), untuk mengurai json untuk digunakan dalam skrip bash.

tslater.dll
sumber
5
Untuk klaster yang baru-baru ini diterapkan, Anda mungkin ingin mengubah v1beta3kev1
Eyal Levin
6
Perhatikan bahwa perintah curl ini akan terhubung secara tidak aman ke apiserver (memungkinkan man-in-the-middle untuk mencegat token pembawa), jadi Anda sebaiknya hanya menggunakannya jika jaringan antara pod dan apiserver dipercaya sepenuhnya. Jika tidak, Anda harus meneruskan --cacertflag ke curl sehingga curl memvalidasi sertifikat yang diberikan oleh apiserver.
Robert Bailey
1
Saya harus menggunakan 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 /… `. Perhatikan bahwa versi API disetel ke v1, bukan v1beta3 dan namespace default diganti dengan $ NAMESPACE.
ruediste
74

Setiap pod memiliki akun layanan yang secara otomatis diterapkan yang memungkinkannya untuk mengakses apiserver. Akun layanan menyediakan kredensial klien, dalam bentuk token pembawa, dan sertifikat otoritas sertifikat yang digunakan untuk menandatangani sertifikat yang diberikan oleh apiserver. Dengan dua informasi ini, Anda dapat membuat koneksi yang aman dan terotentikasi ke apisever tanpa menggunakan curl -k(alias 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/
Robert Bailey
sumber
2
Perlu dicatat bahwa agar cacert dan token ada di akun layanan, pengontrol replikasi harus diberi --root-ca-file=argumen saat dimulai. (ini ditangani secara otomatis di sebagian besar penginstal kubernetes). Lihat diskusi di sini untuk detail lebih lanjut: github.com/kubernetes/kubernetes/issues/10265
JKnight
7
Saya mengakses server API dari pod dengan namespace berbeda. Jadi saya harus menggunakan https://kubernetes.default/sebagai tuan rumah
ruediste
Host resmi kubernetes.default.svcseperti yang didokumentasikan di kubernetes.io/docs/tasks/access-application-cluster/…
Martin Tapp
17

Menggunakan klien Python kubernetes ..

from kubernetes import client, config

config.load_incluster_config()
v1_core = client.CoreV1Api()
rix
sumber
1
Terima kasih! Berikut adalah repo kecil dengan sebuah contoh, berdasarkan jawaban Anda, agar lebih mudah bermain dengan kode ini.
Omer Levi Hevroni
10

versi 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
Halil Kaskavalci
sumber
6

Tambahan terpenting untuk detail yang telah disebutkan di atas adalah bahwa pod tempat Anda mencoba mengakses server API harus memiliki kemampuan RBAC untuk melakukannya.

Setiap entitas di sistem k8s diidentifikasi oleh akun layanan (seperti akun pengguna yang digunakan untuk pengguna). Berdasarkan kemampuan RBAC, token akun layanan (/var/run/secrets/kubernetes.io/serviceaccount/token) diisi. Binding kube-api (misalnya pykube) dapat menggunakan token ini sebagai input saat membuat koneksi ke server kube-api. Jika pod memiliki kapabilitas RBAC yang tepat, pod tersebut akan dapat membuat koneksi dengan server kube-api.

pr-sobat
sumber
5

Saya mengalami masalah ini saat mencoba mengakses API dari dalam pod menggunakan Go Code. Di bawah ini adalah apa yang saya terapkan untuk membuatnya berfungsi, jika seseorang menemukan pertanyaan ini ingin menggunakan Go juga.

Contoh ini menggunakan resource pod, di mana Anda harus menggunakan client-golibrary tersebut jika Anda bekerja dengan objek kubernetes native. Kode ini lebih berguna bagi mereka yang bekerja dengan 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
KyleHodgetts
sumber
4

Dari dalam pod, server kubernetes api dapat diakses langsung di " https: //kubernetes.default ". Secara default menggunakan "akun layanan default" untuk mengakses server api.

Jadi, kita juga perlu meneruskan "ca cert" dan "token akun layanan default" untuk mengautentikasi dengan server api.

file sertifikat disimpan di lokasi berikut di dalam pod: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

dan token akun layanan default di: /var/run/secrets/kubernetes.io/serviceaccount/token

Anda dapat menggunakan klien godaddy 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);
}

Utkarsh Yeolekar
sumber
3

Saya mengalami masalah autentikasi serupa di GKE di mana skrip python tiba-tiba memberikan pengecualian. Solusi yang berhasil bagi saya adalah memberikan izin kepada pod melalui peran

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

untuk informasi lebih lanjut masukkan deskripsi tautan di sini

Bebek karet
sumber
2

Untuk siapa pun yang menggunakan Google Container Engine (diberdayakan oleh Kubernetes):

Panggilan sederhana ke https://kubernetesdari dalam cluster menggunakan klien kubernetes ini untuk pekerjaan Java .

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

Versi k8s saya adalah 1.2.0, dan di versi lain seharusnya berfungsi juga ^ ^

Pagi Y
sumber
Di atas benar jika Anda memiliki webhook atau RBAC lain yang diaktifkan. Hal ini terutama berlaku> 1.2 dari k8s
doktoroblivion
0

This is from the Kubernetes Beraksi book.

Anda perlu menjaga otentikasi . Server API itu sendiri mengatakan Anda tidak berwenang untuk mengaksesnya, karena tidak tahu siapa Anda .

Untuk mengautentikasi, Anda memerlukan token otentikasi. Untungnya, token disediakan melalui Rahasia token default yang disebutkan sebelumnya, dan disimpan dalam file token di volume rahasia.

Anda akan menggunakan token untuk mengakses server API . Pertama, muat token ke dalam variabel lingkungan:

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

Token sekarang disimpan di variabel lingkungan TOKEN . Anda dapat menggunakannya saat mengirim permintaan ke server 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"  
      ]
  }
fgul
sumber