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:
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
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”