WEBVTT

00:00.902 --> 00:02.902
-Hello, and welcome to this lecture.

00:03.017 --> 00:07.494
In this lecture, we will talk about
Service Accounts in Kubernetes.

00:07.906 --> 00:10.013
The concept of service accounts

00:10.093 --> 00:14.252
is linked to other
security-related concepts in Kubernetes,

00:14.363 --> 00:20.460
such as authentication, authorization,
role-based access controls, et cetera.

00:20.663 --> 00:22.753
However, as part of the Kubernetes

00:22.833 --> 00:25.777
for the application developers
exam curriculum,

00:25.965 --> 00:29.661
you only need to know
how to work with service accounts.

00:29.928 --> 00:31.126
We have detailed sections

00:31.206 --> 00:36.714
covering the other concepts and security
in the Kubernetes administrators course.

00:37.076 --> 00:39.943
There are two types
of accounts in Kubernetes.

00:40.093 --> 00:42.789
A user account and a service account.

00:42.890 --> 00:44.623
As you might already know,

00:44.713 --> 00:50.555
the user account is used by humans,
and service accounts are used by machines.

00:50.718 --> 00:54.990
A user account could be
for an administrator accessing the cluster

00:55.070 --> 00:57.372
to perform administrative tasks,

00:57.521 --> 01:03.223
or a developer accessing the cluster
to deploy applications, et cetera.

01:03.763 --> 01:08.391
A service account could be an account
used by an application

01:08.471 --> 01:10.778
to interact with a Kubernetes cluster.

01:10.880 --> 01:16.041
For example, a monitoring application
like Prometheus uses a service account

01:16.127 --> 01:19.617
to pull the Kubernetes API
for performance metrics.

01:19.783 --> 01:23.859
An automated build tool
like Jenkins uses service accounts

01:23.952 --> 01:26.934
to deploy applications
on the Kubernetes cluster.

01:27.436 --> 01:29.062
Let's take an example.

01:29.401 --> 01:33.184
I've built a simple
Kubernetes dashboard application

01:33.301 --> 01:35.894
named My Kubernetes Dashboard.

01:36.062 --> 01:41.308
It's a simple application built in Python,
and all that it does when deployed

01:41.388 --> 01:45.146
is retrieve the list of pods
on a Kubernetes cluster

01:45.242 --> 01:50.916
by sending a request to the Kubernetes API
and display it on a web page.

01:51.354 --> 01:55.094
In order for my application
to query the Kubernetes API,

01:55.273 --> 01:57.486
it has to be authenticated.

01:57.721 --> 02:00.683
For that, we use a service account.

02:00.926 --> 02:02.512
To create a service account,

02:02.762 --> 02:03.833
run the command,

02:03.935 --> 02:06.464
kubectl create serviceaccount,

02:06.544 --> 02:08.110
followed by the account name,

02:08.219 --> 02:12.167
which is dashboard-sa, in this case.

02:12.590 --> 02:14.215
To view the service account,

02:14.324 --> 02:17.227
run the kubectl get serviceaccount
command.

02:17.308 --> 02:19.363
This will list all the service accounts.

02:20.294 --> 02:25.460
When the service account is created,
it also creates a token automatically.

02:25.677 --> 02:28.855
The service account token
is what must be used

02:28.942 --> 02:30.753
by the external application

02:30.833 --> 02:33.762
while authenticating
to the Kubernetes API.

02:34.066 --> 02:37.795
The token, however,
is stored as a secret object.

02:37.890 --> 02:39.663
In this case, it's named

02:39.743 --> 02:45.350
dashboard-sa-token-kbbdm.

02:45.632 --> 02:47.791
When a service account is created,

02:47.873 --> 02:51.073
it first creates
the service account object,

02:51.271 --> 02:54.694
and then generates a token
for the service account.

02:54.893 --> 02:57.236
It then creates a secret object

02:57.316 --> 03:01.506
and stores that token
inside the secret object.

03:01.920 --> 03:06.109
The secret object
is then linked to the service account.

03:06.357 --> 03:07.547
To view the token,

03:07.677 --> 03:10.659
view the secret object
by running the command,

03:10.712 --> 03:14.054
kubectl describe secret.

03:14.388 --> 03:18.216
This token can then be used
as an authentication beta token

03:18.296 --> 03:21.234
while making a risk call
to the Kubernetes API.

03:21.349 --> 03:25.282
For example, in this simple example,
using curl,

03:25.375 --> 03:29.069
you could provide the beta token
as an authorization header

03:29.149 --> 03:32.095
while making a risk call
to the Kubernetes API.

03:32.559 --> 03:35.332
In case of my custom
dashboard application,

03:35.421 --> 03:37.217
copy and paste the token

03:37.315 --> 03:41.622
into the tokens field
to authenticate the dashboard application.

03:42.197 --> 03:45.953
That's how you create
a new service account and use it.

03:46.110 --> 03:49.469
You can create a service account,
assign the right permissions

03:49.566 --> 03:52.226
using role-based access
control mechanisms,

03:52.309 --> 03:54.871
which is out of scope for this course,

03:55.013 --> 03:57.257
and export your service account tokens,

03:57.337 --> 04:00.584
and use it to configure
your third-party application

04:00.685 --> 04:03.477
to authenticate to the Kubernetes API.

04:04.352 --> 04:06.614
What if your third-party application

04:06.694 --> 04:09.787
is hosted
on the Kubernetes cluster itself?

04:09.887 --> 04:14.568
For example, we can have our custom
Kubernetes dashboard application,

04:14.648 --> 04:20.237
or the Prometheus application
deployed on the Kubernetes cluster itself.

04:20.575 --> 04:25.482
In that case, this whole process
of exporting the service accounts token

04:25.577 --> 04:28.748
and configuring
the third-party application to use it

04:28.828 --> 04:33.763
can be made simple by automatically
mounting the service token secret

04:33.843 --> 04:38.547
as a volume inside the pod
hosting the third-party application.

04:38.837 --> 04:42.251
That way,
the token to access the Kubernetes API

04:42.332 --> 04:44.902
is already placed inside the pod

04:44.987 --> 04:47.909
and can be easily read by the application.

04:48.141 --> 04:50.327
You don't have to provide it manually.

04:50.942 --> 04:54.090
If you go back and look
at the list of service accounts,

04:54.230 --> 04:57.165
you will see that
there is a default service account

04:57.245 --> 04:58.838
that exists already.

04:59.009 --> 05:01.333
For every namespace in Kubernetes,

05:01.423 --> 05:06.310
a service account named default
is automatically created.

05:06.680 --> 05:11.304
Each namespace has its own
default service account.

05:11.594 --> 05:16.518
Whenever a pod is created,
the default service account and its token

05:16.643 --> 05:21.161
are automatically mounted
to that pod as a volume mount.

05:21.286 --> 05:25.180
For example,
we have a simple pod definition file

05:25.282 --> 05:30.023
that creates a pod using my
custom Kubernetes dashboard image.

05:30.203 --> 05:34.781
We haven't specified any secrets
or volume mounts in the definition file.

05:34.910 --> 05:39.378
However, when the pod is created,
if you look at the details of the pod

05:39.458 --> 05:42.340
by running
the kubectrl describe pod command,

05:42.495 --> 05:44.057
you see that a volume

05:44.139 --> 05:48.974
is automatically created
from the secret named default token,

05:49.065 --> 05:50.240
which is in fact,

05:50.335 --> 05:54.614
the secret containing the token
for this default service account.

05:55.592 --> 05:58.963
The secret token is mounted at location

05:59.043 --> 06:04.433
var/run/secrets/kubernetes.io/serviceaccount

06:04.514 --> 06:05.942
inside the pod.

06:06.214 --> 06:07.578
From inside the pod,

06:07.658 --> 06:11.464
if you run the LS command
to list the contents of the directory,

06:11.572 --> 06:15.451
you will see the secret mounted
as three separate files.

06:15.991 --> 06:20.458
The one with the actual token
is the files named token.

06:20.562 --> 06:22.413
If you view contents of that file,

06:22.493 --> 06:27.008
you will see the token to be used
for accessing the Kubernetes API.

06:27.931 --> 06:32.850
Now, remember that the default
service account is very much restricted.

06:33.044 --> 06:38.644
It only has permission
to run basic Kubernetes API queries.

06:39.146 --> 06:41.621
If you'd like to use
a different service account

06:41.701 --> 06:43.886
such as the one we just created,

06:43.999 --> 06:48.402
modify the pod definition file
to include a service account field,

06:48.482 --> 06:51.649
and specify the name
of the new service account.

06:51.924 --> 06:56.053
Remember, you cannot edit
the service account of an existing pod.

06:56.134 --> 06:59.639
You must delete and recreate the pod.

06:59.742 --> 07:02.252
However, in case of a deployment,

07:02.357 --> 07:04.986
you will be able to edit
the service account,

07:05.064 --> 07:07.898
as any changes to the pod definition file

07:07.999 --> 07:12.237
will automatically trigger
a new rollout for the deployment.

07:13.003 --> 07:17.533
The deployment will take care
of deleting and recreating new pods

07:17.613 --> 07:19.838
with the right service account.

07:20.318 --> 07:22.907
When you look at the pod details now,

07:23.001 --> 07:26.444
you see that
the new service account is being used.

07:27.290 --> 07:32.353
Remember, Kubernetes automatically
mounts the default service account

07:32.433 --> 07:36.217
if you haven't explicitly specified any.

07:36.381 --> 07:39.975
You may choose not to mount
a service account automatically

07:40.062 --> 07:43.658
by setting the auto mount
service account token field

07:43.748 --> 07:46.484
to false in the pod spec section.

07:46.602 --> 07:48.942
Let's now discuss some of the changes

07:49.022 --> 07:54.389
that were made in releases
version 1.22 and 1.24 of Kubernetes

07:54.520 --> 07:55.994
that changed the way

07:56.063 --> 07:59.743
service accounts,
secrets and tokens worked.

08:00.558 --> 08:02.584
Now,
as we discussed in the previous video,

08:02.659 --> 08:05.987
every namespace has
a default service account,

08:06.167 --> 08:09.063
and that service account
has a secret object

08:09.144 --> 08:11.432
with a token associated with it.

08:11.603 --> 08:13.007
When a pod is created,

08:13.087 --> 08:17.547
it automatically associates
the service account to the pod

08:17.669 --> 08:21.918
and mounts the token
to a well-known location within the pod.

08:22.259 --> 08:27.927
In this case, it's under a var run secrets
Kubernetes.io/service account.

08:28.210 --> 08:31.575
This makes the token
accessible to a process

08:31.655 --> 08:33.411
that's running within the pod,

08:33.527 --> 08:37.134
and that enables that process
to query the Kubernetes API.

08:38.809 --> 08:41.459
Now, if you list the contents
of the directory inside the pod,

08:41.468 --> 08:44.501
you will see the secret mounted
as three separate files.

08:44.604 --> 08:47.570
The one with the actual token
is the file named token,

08:47.652 --> 08:49.966
so if you list the contents of that file,

08:50.058 --> 08:53.225
you'll see the token to be used
for accessing the Kubernetes API,

08:53.363 --> 08:55.099
so all of that remains same.

08:55.179 --> 08:58.624
This is exactly what we discussed
in the previous video.

08:58.723 --> 09:02.130
Now let's take that token
that we just saw,

09:02.170 --> 09:05.989
and if you decode this token
using this command,

09:06.139 --> 09:09.589
or you could just copy
and paste this token

09:09.670 --> 09:13.490
in the JWT website@jwt.io,

09:13.803 --> 09:17.248
you'll see that
it has no expiry date defined

09:17.329 --> 09:20.840
in the payload section
here on the right.

09:20.921 --> 09:26.575
This is a token
that does not have an expiry date set.

09:26.980 --> 09:31.007
This excerpt from the Kubernetes
enhancement proposal

09:31.087 --> 09:36.674
for creating bound service account tokens
describes this form of JWT

09:36.807 --> 09:40.006
to be having some security
and scalability-related issues.

09:40.272 --> 09:42.186
The current implementation of JWT

09:42.267 --> 09:45.723
is not bound to any audience
and is not time-bound

09:45.873 --> 09:48.628
as we just saw,
there was no expiry date for the token.

09:48.974 --> 09:53.324
The JWT is valid as long
as the service account exists.

09:53.452 --> 09:55.933
Moreover, each JWT requires

09:56.013 --> 09:58.601
a separate secret object
per service account,

09:58.783 --> 10:01.368
which results in scalability issues.

10:02.790 --> 10:07.281
As such, in version 1.22,
the token request API was introduced

10:07.377 --> 10:11.012
as part of the Kubernetes
enhancement proposal 1205

10:11.272 --> 10:13.386
that aimed to introduce a mechanism

10:13.466 --> 10:15.928
for provisioning Kubernetes
service account tokens

10:16.062 --> 10:19.513
that are more secure
and scalable via an API.

10:19.983 --> 10:23.951
Tokens generated by the token request API
are audience bound.

10:24.036 --> 10:28.206
They're time-bound and object-bound,
and hence are more secure.

10:29.892 --> 10:33.425
Now, since version 1.22,
when a new pod is created,

10:33.505 --> 10:37.526
it no longer relies
on the service account secret token

10:37.690 --> 10:39.366
that we just saw.

10:39.523 --> 10:45.042
Instead, a token with a defined lifetime
is generated through the token request API

10:45.535 --> 10:47.472
by the service
account admission controller

10:47.622 --> 10:48.847
when the pod is created,

10:49.061 --> 10:54.120
and this token is then mounted
as a projected volume into the pod.

10:54.418 --> 10:57.399
In the past,
if you look at this space here,

10:57.479 --> 10:59.280
you'd see the secret

10:59.403 --> 11:02.356
that's part of the service account mount
as a secret object,

11:02.476 --> 11:05.984
but now as you can see,
it's a projected volume

11:06.527 --> 11:10.954
that actually communicates
with the token controller API,

11:11.036 --> 11:12.489
token request API

11:12.958 --> 11:17.813
and it gets a token for the pod.

11:18.582 --> 11:21.786
Now with version 1.24,
another enhancement was made

11:21.848 --> 11:26.135
as part of the Kubernetes
enhancement proposal 2799,

11:26.365 --> 11:29.964
which dealt with the reduction
of secret-based service account tokens.

11:30.082 --> 11:33.525
In the past
when a service account was created,

11:33.757 --> 11:37.379
it automatically created
a secret with a token

11:37.473 --> 11:41.204
that has no expiry
and is not bound to any audience.

11:41.588 --> 11:44.862
This was then automatically mount
as a volume to any pod

11:44.940 --> 11:48.785
that uses that service account,
and that's what we just saw.

11:49.100 --> 11:53.213
In version 1.22 that was changed,
the automatic mounting

11:53.364 --> 11:56.665
of the secret object
to the pod was changed,

11:56.768 --> 12:02.343
and instead it then moved
to the token request API.

12:02.640 --> 12:07.829
With version 1.24, a change was made
where when you create a service account,

12:08.019 --> 12:13.742
it no longer automatically creates
a secret or a token access secret.

12:14.086 --> 12:16.550
You must run the command
kubectl create token

12:16.631 --> 12:18.378
followed by the name
of the service account

12:18.440 --> 12:20.954
to generate a token
for that service account

12:21.035 --> 12:22.986
if you needed one.

12:23.463 --> 12:26.504
It will then print that token on screen.

12:26.988 --> 12:30.837
Now if you copy that token,
and then if you try to decode this token,

12:30.917 --> 12:33.471
this time you'll see that
it has an expiry date defined,

12:33.551 --> 12:35.588
and if you haven't specified
any time limit,

12:35.694 --> 12:38.490
then it's usually one hour from the time
that you ran the command.

12:38.636 --> 12:41.310
You can also pass in additional options
to the command

12:41.411 --> 12:44.287
to increase the expiry of the token.

12:45.730 --> 12:48.608
Now post version 1.24,

12:48.855 --> 12:53.689
if you would still like to create secrets
the old way with non-expiring token,

12:53.780 --> 12:56.873
then you could still do that
by creating a secret object

12:56.953 --> 13:01.984
with the type set
to Kubernetes.io/service-account-token.

13:02.297 --> 13:04.232
The name of the service account specified

13:04.354 --> 13:07.677
within annotations
in the metadata section like this.

13:07.867 --> 13:10.223
This is how the secret object

13:10.303 --> 13:13.166
will be associated
with that particular service account.

13:13.831 --> 13:18.756
When you do this, just make sure that
you have the service account created first

13:18.897 --> 13:20.332
and then create a secret object,

13:20.412 --> 13:23.206
otherwise the secret object
will not be created.

13:23.515 --> 13:26.557
This will create a nonexpiring token
in a secret object

13:26.692 --> 13:29.431
and associated with that service account.

13:30.349 --> 13:33.743
Now you have to be sure
if you really want to do that

13:33.823 --> 13:35.787
because that's where
the Kubernetes documentation pages

13:35.846 --> 13:37.858
on service account token secrets.

13:37.977 --> 13:41.037
It says you should only create
service account token secrets

13:41.117 --> 13:45.621
if you can't use
the token request API to obtain a token.

13:45.746 --> 13:48.660
That's either the kubectl create
token command we just talked about,

13:48.741 --> 13:53.298
or it talks to the token request API
to generate that token,

13:53.404 --> 13:56.453
or it's the automated token creation
that happens on pods

13:56.533 --> 14:00.120
when they are created post version 1.22.

14:00.468 --> 14:03.205
Also, you should only create
service account token request

14:03.292 --> 14:07.233
if the security exposure of persisting
a non-expiring token credential

14:07.319 --> 14:08.943
is acceptable to you.

14:09.052 --> 14:12.063
Now, the token request API
is recommended

14:12.164 --> 14:15.418
instead of using the service account
token secret objects

14:15.498 --> 14:18.112
as they are more secure
and have a bounded lifetime,

14:18.192 --> 14:22.371
unlike the service account secrets
that have no expiry.

14:22.948 --> 14:24.232
That's all for now.

14:24.344 --> 14:25.555
To read more about these changes,

14:25.589 --> 14:27.917
refer to the Kubernetes
enhancement proposals

14:28.075 --> 14:30.476
that are listed here
as well as the documentation pages

14:30.602 --> 14:33.297
on service accounts and secrets.

14:33.461 --> 14:34.484
All right. Thank you very much.

