we will talk about Service Accounts in Kubernetes.
The concept of service accounts
is linked to other security related concepts
in Kubernetes, such as authentication,
authorization, role-based access controls, et cetera.
However, as part of the Kubernetes
for the Application Developers Exam Curriculum,
you only need to know how to work with service accounts.
We have detailed sections
covering the other concepts and security
in the Kubernetes Administrators course.
So there are two types of accounts in Kubernetes,
a user account and a service account.
As you might already know,
the user account is used by humans,
and service accounts are used by machines.
A user account could be for an administrator
accessing the cluster to perform administrative tasks,
or a developer accessing the cluster
to deploy applications, et cetera.
A service account could be an account used by an application
to interact with the Kubernetes cluster.
For example, a monitoring application like Prometheus
uses a service account to pull the Kubernetes API
for performance metrics.
An automated built tool like Jenkins,
user service accounts to deploy applications
on the Kubernetes cluster.
Let’s take an example.
I’ve built a simple Kubernetes dashboard application
named My Kubernetes Dashboard.
It’s a simple application built in Python,
and all that it does when deployed
is retrieve the list of pods on a Kubernetes cluster
by sending a request to the Kubernetes API,
and display it on a webpage.
In order for my application to query the Kubernetes API,
it has to be authenticated.
For that, we use a service account.
To create a service account, run the command
kubectl create serviceaccount,
followed by the account name,
which is “dashboard-sa” in this case.
To view the service accounts,
run the kubectl get serviceaccount command,
this will list all the service accounts.
When the service account is created,
it also creates a token automatically.
The service account token
is what must be used by the external application
while authenticating to the Kubernetes API.
The token, however, is stored as a secret object.
In this case, it’s named dashboard-sa-token-kbbdm.
So when a service account is created,
it first creates the service account object,
and then generates a token for the service account.
It then creates a secret object
and stores that token inside the secret object.
The secret object is then linked to the service account.
To view the token, view the secret object
by running the command kubectl describe secret.
This token can then be used
as an authentication bearer token
while making a risk call to the Kubernetes API.
For example, in this simple example, using Curl,
you could provide the bearer token
as an authorization header
while making a risk call to the Kubernetes API.
In case of my custom dashboard application,
copy and paste the token into the tokens field
to authenticate the dashboard application.
So that’s how you create a new service account and use it.
You can create a service account,
assign the right permissions
using role-based access control mechanisms,
and export your service account tokens,
and use it to configure your third party application
to authenticate to the Kubernetes API.
But what if your third party application
is hosted on the Kubernetes cluster itself?
For example, we can have
our custom Kubernetes dashboard application,
or the Prometheus application
deployed on the Kubernetes cluster itself.
In that case, this whole process
of exporting the service account token,
and configuring the third party application to use it
can be made simple
by automatically mounting the service token secret
as a volume inside the pod,
hosting the third party application.
That way, the token
to access the Kubernetes API
is already placed inside the pod
and can be easily read by the application.
You don’t have to provide it manually.
If you go back and look at the list of service accounts,
you will see that there is a default service account
that exists already.
For every namespace in Kubernetes,
a service account named default is automatically created.
Each namespace has its own default service account.
Whenever a pod is created,
the default service account and its token
are automatically mounted to that pod as a volume mount.
For example, we have a simple pod definition file
that creates a pod
using my custom Kubernetes dashboard image.
We haven’t specified any secrets
or volume mounts in the definition file.
However, when the pod is created,
if you look at the details of the pod
by running the Kube control described pod command,
you see that a volume is automatically created
from the secret named default token,
which is in fact the secret containing the token
for this default service account.
The secret token is mounted at location
/var/run/secrets/kubernetes.io/serviceaccount
inside the pod.
So from inside the pod, if you run the LS command
to list the contents of the directory,
you will see the secret mounted as three separate files.
The one with the actual token is the file’s named token.
If you view contents of that file,
you will see the token to be used for accessing
the Kubernetes API.
Now remember that the default service account
is very much restricted.
It only has permission to run basic Kubernetes API queries.
If you’d like to use a different service account
such as the one we just created,
modify the pod definition file
to include a service account field
and specify the name of the new service account.
Remember, you cannot edit the service account
of an existing pod.
You must delete and recreate the pod.
However, in case of a deployment,
you will be able to edit the service account
as any changes to the pod definition file,
will automatically trigger a new rollout for the deployment.
So the deployment will take care of deleting
and recreating new pods, with the right service account.
When you look at the pod details now,
you see that the new service account is being used.
So remember, Kubernetes automatically mounts
the default service account
if you haven’t explicitly specified any.
You may choose not to mount a service account automatically
by setting the automountServiceAccountToken field
to false in the pod spec section.
Let’s now discuss some of the changes
that were made in releases
version 1.22 and 1.24 of Kubernetes
that changed the way service accounts
secrets and tokens worked.
Now, as we discussed in the previous video,
every namespace has a default service account,
and that service account has a secret object
with a token associated with it.
When a pod is created,
it automatically associates the service account
to the pod and mounts the token
to a well-known location within the pod.
In this case, it’s under
a /var/run/secrets/kubernetes.io/serviceaccount.
This makes the token accessible
to a process that’s running within the pod,
and that enables that process to query the Kubernetes API.
Now, if you list the contents of the directory
inside the pod,
you will see the secret mounted as three separate files.
The one with the actual token is the file named token.
So if you list the contents of that file,
you’ll see the token to be used
for accessing the Kubernetes API.
So all of that remains same.
This is exactly what we discussed in previous video.
Now let’s take that token that we just saw,
and if you decode this token using this command,
or you could just copy and paste this token
in the JWT website at jwt.io,
you’ll see that it has no expiry date defined
in the payload section here on the right.
So this is a token that does not have an expiry date set.
So this excerpt from the Kubernetes enhancement proposal
for creating bound service account tokens
describes this form of JWT
to be having some security and scalability related issues.
So the current implementation of JWT
is not bound to any audience and is not time bound.
As we just saw, there was no expiry date for the token.
So the JWT is valid, as long as the service account exists.
Moreover, each JWT requires a separate secret object
per service account, which results in scalability issues.
And as such, in version 1.22,
the token request API was introduced
as part of the Kubernetes enhancement proposal 1205,
that aimed to introduce a mechanism
for provisioning Kubernetes service account tokens
that are more secure and scalable via an API.
So tokens generated by the token request API
are audience bound.
They’re time bound, and object bound,
and hence are more secure.
Now, since version 1.22, when a new pod is created,
it no longer relies on the service account,
a secret token, that we just saw.
Instead, a token with a defined lifetime
is generated through the token request, API
by the service account admission controller
when the pod is created.
And this token is then mount
as a projected volume onto the pod.
So in the past, if you look at this space here,
you’d see as the secret,
that’s part of the service account mount as a secret object.
But now as you can see, it’s a projected volume
that actually communicates
with the token controller API token request API
and it gets a token for the pod.
Now with version 1.24, another enhancement was made
as part of the Kubernetes enhancement proposal 2799,
which dealt with the reduction
of secret-based service account tokens.
So in the past when a service account was created,
it automatically created a secret with a token
that has no expiry and is not bound to any audience.
This was then automatically mount as a volume to any pod
that uses that service account.
And that’s what we just saw.
But in version 1.22 that was changed the automatic mounting
of the secret object to the pod was changed,
and instead it then moved to the token request API.
So with version 1.24,
a change was made where when you create a service account,
it no longer automatically creates
a secret or a token access secret.
So you must run the command Kubectl to create token,
followed by the name of the service account
to generate a token for that service account
if you needed one.
And it will then print that token on screen.
Now, if you copy that token,
and then if you try to decode this token,
this time, you’ll see that it has an expiry date defined.
And if you haven’t specified any time limit,
then it’s usually one hour
from the time that you run the command.
You can also pass in additional options to the command
to increase the expiry of the token.
So now post version 1.24,
if you would still like to create secrets
the old way with non expiring token,
then you could still do that by creating a secret object
with the type set
to kubernetes.io/service-account-token,
and the name of the service account specified
within annotations in the metadata section like this.
So this is how the secret object will be associated
with that particular service account.
So when you do this,
just make sure that you have the service account
created first, and then create a secret object.
Otherwise the secret object will not be created.
So this will create a non expiring token in a secret object
and associated with that service account.
Now you have to be sure if you really wanna do that,
because as per the Kubernetes documentation pages
on service account token secrets,
it says you should only create
service account token secrets,
if you can’t use the token request API to obtain a token.
So that’s either the kubectl create token command
we just talked about,
or it talks to the token request API to generate that token,
or it’s the automated token creation
that happens on pods when they’re created post version 1.22.
And also, you should only create
service account token request if the security exposure
of persisting in non-expiring token credential
is acceptable to you.
Now, the token request API is recommended
instead of using the service account token,
secret objects as they are more secure
and have a bounded lifetime,
unlike the service account token secrets
that have no expiry.
Well, that’s all for now,
to read more about these changes
refer to the Kubernetes enhancement proposals
that are listed here, as well as the documentation pages
on service account and secrets.
All right, thank you very much.