简体   繁体   English

如何从 pod 容器中访问 Kubernetes api?

[英]How do I access the Kubernetes api from within a pod container?

I used to be able to curl我曾经可以卷曲

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

as my base URL, but in kubernetes 0.18.0 it gives me "unauthorized".作为我的基本 URL,但在 kubernetes 0.18.0 中它给了我“未经授权”。 The strange thing is that if I used the external IP address of the API machine ( http://172.17.8.101:8080/api/v1beta3/namespaces/default/ ), it works just fine.奇怪的是,如果我使用 API 机器的外部 IP 地址( http://172.17.8.101:8080/api/v1beta3/namespaces/default/ ),它工作得很好。

In the official documentation I found this:在官方文档中,我发现了这一点:

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

Apparently I was missing a security token that I didn't need in a previous version of Kubernetes.显然,我缺少在以前版本的 Kubernetes 中不需要的安全令牌。 From that, I devised what I think is a simpler solution than running a proxy or installing golang on my container.从那以后,我设计了一个我认为比在我的容器上运行代理或安装 golang 更简单的解决方案。 See this example that gets the information, from the api, for the current container:请参阅此示例,该示例从 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

I also use include a simple binary, jq ( http://stedolan.github.io/jq/download/ ), to parse the json for use in bash scripts.我还使用包含一个简单的二进制文件 jq ( http://stedolan.github.io/jq/download/ ) 来解析 json 以在 bash 脚本中使用。

Every pod has a service account automatically applied that allows it to access the apiserver.每个 pod 都有一个自动应用的服务帐户,允许它访问 apiserver。 The service account provides both client credentials, in the form of a bearer token, and the certificate authority certificate that was used to sign the certificate presented by the apiserver.服务帐户以不记名令牌的形式提供客户端凭据,以及用于签署 apiserver 提供的证书的证书颁发机构证书。 With these two pieces of information, you can create a secure, authenticated connection to the apisever without using curl -k (aka curl --insecure ):使用这两条信息,您可以在不使用curl -k (又名curl --insecure )的情况下创建到 apisever 的安全、经过身份验证的连接:

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/

Using the Python kubernetes client..使用 Python kubernetes 客户端..

from kubernetes import client, config

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

wget version: 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

From inside the pod, kubernetes api server can be accessible directly on " https://kubernetes.default ".从 pod 内部,可以直接在“ https://kubernetes.default ”上访问 kubernetes api 服务器。 By default it uses the "default service account" for accessing the api server.默认情况下,它使用“默认服务帐户”来访问 api 服务器。

So, we also need to pass a "ca cert" and "default service account token" to authenticate with the api server.所以,我们还需要传递一个“ca cert”和“default service account token”来与api服务器进行身份验证。

certificate file is stored at the following location inside the pod : /var/run/secrets/kubernetes.io/serviceaccount/ca.crt证书文件存储在 pod 内的以下位置:/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

and the default service account token at : /var/run/secrets/kubernetes.io/serviceaccount/token以及位于以下位置的默认服务帐户令牌:/var/run/secrets/kubernetes.io/serviceaccount/token

You can use the nodejs kubbernetes godaddy client .您可以使用nodejs kubbernetes godaddy 客户端

 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); }

The most important addendum to the details already mentioned above is that the pod from which you are trying to access the API server should have the RBAC capabilities to do so.对上面已经提到的细节最重要的补充是,您尝试从中访问 API 服务器的 pod 应该具有 RBAC 功能来这样做。

Each entity in the k8s system is identified by a service-account (like user account being used for users). k8s 系统中的每个实体都由一个服务帐户标识(例如用户帐户用于用户)。 Based on the RBAC capabilities, the service account token (/var/run/secrets/kubernetes.io/serviceaccount/token) is populated.根据 RBAC 功能,填充服务帐户令牌 (/var/run/secrets/kubernetes.io/serviceaccount/token)。 The kube-api bindings (eg pykube) can take this token as a input when creating connection to the kube-api-servers.在创建与 kube-api-servers 的连接时,kube-api 绑定(例如 pykube)可以将此令牌作为输入。 If the pod has the right RBAC capabilities, the pod would be able to establish the connection with the kube-api server.如果 pod 具有正确的 RBAC 功能,则 pod 将能够与 kube-api 服务器建立连接。

I ran into this issue when trying to access the API from inside a pod using Go Code.我在尝试使用 Go Code 从 pod 内部访问 API 时遇到了这个问题。 Below is what I implemented to get that working, should someone come across this question wanting to use Go too.下面是我实现的工作,如果有人遇到这个问题也想使用 Go。

The example uses a pod resource, for which you should use the client-go library if you are working with native kubernetes objects.该示例使用 pod 资源,如果您使用原生 kubernetes 对象,则应使用client-go库。 The code is more helpful for those working with CustomResourceDefintions.该代码对那些使用 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

I had a similar auth problem on GKE where python scripts suddenly threw exceptions.我在 GKE 上遇到了类似的身份验证问题,其中 python 脚本突然抛出异常。 The solution that worked for me was to give pods permission through role对我有用的解决方案是通过角色授予 pods 权限

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

for more information enter link description here有关更多信息,请在此处输入链接描述

With RBAC enabled, default service account don't have any permissions.启用 RBAC 后,默认服务帐户没有任何权限。

Better create separate service account for your needs and use it to create your pod.更好地根据您的需要创建单独的服务帐户并使用它来创建您的 pod。

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

It's well explained here https://developer.ibm.com/recipes/tutorials/service-accounts-and-auditing-in-kubernetes/这里有很好的解释https://developer.ibm.com/recipes/tutorials/service-accounts-and-auditing-in-kubernetes/

This is from the Kubernetes In Action book. This is from the Kubernetes In Action book.

You need to take care of authentication .您需要处理身份验证 The API server itself says you're not authorized to access it, because it doesn't know who you are . API 服务器本身说您无权访问它,因为它不知道您是谁

To authenticate, you need an authentication token.要进行身份验证,您需要一个身份验证令牌。 Luckily, the token is provided through the default-token Secret mentioned previously, and is stored in the token file in the secret volume.幸运的是,令牌是通过前面提到的default-token Secret提供的,并存储在机密卷中的令牌文件中。

You're going to use the token to access the API server .您将使用令牌访问 API 服务器 First, load the token into an environment variable:首先,将令牌加载到环境变量中:

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

The token is now stored in the TOKEN environment variable .令牌现在存储在TOKEN环境变量中 You can use it when sending requests to the API 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"  
      ]
  }

For whoever is using Google Container Engine (powered by Kubernetes):对于使用 Google Container Engine(由 Kubernetes 提供支持)的人:

A simple call to https://kubernetes from within the cluster usingthis kubernetes client for Java works.使用此用于 Java 的 kubernetes 客户端从集群内简单调用https://kubernetes即可

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

我的k8s版本是1.2.0,其他版本应该也能用^ ^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM