Kubernetes api'ye bir kapsül kapsayıcısından nasıl erişirim?


119

Ben kıvrılabiliyordum

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

benim temel URL'm olarak, ancak kubernetes 0.18.0'da bana "yetkisiz" veriyor. Garip olan şey, API makinesinin ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/) harici IP adresini kullanırsam, gayet iyi çalışıyor olmasıdır.


Kümenizi (GCE, AWS, vb.) Nerede çalıştırıyorsunuz ve hangi temel işletim sistemini (debian, CoreOS, vb.) Kullanıyorsunuz?
Robert Bailey

Vagrant / CoreOS ... i sonunda onu AWS / CoreOS'a taşıyacak
tslater

Nerede yok $KUBERNETES_SERVICE_HOSTve $KUBERNETES_PORT_443_TCP_PORTdeğişkenler geliyor?
ruediste

Bu kılavuzu hizmet hesapları, roller ve rol bağlama geliştirici.ibm.com/ recipes/tutorials/… konusunda harika buldum . Son bölüm, bölmelerdeki k8 API formuna nasıl erişebileceğimizi detaylandırmaktadır.
viv

Yanıtlar:


132

Resmi belgelerde şunu buldum:

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

Görünüşe göre Kubernetes'in önceki bir sürümünde ihtiyaç duymadığım bir güvenlik belirtecim eksikti. Bundan, bir proxy çalıştırmaktan veya konteynırıma golang yüklemekten daha basit bir çözüm olduğunu düşündüğüm şeyi tasarladım. Geçerli kapsayıcı için API'den bilgi alan bu örneğe bakın:

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

Ayrıca bash betiklerinde kullanmak üzere json'u ayrıştırmak için basit bir ikili dosya, jq ( http://stedolan.github.io/jq/download/ ) kullanıyorum.


5
Yakın zamanda dağıtılan kümeler için değiştirmek v1beta3isteyebilirsinizv1
Eyal Levin

6
Bu curl komutunun güvensiz bir şekilde apiserver'a bağlanacağını unutmayın (ortadaki bir adamın taşıyıcı belirtecine müdahale etmesini mümkün kılar), bu nedenle onu yalnızca pod ile apiserver arasındaki ağ tamamen güvenilirse kullanmalısınız. Aksi takdirde, --cacertcurl'nin apiserver tarafından sunulan sertifikayı doğrulaması için curl'ye geçmeniz gerekir.
Robert Bailey

1
Ben kullanmak zorunda kaldı KUBERNETES_SERVICE_HOST=kubernetes.default, $KUBERNETES_443_TCP_PORT=443, NAMESPACE == $ (</ var / run / sırlar / kubernetes.io / HizmetHesabı / ad) . The URL was kubernetes.default: 443 / API / v1 / ad / $ NAMESPACE / bakla / ... `. API sürümünün v1beta3 yerine v1 olarak ayarlandığını ve varsayılan ad alanının $ NAMESPACE ile değiştirildiğini unutmayın.
ruediste

74

Her bölmeye otomatik olarak uygulanan ve bir sunucuya erişmesine izin veren bir hizmet hesabı vardır. Hizmet hesabı, hem bir taşıyıcı belirteci biçiminde istemci kimlik bilgilerini hem de bir apiserver tarafından sunulan sertifikayı imzalamak için kullanılan sertifika yetkilisi sertifikasını sağlar. Bu iki parça bilgiyle, curl -k(aka curl --insecure) kullanmadan apisever ile güvenli, kimliği doğrulanmış bir bağlantı oluşturabilirsiniz :

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 ve jetonun hizmet hesabında her ikisinin de var olması için, başlatıldığında çoğaltma denetleyicisine bir --root-ca-file=bağımsız değişken verilmesi gerektiğine dikkat edilmelidir . (bu, çoğu kubernetes yükleyicisinde otomatik olarak ele alınır). Daha fazla ayrıntı için buradaki tartışmaya bakın: github.com/kubernetes/kubernetes/issues/10265
JKnight

7
API sunucusuna farklı bir ad alanına sahip bir bölmeden erişiyordum. Bu yüzden https://kubernetes.default/sunucu olarak kullanmak zorunda kaldım
ruediste

Resmi sunucu, kubernetes.io/docs/tasks/access-application-cluster/…kubernetes.default.svc adresinde belgelendiği gibidir
Martin Tapp

17

Python kubernetes istemcisini kullanma ..

from kubernetes import client, config

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

1
Teşekkürler! İşte, bu kodla oynamayı kolaylaştırmak için cevabınıza göre bir örnek içeren küçük bir depo .
Omer Levi Hevroni

10

wget sürümü:

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

Yukarıda belirtilen ayrıntılara en önemli ek, API sunucusuna erişmeye çalıştığınız bölmenin bunu yapmak için RBAC yeteneklerine sahip olması gerektiğidir.

K8s sistemindeki her varlık bir hizmet hesabı ile tanımlanır (kullanıcılar için kullanılan kullanıcı hesabı gibi). RBAC yeteneklerine bağlı olarak, hizmet hesabı belirteci (/var/run/secrets/kubernetes.io/serviceaccount/token) doldurulur. Kube-api bağları (örneğin pykube), kube-api-sunucularına bağlantı oluştururken bu belirteci bir girdi olarak alabilir. Bölme doğru RBAC yeteneklerine sahipse, bölme kube-api sunucusuyla bağlantı kurabilir.


5

Go Code kullanarak bir bölmenin içinden API'ye erişmeye çalışırken bu sorunla karşılaştım. Aşağıda, birisi bu soruyla karşılaşıp Go'yu kullanmak isterse, bu çalışmayı sağlamak için uyguladığım şey.

Örnek, client-goyerel kubernetes nesneleriyle çalışıyorsanız kitaplığı kullanmanız gereken bir bölme kaynağı kullanır . Kod, CustomResourceDefintions ile çalışanlar için daha yararlıdır.

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

Kapsülün içinden, kubernetes api sunucusuna doğrudan " https: //kubernetes.default " adresinden erişilebilir . Varsayılan olarak, api sunucusuna erişmek için "varsayılan hizmet hesabını" kullanır.

Bu nedenle, api sunucusuyla kimlik doğrulaması yapmak için bir "ca cert" ve "varsayılan hizmet hesabı belirteci" iletmemiz gerekir.

sertifika dosyası, bölmenin içinde şu konumda saklanır: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

ve /var/run/secrets/kubernetes.io/serviceaccount/token adresindeki varsayılan hizmet hesabı jetonu

Sen kullanabilirsiniz nodejs kubbernetes godaddy müşteri .

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'de python komut dosyalarının aniden istisnalar attığı benzer bir kimlik doğrulama sorunum vardı. Benim için işe yarayan çözüm, bölmelere rol aracılığıyla izin vermekti

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

daha fazla bilgi için buraya bağlantı açıklamasını girin




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

K8s sürümüm 1.2.0 ve diğer sürümlerde de çalışması gerekiyor ^ ^


Yukarıdakiler, web kancalarınız veya başka bir RBAC etkinleştirilmişse doğrudur. Bu özellikle> 1,2 / k8s
doktoroblivion

0

This is from the Kubernetes İş Başında book.

Kimlik doğrulamasına dikkat etmeniz gerekiyor . API sunucusunun kendisi ona erişme yetkinizin olmadığını söylüyor çünkü sizin kim olduğunuzu bilmiyor .

Kimlik doğrulaması için bir kimlik doğrulama jetonuna ihtiyacınız var . Neyse ki, belirteç daha önce bahsedilen varsayılan belirteç Sırrı aracılığıyla sağlanır ve belirteç dosyasında gizli birimde saklanır.

API sunucusuna erişmek için jetonu kullanacaksınız . İlk olarak, belirteci bir ortam değişkenine yükleyin:

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

Belirteç artık TOKEN ortam değişkeninde saklanır . API sunucusuna istek gönderirken kullanabilirsiniz:

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"  
      ]
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.