Conectarse al API de Kubernetes con un cliente HTTP
Aunque el propio Kubernetes nos facilita y se conecta con el API de Kubernetes directamente, quizás querramos conectarnos al API para explorar, investigar o tener un mayor control sobre lo que se hace por detrás. Por esos motivos, vamos a ver en este artículo como conectarse al API de Kubernetes con un cliente HTTP.
Para comenzar con el ejemplo que vamos a realizar vamos a utilizar minikube.
Obtener IP del clúster de Kubernetes
Para poder acceder a cualquier API lo primero que necesitamos saber es su dirección IP, por lo que para obtener esta IP lo primero que vamos a hacer es ejecutar el siguiente comando:
$ kubectl cluster-info
y la respuesta sería:
Kubernetes control plane is running at https://127.0.0.1:57768 CoreDNS is running at https://127.0.0.1:57768/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Tenemos que tener en cuenta que el comando anterior nos da la dirección del contexto actual, en el caso en el que tengamos diferentes contextos podemos utilizar el siguiente comando:
kubectl config view
Y la respuesta sería:
apiVersion: v1 clusters: - cluster: certificate-authority: /Users/nrcalle/.minikube/ca.crt extensions: - extension: last-update: Tue, 09 Aug 2022 14:00:08 CEST provider: minikube.sigs.k8s.io version: v1.26.1 name: cluster_info server: https://127.0.0.1:57768 name: minikube contexts: - context: cluster: minikube extensions: - extension: last-update: Tue, 09 Aug 2022 14:00:08 CEST provider: minikube.sigs.k8s.io version: v1.26.1 name: context_info namespace: default user: minikube name: minikube current-context: minikube kind: Config preferences: {} users: - name: minikube user: client-certificate: /Users/nrcalle/.minikube/profiles/minikube/client.crt client-key: /Users/nrcalle/.minikube/profiles/minikube/client.key
Ahora vamos a obtener la IP haciendo uso de jsonpath:
kubectl config view -o jsonpath='{.clusters[0].cluster.server}'
Y guardamos la IP:
KUBE_API=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
Siendo el clusters[0], el lugar en el array anterior que ocupa nuestro clúster al que queremos acceder.
Llamar al API de Kubernetes con certificados
Ya tenemos la IP para poder acceder al API, pero si realizamos una petición directamente nos dará un error de autorización por lo que primero necesitamos hacer uso de un certificado para poder autenticarnos en la petición. Ya que Kubernetes expone su API por HTTPS.
En mi caso, me he levantado un clúster haciendo uso de minikube por lo que para poder acceder al API vamos a utilizar los certificados que nos guarda minikube:
Los certificados se encuentran dentro de la carpeta de minikube, en la siguiente ruta:
.minikube/ca.crt
Para poder ver el contenido del certificado podemos ejecutar el siguiente comando:
cat ~/.minikube/ca.crt | openssl x509 -text
Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=minikubeCA Validity Not Before: Aug 8 11:59:52 2022 GMT Not After : Aug 6 11:59:52 2032 GMT Subject: CN=minikubeCA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) .... .... ....
Pero con este certificado no vamos a poder acceder a todos los servicios que expone su API, por ejemplo, podremos ver la versión pero no el listado de los deployment.
Por lo que necesitamos el usuario creado por minikube cuando crea el clúster, ya que la CA que crea es de la confianza de Kubernetes. Para poder ver la ruta del certificado creado y firmado podemos hacer uso del siguiente comando:
kubectl config view -o jsonpath='{.users[0]}'
Y la respuesta sería:
{"name":"minikube","user":{"client-certificate":"/Users/nrcalle/.minikube/profiles/minikube/client.crt","client-key":"/Users/nrcalle/.minikube/profiles/minikube/client.key"}}
Y como hemos hecho antes vamos a ver el contenido del certificado:
cat ~/.minikube/profiles/minikube/client.crt | openssl x509 -text
Una vez tenemos el certificado del usuario podemos realizar una petición, por ejemplo, para ver todos los deployment.:
curl $KUBE_API/apis/apps/v1/deployments \ --cacert ~/.minikube/ca.crt \ --cert ~/.minikube/profiles/minikube/client.crt \ --key ~/.minikube/profiles/minikube/client.key
Y la respuesta:
{ "kind": "DeploymentList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "1757" }, "items": [ { "metadata": { "name": "coredns", "namespace": "kube-system", "uid": "7cf2c0e1-1856-4c21-bde4-87852022ce8a", "resourceVersion": "698", "generation": 2, "creationTimestamp": "2022-08-09T12:00:08Z", "labels": { "k8s-app": "kube-dns" }, "annotations": { "deployment.kubernetes.io/revision": "1" }, "managedFields": [ { "manager": "minikube", "operation": "Update", "apiVersion": "apps/v1", "fieldsType": "FieldsV1", "fieldsV1": { "f:spec": { "f:replicas": {} } ........ ........ ........
Llamar al API de Kubernetes con un Token JWT
En el apartado anterior hemos visto que podemos llamar al API de Kubernetes, pero tenemos otra manera alternativa a través de un Service Account. El Service Account nos va a proporcionar un Token JWT con el nos podemos comunicar con el API de Kubernetes.
Hay que tener en cuenta que podemos tener/crear diferentes service account con diferentes accesos y/o roles, por lo que para nuestro ejemplo vamos a hacer uso del Service Account por defecto.
La mejor manera de obtener un token del Service Account es a través de TokenRequest API. Para ello ejecutamos el siguiente comando:
$ JWT_TOKEN_DEFAULT_DEFAULT=$(kubectl create token default)
Y la respuesta de la invocación al token nos devuelve el siguiente token:
eyJhbGciOiJSUzI1NiIsImtpZCI6InVMOXVkTDVaaENiUWpzMEtUcmdoWTR0UjhseG5sSHJpWFlZMTFUckN2WXcifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjYwMDU1MDA3LCJpYXQiOjE2NjAwNTE0MDcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiIyMGE2OWM3Yi0zY2MxLTQ2ZjAtYjNjNS0wMGQyNGQwODE0ZjgifX0sIm5iZiI6MTY2MDA1MTQwNywic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.Cr_Tz37q0-kVxgE97MF49sYwREUYEXbHi5ERT7sy-FZ59pttE6Lx5hQHf271wALa46RIzdVuXrGOE1Fa34QJ_RpclC8PqBKkiFE4xyJE_Wk1j4_Z9V5Esu0j_9gVXVCcGyiOKyNpLJcy94KyQqLe1U-4YepD9Tapsl5EdjIlsdxYDred26wVeDZRQAjfw4uWZdCoIinSq_V8cJ71D01l_NOZW-IcuswXyTlA-jYbHJRWVrYj_Bs1oKht7jZlW2OyhZ-0ccMJBlokZZh9wqJEhbhnhuq9C2kTVniOKC7elnLvQq_ZR9Uo8dUUm_t1oMzZc0gCBi9kUFudaNKGQ8n9Yg
Cuyo payload significa:
{ "aud": [ "https://kubernetes.default.svc.cluster.local" ], "exp": 1660055007, "iat": 1660051407, "iss": "https://kubernetes.default.svc.cluster.local", "kubernetes.io": { "namespace": "default", "serviceaccount": { "name": "default", "uid": "20a69c7b-3cc1-46f0-b3c5-00d24d0814f8" } }, "nbf": 1660051407, "sub": "system:serviceaccount:default:default" }
El token anterior deberá ir en las cabeceras de las peticiones con el nombre de Authorization Bearer. Por ejemplo:
curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \ --cacert ~/.minikube/ca.crt \ --header "Authorization: Bearer $JWT_TOKEN_KUBESYSTEM_DEFAULT"
Como hemos dicho, en función del service account que utilicemos obtendremos unos permisos u otros. El Service Account por defecto ( el token obtenido anteriormente) no nos permitirá tener acceso al listado de deployments.
Por lo que vamos vamos a obtener el token del kube-system, el cual nos garantiza el token para los permisos necesarios ya que creado para la gestión y administración del sistema de Kubernetes.
JWT_TOKEN_KUBESYSTEM_DEFAULT=$(kubectl -n kube-system create token default)
Ahora con este token volvemos a hacer la petición y obtenemos lo siguiente:
{ "kind": "DeploymentList", "apiVersion": "apps/v1", "metadata": { "resourceVersion": "2231" }, "items": [] }
Nos devuelve una lista vacía porque no tenemos ningún deployment todavía para el namespace.
Conclusión
En esta entrada hemos visto haciendo uso de comandos desde nuestro terminal como conectarse al API de Kubernetes con un cliente HTTP. Kubernetes expone un API a través de HTTPS que puede ser utilizada con diferentes fines, o por si quieres tener mayor control de lo que se hace por abajo.
Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!