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


117

我曾经能够卷曲

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

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


您在哪里运行集群(GCE,AWS等)并使用什么基本操作系统(Debian,CoreOS等)?
罗伯特·贝利2015年

Vagrant / CoreOS ... i最终将其移至AWS /
CoreOS

你在哪里的$KUBERNETES_SERVICE_HOST$KUBERNETES_PORT_443_TCP_PORT变量从何而来?
ruediste

在服务帐户,角色和角色绑定developer.ibm.com/recipes/tutorials/…上,我发现该指南对于101而言是惊人的。最后一部分详细说明了如何在Pod中访问k8 API表单。
viv

Answers:


131

在官方文档中,我发现:

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。


5
对于最近部署的群集,您可能想要更改v1beta3v1
Eyal Levin

6
请注意,该curl命令将不安全地连接到apiserver(这使得中间人有可能截取承载令牌),因此,只有在pod和apiserver之间的网络受到完全信任时,才应使用它。否则,您应该传递该--cacert标志以进行curl更改,以便curl验证apiserver提交的证书。
罗伯特·贝利

1
我必须使用KUBERNETES_SERVICE_HOST=kubernetes.default,,$KUBERNETES_443_TCP_PORT=443NAMESPACE == $(</ var / run / secrets / kubernetes.io / serviceaccount / namespace). The URL was kubernetes.default:443 / api / v1 / namespaces / $ NAMESPACE / pods /… `。请注意,API版本设置为v1而不是v1beta3,并且默认名称空间已替换为$ NAMESPACE。
ruediste

74

每个Pod都有一个自动应用的服务帐户,该帐户可以使其访问apiserver。服务帐户以承载令牌的形式提供客户端凭据,以及用于对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
我正在从具有不同名称空间的Pod访问API服务器。因此,我不得不https://kubernetes.default/作为主持人
ruediste '17

官方主机kubernetes.default.svc作为记录在kubernetes.io/docs/tasks/access-application-cluster/...
马丁特普

17

使用Python kubernetes客户端

from kubernetes import client, config

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

1
谢谢!这是一个小型存储,并根据您的答案提供了一个示例,以简化使用此代码的过程。
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服务器的Pod应该具有RBAC功能。

k8s系统中的每个实体都由一个服务帐户(例如用于用户的用户帐户)标识。基于RBAC功能,将填充服务帐户令牌(/var/run/secrets/kubernetes.io/serviceaccount/token)。创建与kube-api-servers的连接时,kube-api绑定(例如pykube)可以将此令牌作为输入。如果Pod具有正确的RBAC功能,则Pod将能够与kube-api服务器建立连接。


5

尝试使用Go Code从pod内部访问API时遇到了此问题。下面是我实现该功能的实现方式,如果有人也想使用Go遇到这个问题。

该示例使用pod资源,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

从容器内部,可以直接在“ https://kubernetes.default ” 上访问kubernetes api服务器。默认情况下,它使用“默认服务帐户”访问api服务器。

因此,我们还需要传递“ ca cert”和“默认服务帐户令牌”以向api服务器进行身份验证。

证书文件存储在Pod中的以下位置:/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

以及默认的服务帐户令牌,位于:/var/run/secrets/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);
}


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

有关更多信息,请在此处输入链接描述




0
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,在其他版本中也应该工作^^


如果您启用了Webhooks或其他一些RBAC,则以上内容是正确的。> 1.2的k8尤其如此
-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"  
      ]
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.