Usando el ServiceAccount en Kubernetes


El ServiceAccount es usado en Kubernetes para proporcionar una identidad a los pods. Todo Pod que quiera interaccionar con el API Server deberá de autenticarse con un particular ServiceAccount. Por defecto, se usa el default. En esta entrada Usando el ServiceAccount en Kubernetes, vamos a ver como podemos comunicarnos con el API Server desde el Pod. Si quieres empezar con una introducción de kubernetes, echa un ojo a entradas anteriores.

¿Qué es el API Server?

API Server, es un componente de kubernetes que se encarga de validar y configurar toda la información para los objectos de kubernetes. API Server, es básicamente un servicio REST que proporciona información y permite interactuar con los componentes.

El kube-apiserver, es un componente del Control Plane, y se encarga de interceptar y procesar las llamadas REST de los usuarios y llamadas externas. En el transcurso de este procesamiento, se lee el estado del clúster de Kubernetes, para poder proporcionar el estado deseado.

Comunicación con el API Server

Como hemos comentado en la introducción, cada Pod usa un ServiceAccount que contiene un token para poder autenticarse y comunicarse con el API Server.

Para poder comunicarse con el API Server, podemos no crear ningún serviceAccount específico con el que entonces, se le asignará el SerivceAccount por defecto (default), o podemos crear uno:

kubectl create serviceaccount test

Roles, ClusterRoles, RoleBinding y ClusterRoleBinding

Para comunicarnos con el API Server vamos a hacer uso de un token, al que además podemos establecer Roles y ClusterRoles, los cuales contienen unas reglas que van a representar un conjunto de permisos, los cuales añaden, es decir, no tienen la capacidad de rechazar o negar algún permiso. Un Rol, podrá añadir permisos dentro de un namespace, en cambio si quieres añadir permisos a lo largo de un cluster, habrá que hacerlo a traves de ClusterRole.

Para que tanto Roles como ClusterRoles sean efectivos, son necesarios hacer uso de RoleBinding y ClusterRoleBinding, el primero asignará permisos dentro de un namespace definido, y el segundo dará acceso a todo el clúster.

Comunicación con el API Server

Tal y como hemos comentado arriba cada Pod hará uso de un ServiceAccount con un token y con unos roles establecidos para poder acceder al API Server, al que vamos a poder:

  • Acceder desde dentro del Cluster: el API Server puede ser accedido desde dentro usando el servicio dedicado de tipo ClusterIP llamado Kubernetetes. kubectl get svc.
  • Acceder desde fuera del Cluster: para acceder desde fuera del cluster, podemos mirar en el directorio $HOME/.kube/config, el endpoint que aparece.

Obtener Token JWT del ServiceAccount

Cada vez que se crea un namespace, se le otorga un ServiceAccount por defecto, el cual se llama default. Podemos escribir el siguiente comando para verificarlo:

kubectl get sa --all-namespaces

Tal y como hemos comentado anteriormente, cada ServiceAccount va a llevar un token asociado, que será el necesario para comunicarse con el API Server. Para poder verlo vamos a ejecutar el siguiente comando, para obtener información sobre el ServiceAccount default:

kubectl get sa default -o yaml

El comando anterior nos ha devuelto:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-09-08T16:02:50Z"
  name: default
  namespace: default
  resourceVersion: "398"
  selfLink: /api/v1/namespaces/default/serviceaccounts/default
  uid: c6fd23a3-1dcc-4b7f-9d79-81aecaf74306
secrets:
- name: default-token-jwmt9

Con lo que en la información anterior vemos que hay un secret con nombre default-token-jwmt9, por lo que vamos a mirar que tiene ese secret:

kubectl get secrets default-token-jwmt9 -o yaml

Recuerda que añadimos -o yaml para mostrar por pantalla en formato «yaml».

Obtenemos un yaml, más o menos como la siguiente imagen:

Secret del ServiceAccount
Secret del ServiceAccount

Vamos a verlos en más detalle mejor:

apiVersion: v1
data:
  ca.crt: LS0tL...XVsdA==
  token: ZXlKa...
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
    kubernetes.io/service-account.uid: c6fd23a3-1dcc-4b7f-9d79-81aecaf74306
  creationTimestamp: "2020-09-08T16:02:51Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    manager: kube-controller-manager
    operation: Update
    time: "2020-09-08T16:02:51Z"
  name: default-token-jwmt9
  namespace: default
  resourceVersion: "392"
  selfLink: /api/v1/namespaces/default/secrets/default-token-jwmt9
  uid: c319478b-dd4f-4aa0-b5c8-ae268758d4fd
type: kubernetes.io/service-account-token

Como podemos ver en el yaml anterior hay dos puntos a destacar:

  • ca.crt: es la ca codificada en Base64 del cluster.
  • token: es el token JWT en Base64, para autenticar contra el API Server. Se puede copiar y pegar y ver en jwt.io

Llamar al API Server haciendo uso del Token JWT del ServiceAccount

Mediante el ServiceAccount por defecto

Primero de todo vamos a crear un pod con la típica imagen de alpine, y al no asignar ningún serviceaccount será el default:

apiVersion: v1
kind: Pod
metadata:
  name: serviceaccount-demo
  labels:
    purpose: demonstrate-serviceaccount-demo
spec:
  containers:
  - name: serviceaccount-demo
    image: alpine:3.9
    command: ["sleep", "10000"]
  restartPolicy: OnFailure

Vamos a asegurarnos que el serviceaccount creado es el de por defecto:

kubectl get po/serviceaccount-demo -o yaml
ServiceAccount default - Usando el ServiceAccount en Kubernetes
ServiceAccount default

Llamar al ServiceAccount con el token

Una vez que el pod esta desplegado vamos a realizar una llamada al API Server utilizando el token del ServiceAccount, para ello vamos a acceder al contendeor:

kubectl exec -ti serviceaccount-demo -- sh

y desde dentro instalar curl:

apk add --update curl

obtener el TOKEN que se encuentra en /run/secrets/kubernetes.io/serviceaccount/token:

TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
curl -X GET --header 'Authorization: Bearer $TOKEN' https://kubernetes/api/v1/ --insecure

Y veremos toda la lista de recursos a la que tenemos acceso con ese token.

Mediante creación de ServiceAccount

Vamos a crear en primer lugar un service account:

kubectl create serviceaccount serviceaccount-test

Tras crear el serviceaccount, vamos a crear una serie de reglas mediante la creación de un rol, tal y como comentamos en el apartado de roles:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 name: list-pods
 namespace: default
rules:
 — apiGroups:
   — ''
 resources:
   — pods
 verbs:
   — list
kubectl apply -f role.yaml

Una vez hemos creado el rol, hay que enlazarlo mediante un RoleBinding al serviceaccount:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
 name: list-pods_servicaccount-test
 namespace: default
roleRef:
 kind: Role
 name: list-pods
 apiGroup: rbac.authorization.k8s.io
subjects:
 — kind: ServiceAccount
   name: serviceaccount-test
   namespace: default

Tras ejecutar el anterior fichero con el comando de siempre: kubectl apply -f fichero.yaml. Podemos listar los pods de dentro del namespace, bajo las reglas definidas.

Vamos a asociar el serviceaccount a un pod, para ello:

apiVersion: v1
kind: Pod
metadata:
  name: serviceaccount-test
  labels:
    purpose: demonstrate-serviceaccount-demo
spec:
  serviceAccountName: demo-sa
  containers:
  - name: serviceaccount-demo
    image: alpine:3.9
    command: ["sleep", "10000"]
  restartPolicy: OnFailure

Con la creación de este Pod le hemos asociado el serviceaccount creado. Si, como hicimos anteriormente, hacemos una llamada, pero al namespace default, obtendremos la lista de pods que se están ejecutando, ya que se ha definido en los roles. En este caso haríamos la siguiente llamada:

https://kubernetes/api/v1/namespaces/default/pods/

Conclusión

Vamos a ver un resumen de lo que hemos visto en el artículo Usando el ServiceAccount en Kubernetes.

Cada Pod puede comunicarse por defecto con e API Server que se encuentra en su Pod. Al crear un Pod podemos no crear ningún ServiceAccount por lo que se usará el de por defecto, pero este tendrá permisos limitados, por lo que es mejor generar un ServiceAccount para nuestra aplicación y dar, como hemos visto antes, los permisos que requiera.

El API Server, al final funciona como un API Rest, por lo que con el token correcto que podemos encontrar accediendo al contenedor a sus secretos, podemos llamarlo.

Otros artículos que te pueden interesar

Ejemplo de aplicación de Spring Boot y Kubernetes

Ejercicios de Labels y Selectors en Kubernetes

Deployment rolling update y rolling back con kubernetes


1 pensamiento sobre “Usando el ServiceAccount en Kubernetes

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *