Service Accounts
Existen dos tipos de cuentas en kubernetes.
- User Accounts: Estas cuentas son usadas por humanos.
- Service Accounts: Son usadas por aplicaciones.
En cualquier namespace creado una service account default es creada por defecto, vamos a verificar.
kubectl create namespace demo
namespace/demo created
kubectl get serviceaccounts -n demo
NAME SECRETS AGE
default 0 16s
# Pero nada impide que creemos una service account específica.
create sa -n default demo-sa
serviceaccount/demo-sa created
kubectl get serviceaccounts -n demo
NAME SECRETS AGE
default 0 2m20s
demo-sa 0 4s
# Para eliminar
kubectl delete sa -n demo demo-sa
serviceaccount "demo-sa" deleted
Vamos a observar que no existe una secret vinculada a este service account aún por eso tenemos 0. La secret allí es el nombre de la secret que guardará un token usado por la aplicación como bearer token para acceso a la api de kubernetes.
Antes de la versión 1.24 la secret era generada automáticamente y el token era colocado dentro de la secret.
Vamos a entender un poco de la historia.
Cada vez que un pod es creado, automáticamente la cuenta de servicio default del namespace es automáticamente montada dentro del pod como un volumeMount.
kubectl create deployment nginx --image nginx
kubectl describe pods nginx-7854ff8877-8r7hs
Name: nginx-7854ff8877-8r7hs
Namespace: default
Priority: 0
Service Account: default #<<<< NI SIQUIERA PASAMOS ESTO
...
Containers:
nginx:
Container ID: containerd://c7c95a9dda456e6da5ad14e17f8d5ab496991d177b1cadbc69ca28614a903a8a
Image: nginx
Image ID: docker.io/library/nginx@sha256:84c52dfd55c467e12ef85cad6a252c0990564f03c4850799bf41dd738738691f
...
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-c9f7j (ro) #<<<<El recurso kube-api-access-c9f7j no es directamente accesible para inspección o visualización a nivel del usuario. Es creado y gestionado internamente por Kubernetes como parte del proceso de creación y ejecución de pods para generar el token automáticamente.
...
Volumes:
kube-api-access-c9f7j:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
...
Claro podríamos usar otro service account si quisiéramos pasando dentro del spec del pod.
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
serviceAccountName: my-service-account #<<<
automountServiceAccountToken: true #<<< ESTE ES EL VALOR POR DEFECTO
status: {}
Por defecto kubernetes hace automount del service account token, pero es posible desactivar si es necesario.
¿Qué tenemos allí?
kubectl exec -it nginx-7854ff8877-8r7hs -- ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
# ca del cluster
kubectl exec -it nginx-7854ff8877-8r7hs -- cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIIeL8dKSH2rh8wDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNDAyMDgyMjU3MThhFw0zNDAyMDUyMzAyMThaMBUx
EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDRCy18tHA4HJbSDtOZo2yp4yzyJ7QnAirXImfoqjjjOe0uF8Jo4GjbCb61
GhBiWt3+A4rfJ3yGdx75PuOcnhN6siOR5oOWUHx2zDbJwSDA9pdvXJa0GdU0LTUY
mvSkUOn7DtZtLZ8q/lElIHphnSX4uqQTTL87NPL9ComFTHZAXqR8WjSQTFcYle4b
hiu6coMUq/1BKCTeN84omVqnLxuDdkdjoxnXm+Q3Jj4iQujFJ5NrxFOfCR2g4OTY
x92p1K5krnXS+z26NrzR1Up9k/2fQs129Rsn4+oAPkgs4s1CXfs9mS/5rJhqemRo
IghxaAKP+0hmSWSyKbZgqxDs3dAPAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQaEQhPwBz2wWOm66FEI7HiE+V1JjAV
BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQCRkBml9DKD
iX7Qfc/jguqr+K5FRtvraanbl4v6/fP2duGzU6fvRMv0Qs4yKnPSg0QsvXyItHXZ
4P+AgPLTYnzAuK8uqUoCLF3q/DCuH7plWn7HmXGL/JQ0KBIxwgk3pYPCO0Y53ROJ
vxiXPvFgGovtZWYj5RKn9T4F+dir6gQufXctKHel2o0OP8KfzNqz5L2pbXE58vMO
Jk6Fvd82mH1N7SpWBJgW6d3Co4FW+Zp527sjmu+IHzyctLUfK/hSSDhLDC1MWmP4
99DV0sgY1mRXTz7AIzjXyDTy0z0Rdgy9ibPSwDRbVqiZ+v2mfszkPunazohlHv8J
5w63PiNNZBeA
-----END CERTIFICATE-----
# el namespace
kubectl exec -it nginx-7854ff8877-8r7hs -- cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
default
# y el token creado automágicamente por kube-api-access
kubectl exec -it nginx-7854ff8877-8r7hs -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzM5Mjc3NDY0LCJpYXQiOjE3MDc3NDE0NjQsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueC03ODU0ZmY4ODc3LThyN2hzIiwidWlkIjoiMTk3Y2E2YjctZTEyMC00OTgxLWFmOGEtZTllOTllMmIxZjBiIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiYjRlZDJhMGUtNDBmMC00Yjc0LWEzNzgtZjgwYmJkOTEzNzNiIn0sIndhcm5hZnRlciI6MTcwNzc0NTA3MX0sIm5iZiI6MTcwNzc0MTQ2NCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.KvlOcSuG_W3YqOKUKC9nIEI8ksITGwUoKboubyGcozHRg9v_OycyG-5O6EAOdmYKE5Hd1u-b9Bl8n4NhYDF_ygf8gzu406nEf-BpBgWjogOaGylD0dIopaeC3rK7G47S9nMD1cFDGTz07hygxIQSezUfZd1EkmaSq3nK1g0yk3lcKv9fKZpFHcBsZAOEUMJyQ2cLeE_Rdaf9i4w1XTtWL-5fcbWuOjHq96rBjIejP-myjE971bvCyN3WE39vRUYZMq8aO1XIVt9_bsOd-GaTVXgN1r0LNeCz1ye743J2JYWin2_ic5fkc5vUxeNObgg03WXvUAAkcvOaetSp5yLLIQ
El jwt.io hace el decode para nosotros de forma visual.

Antiguamente no teníamos la fecha de expiración y el token para una cuenta de servicio era siempre el mismo y válido mientras la service account existiera.
Todos los pods del mismo namespace que no definían un service account usaban el mismo token. Con esta modificación todos los pods pueden usar la misma service account, pero con tokens diferentes lo que mejora la seguridad y garantiza la rotación de token (cada vez que un pod es recreado nuevos tokens son generados).
Otra situación es que una service account perdida en el cluster podría dar acceso a todo aquel namespace si tuviera permiso.
Por eso fue propuesta una TokenRequestAPI que provisionara tokens automáticamente con mayor seguridad y resolvía también algunas issues de escalabilidad que existían.
Además del jwt.io, el comando abajo también verifica usando el jq o el jwt cli.
jq -R 'split(".") | select(length > 0) | .[0],.[1] | @base64d | fromjson' <<< eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzM5Mjc3NDY0LCJpYXQiOjE3MDc3NDE0NjQsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueC03ODU0ZmY4ODc3LThyN2hzIiwidWlkIjoiMTk3Y2E2YjctZTEyMC00OTgxLWFmOGEtZTllOTllMmIxZjBiIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiYjRlZDJhMGUtNDBmMC00Yjc0LWEzNzgtZjgwYmJkOTEzNzNiIn0sIndhcm5hZnRlciI6MTcwNzc0NTA3MX0sIm5iZiI6MTcwNzc0MTQ2NCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.KvlOcSuG_W3YqOKUKC9nIEI8ksITGwUoKboubyGcozHRg9v_OycyG-5O6EAOdmYKE5Hd1u-b9Bl8n4NhYDF_ygf8gzu406nEf-BpBgWjogOaGylD0dIopaeC3rK7G47S9nMD1cFDGTz07hygxIQSezUfZd1EkmaSq3nK1g0yk3lcKv9fKZpFHcBsZAOEUMJyQ2cLeE_Rdaf9i4w1XTtWL-5fcbWuOjHq96rBjIejP-myjE971bvCyN3WE39vRUYZMq8aO1XIVt9_bsOd-GaTVXgN1r0LNeCz1ye743J2JYWin2_ic5fkc5vUxeNObgg03WXvUAAkcvOaetSp5yLLIQ
## usando jwt-cli que va a verificar en jwt.io
npm install -g jwt-cli
jwt eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzM5Mjc3NDY0LCJpYXQiOjE3MDc3NDE0NjQsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJuZ2lueC03ODU0ZmY4ODc3LThyN2hzIiwidWlkIjoiMTk3Y2E2YjctZTEyMC00OTgxLWFmOGEtZTllOTllMmIxZjBiIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiYjRlZDJhMGUtNDBmMC00Yjc0LWEzNzgtZjgwYmJkOTEzNzNiIn0sIndhcm5hZnRlciI6MTcwNzc0NTA3MX0sIm5iZiI6MTcwNzc0MTQ2NCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6ZGVmYXVsdCJ9.KvlOcSuG_W3YqOKUKC9nIEI8ksITGwUoKboubyGcozHRg9v_OycyG-5O6EAOdmYKE5Hd1u-b9Bl8n4NhYDF_ygf8gzu406nEf-BpBgWjogOaGylD0dIopaeC3rK7G47S9nMD1cFDGTz07hygxIQSezUfZd1EkmaSq3nK1g0yk3lcKv9fKZpFHcBsZAOEUMJyQ2cLeE_Rdaf9i4w1XTtWL-5fcbWuOjHq96rBjIejP-myjE971bvCyN3WE39vRUYZMq8aO1XIVt9_bsOd-GaTVXgN1r0LNeCz1ye743J2JYWin2_ic5fkc5vUxeNObgg03WXvUAAkcvOaetSp5yLLIQ
...
✻ Header
{
"alg": "RS256",
"kid": "h9S_NPctZsbqi6gHkfi8VJcIJPEewsT2DvDuOG9VlkE"
}
✻ Payload
{
"aud": [
"https://kubernetes.default.svc.cluster.local"
],
"exp": 1739277464, # Esta fecha de expiración es una epoch o sea el número de segundos a partir de 1970
"iat": 1707741464,
"iss": "https://kubernetes.default.svc.cluster.local",
"kubernetes.io": {
"namespace": "default",
"pod": {
"name": "nginx-7854ff8877-8r7hs",
"uid": "197ca6b7-e120-4981-af8a-e9e99e2b1f0b"
},
"serviceaccount": {
"name": "default",
"uid": "b4ed2a0e-40f0-4b74-a378-f80bbd91373b"
},
"warnafter": 1707745071
},
"nbf": 1707741464,
"sub": "system:serviceaccount:default:default"
}
iat: 1707741464 2/12/2024, 9:37:44 AM
nbf: 1707741464 2/12/2024, 9:37:44 AM
exp: 1739277464 2/11/2025, 9:37:44 AM
✻ Signature KvlOcSuG_W3YqOKUKC9nIEI8ksITGwUoKboubyGcozHRg9v_OycyG-5O6EAOdmYKE5Hd1u-b9Bl8n4NhYDF_ygf8gzu406nEf-BpBgWjogOaGylD0dIopaeC3rK7G47S9nMD1cFDGTz07hygxIQSezUfZd1EkmaSq3nK1g0yk3lcKv9fKZpFHcBsZAOEUMJyQ2cLeE_Rdaf9i4w1XTtWL-5fcbWuOjHq96rBjIejP-myjE971bvCyN3WE39vRUYZMq8aO1XIVt9_bsOd-GaTVXgN1r0LNeCz1ye743J2JYWin2_ic5fkc5vUxeNObgg03WXvUAAkcvOaetSp5yLLIQ
# Transformando la fecha para algo que podamos leer, solo de curiosidad
date -d @1739277464
mar 11 feb 2025 09:37:44 -03 # 1 AÑO
No es posible editar la service account de un pod, es necesario eliminar y recrear uno nuevo. En el caso de un deployment es posible editar el deployment pues él crea un nuevo replicaset con nuevas configuraciones de pod.
Si es necesario podemos crear un token para una service account que no es usada en ningún pod, pero para acceso de tercero podemos hacer.
kubectl get sa
NAME SECRETS AGE
default 0 3d15h
my-service-account 0 157m #<<< vamos a usar esta
kubectl create token my-service-account --duration 87600h
eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoyMDIzMTA4NjU1LCJpYXQiOjE3MDc3NDg2NTUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6Im15LXNlcnZpY2UtYWNjb3VudCIsInVpZCI6IjExMDcwMmZmLTkwNjAtNDAyNy1hMTlmLWNjMDQyOGE2NzBiZiJ9fSwibmJmIjoxNzA3NzQ4NjU1LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpteS1zZXJ2aWNlLWFjY291bnQifQ.BzVKg4oVTCKScv76zb-507q3EenpaQF-0XbcmqDmEK7t23GY1euIMQdolgAriu8KzYet9TY_1SCKRn3vsR4a6qjl89BmWO9yxUuuaLLy1TmGRKr3KC854XaldlhZ7aT4hqg20Ut9V7lnPjUKBvIZ8xzILHkhv_ZlZUS9C7BzBeaR9IJY-qnQ5PUnxb5WqyThmdLWWwyUPQtve7YJuOEGSpvXo3AoXad9OjNXAkjPuxqWtxyIus8BIzTWxn0loQ1L47mHfMY_AAfBhblwNLx15GZr6Mjh1wzR0uNmzh2stcANYudcagz9bGtkMqel-rF-9ingoSm2cHEFeHdBbFY3EQ
¿Este token puedo usarlo? ¿Y si quiero eliminarlo? ¿Dónde puedo ver los tokens creados para eliminar?
Para replicar el escenario antiguo y tener un token sin expiración vinculado a una service account, primero necesitamos tener la service account y después crear una secret con un tipo especificado y a través de las annotations vincular la secret a serviceaccount.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token # Tipo específico de token
metadata:
name: my-service-account-token # nombre
annotations:
kubernetes.io/service-account.name: my-service-account # Service Account que usará
EOF
kubectl describe secrets my-service-account-token
Name: my-service-account-token
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: my-service-account
kubernetes.io/service-account.uid: 110702ff-9060-4027-a19f-cc0428a670bf
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1107 bytes
namespace: 7 bytes
## Vamos a verificar este token aquí
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Im15LXNlcnZpY2UtYWNjb3VudC10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJteS1zZXJ2aWNlLWFjY291bnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxMTA3MDJmZi05MDYwLTQwMjctYTE5Zi1jYzA0MjhhNjcwYmYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpteS1zZXJ2aWNlLWFjY291bnQifQ.frN4SSbI-SgoGLNjyapdOaUlc_WmTTFmWBO9hejdCnCkf5NfjiFVNkxSGht-cKNvlI2ADLz1-gVB3vIRbxFw-hXmxsZeH5heK5OeyMctpcRZrj-BRpwo1ubZ14VH94VH-nF8q7MwaA84uuuK0CiBOdSLITXkKRzVUkxR3qPa7MBNUs-0HIlMZQBzxkgQ24lu3cvPRX1rP9HX3UmxZaemARBBrqki03t1udJzDWwPkc48H_r3I0zSjdqxoIJ0NtDXj_fJdv8rjaeJC8TiXJvOmtvhpkleU0NC51BsjRi7ennWZ2MYO_9XjX4NDUkBcsovEAOOo4T7olJpv9lC3zSlwg
# VERIFICANDO
jwt eyJhbGciOiJSUzI1NiIsImtpZCI6Img5U19OUGN0WnNicWk2Z0hrZmk4VkpjSUpQRWV3c1QyRHZEdU9HOVZsa0UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Im15LXNlcnZpY2UtYWNjb3VudC10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJteS1zZXJ2aWNlLWFjY291bnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxMTA3MDJmZi05MDYwLTQwMjctYTE5Zi1jYzA0MjhhNjcwYmYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpteS1zZXJ2aWNlLWFjY291bnQifQ.frN4SSbI-SgoGLNjyapdOaUlc_WmTTFmWBO9hejdCnCkf5NfjiFVNkxSGht-cKNvlI2ADLz1-gVB3vIRbxFw-hXmxsZeH5heK5OeyMctpcRZrj-BRpwo1ubZ14VH94VH-nF8q7MwaA84uuuK0CiBOdSLITXkKRzVUkxR3qPa7MBNUs-0HIlMZQBzxkgQ24lu3cvPRX1rP9HX3UmxZaemARBBrqki03t1udJzDWwPkc48H_r3I0zSjdqxoIJ0NtDXj_fJdv8rjaeJC8TiXJvOmtvhpkleU0NC51BsjRi7ennWZ2MYO_9XjX4NDUkBcsovEAOOo4T7olJpv9lC3zSlwg
...
## NO TENEMOS TIEMPO DE EXPIRACIÓN
✻ Header
{
"alg": "RS256",
"kid": "h9S_NPctZsbqi6gHkfi8VJcIJPEewsT2DvDuOG9VlkE"
}
✻ Payload
{
"iss": "kubernetes/serviceaccount",
"kubernetes.io/serviceaccount/namespace": "default",
"kubernetes.io/serviceaccount/secret.name": "my-service-account-token",
"kubernetes.io/serviceaccount/service-account.name": "my-service-account",
"kubernetes.io/serviceaccount/service-account.uid": "110702ff-9060-4027-a19f-cc0428a670bf",
"sub": "system:serviceaccount:default:my-service-account"
}
✻ Signature frN4SSbI-SgoGLNjyapdOaUlc_WmTTFmWBO9hejdCnCkf5NfjiFVNkxSGht-cKNvlI2ADLz1-gVB3vIRbxFw-hXmxsZeH5heK5OeyMctpcRZrj-BRpwo1ubZ14VH94VH-nF8q7MwaA84uuuK0CiBOdSLITXkKRzVUkxR3qPa7MBNUs-0HIlMZQBzxkgQ24lu3cvPRX1rP9HX3UmxZaemARBBrqki03t1udJzDWwPkc48H_r3I0zSjdqxoIJ0NtDXj_fJdv8rjaeJC8TiXJvOmtvhpkleU0NC51BsjRi7ennWZ2MYO_9XjX4NDUkBcsovEAOOo4T7olJpv9lC3zSlwg
Ahora algunas curiosidades que encontré en el camino.
## Si miramos la service account tenemos el token allá vinculado
kubectl describe sa my-service-account
Name: my-service-account
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: my-service-account-token #<<<<
Events: <none>
## Tenemos la secret
kubectl get secret
NAME TYPE DATA AGE
my-service-account-token kubernetes.io/service-account-token 3 4m54s
## Pero el Service Account no muestra de hecho que tiene una secret. ¿LOCURA?
kubectl get serviceaccounts
NAME SECRETS AGE
default 0 3d15h
my-service-account 0 3h2m #<<<< ????
Podemos crear roles y hacer rolebinding con los service accounts normalmente. En lugar de User es ServiceAccount.