Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

kubernetes

People also ask

How do you interact with Kubernetes API?

The easiest way to get started with the Kubernetes API is by using kubectl. Run kubectl proxy --port=8080, and as long as the command is successful, you should be able to open your browser. Go to http://localhost:8080 and get a response, telling you what paths are available to be queried.


In the official documentation I found this:

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. From that, I devised what I think is a simpler solution than running a proxy or installing golang on my container. See this example that gets the information, from the api, for the current container:

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.


Every pod has a service account automatically applied that allows it to access the 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. With these two pieces of information, you can create a secure, authenticated connection to the apisever without using 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/

Using the Python kubernetes client..

from kubernetes import client, config

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

wget version:

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". By default it uses the "default service account" for accessing the api server.

So, we also need to pass a "ca cert" and "default service account token" to authenticate with the api server.

certificate file is stored at the following location inside the pod : /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

and the default service account token at : /var/run/secrets/kubernetes.io/serviceaccount/token

You can use the nodejs kubbernetes godaddy client.

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.

Each entity in the k8s system is identified by a service-account (like user account being used for users). Based on the RBAC capabilities, the service account token (/var/run/secrets/kubernetes.io/serviceaccount/token) is populated. The kube-api bindings (e.g. pykube) can take this token as a input when creating connection to the kube-api-servers. If the pod has the right RBAC capabilities, the pod would be able to establish the connection with the kube-api server.


I ran into this issue when trying to access the API from inside a pod using Go Code. Below is what I implemented to get that working, should someone come across this question wanting to use Go too.

The example uses a pod resource, for which you should use the client-go library if you are working with native kubernetes objects. The code is more helpful for those working with 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