我如何从一个豆荚容器内访问库伯内特斯 api?

我以前会卷发

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

作为我的基本网址,但在库伯内特0.18.0它给我“未经授权”。奇怪的是,如果我使用 API 机器(http://172.17.8.101:8080/api/v1beta3/namespaces/default/)的外部 IP 地址,它就可以正常工作。

99440 次浏览

在官方文件中我发现了这个:

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/)来解析用于 bash 脚本的 json。

每个吊舱都有一个自动应用的服务帐户,允许它访问 apiserver。服务帐户既提供持有者令牌形式的客户端凭据,也提供用于对 apiserver 提供的证书进行签名的证书颁发机构证书。有了这两条信息,您就可以创建到 apisever 的安全的、经过身份验证的连接,而无需使用 curl -k(又名 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/
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,在其他版本中它应该也能工作 ^ ^

对于使用谷歌容器引擎(由 Kubernetes 提供动力)的用户:

使用 这个 kubernetes 客户端为 Java从集群内部对 https://kubernetes进行一个简单的调用就可以工作。

从吊舱内部,库伯内特斯 API 服务器可以直接访问“ https://kubernetes.default”。默认情况下,它使用“默认服务帐户”访问 api 服务器。

因此,我们还需要传递一个“ ca cert”和“ default service account token”来与 api 服务器进行身份验证。

证书文件存储在吊舱内以下位置: /var/run/secret/ kubernetes.io/serviceaccount/ca.crt

以及默认服务帐户令牌位于: /var/run/secret/ kubernetes.io/serviceaccount/token

你可以使用 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);
}

使用 Python kubernetes 客户端. 。

from kubernetes import client, config


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

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

启用 RBAC 后,默认服务帐户没有任何权限。

最好为您的需要创建单独的服务帐户,并使用它来创建您的吊舱。

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

这里解释得很清楚

我在尝试使用 Go Code 从吊舱内访问 API 时遇到了这个问题。下面是我实现的工作,如果有人遇到这个问题想使用围棋太。

该示例使用了一个 pod 资源,如果使用的是本机 kubernetes 对象,则应该使用 client-go库。该代码对于使用 CustomResourceDefinition 的用户更有帮助。

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

我在 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

了解更多信息

对于上面提到的细节,最重要的补充是,尝试访问 API 服务器的 pod 应该具有这样做的 RBAC 功能。

K8s 系统中的每个实体都由一个服务帐户标识(就像用户帐户被用于用户一样)。根据 RBAC 功能,将填充服务帐户令牌(/var/run/secret/ kubernetes.io/serviceaccount/token )。当创建到 kube-api-server 的连接时,kube-api 绑定(例如 pykube)可以将此令牌作为输入。如果吊舱有正确的 RBAC 功能,吊舱将能够建立与 kube-api 服务器的连接。

This is from the 库伯内特在行动 book.

你要照顾好 认证。API 服务器本身表示您无权访问它,因为 它不知道你是谁

要进行身份验证,您需要一个 认证令牌。。幸运的是,令牌是通过前面提到的 默认标记的秘密提供的,并存储在秘密卷中的令牌文件中。

您将使用 Token访问 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"
]
}