diff --git a/slides/k8s/authn-authz-k8s201.md b/slides/k8s/authn-authz-k8s201.md
index 5126d3b1..ad80639a 100644
--- a/slides/k8s/authn-authz-k8s201.md
+++ b/slides/k8s/authn-authz-k8s201.md
@@ -58,7 +58,7 @@
---
-## Anonymous requests
+## Anonymous & unauthenticated requests
- If any authentication method *rejects* a request, it's denied
@@ -72,93 +72,16 @@
- By default, the anonymous user can't do anything
- (that's what you get if you just `curl` the Kubernetes API)
-
----
-
-## Authentication with TLS certificates
-
-- This is enabled in most Kubernetes deployments
-
-- The user name is derived from the `CN` in the client certificates
-
-- The groups are derived from the `O` fields in the client certificate
-
-- From the point of view of the Kubernetes API, users do not exist
-
- (i.e. they are not stored in etcd or anywhere else)
-
-- Users can be created (and added to groups) independently of the API
-
-- The Kubernetes API can be set up to use your custom CA to validate client certs
-
----
-
-class: extra-details
-
-## Viewing our admin certificate
-
-- Let's inspect the certificate we've been using all this time!
.exercise[
-- This command will show the `CN` and `O` fields for our certificate:
+- Note that 401 (not 403) is what you get if you just `curl` the Kubernetes API
```bash
- kubectl config view \
- --raw \
- -o json \
- | jq -r .users[0].user[\"client-certificate-data\"] \
- | openssl base64 -d -A \
- | openssl x509 -text \
- | grep Subject:
+ curl -k $API_URL
```
]
-Let's break down that command together! 😅
-
----
-
-class: extra-details
-
-## Breaking down the command
-
-- `kubectl config view` shows the Kubernetes user configuration
-- `--raw` includes certificate information (which shows as REDACTED otherwise)
-- `-o json` outputs the information in JSON format
-- `| jq ...` extracts the field with the user certificate (in base64)
-- `| openssl base64 -d -A` decodes the base64 format (now we have a PEM file)
-- `| openssl x509 -text` parses the certificate and outputs it as plain text
-- `| grep Subject:` shows us the line that interests us
-
-→ We are user `kubernetes-admin`, in group `system:masters`.
-
-(We will see later how and why this gives us the permissions that we have.)
-
----
-
-## User certificates in practice
-
-- The Kubernetes API server does not support certificate revocation
-
- (see issue [#18982](https://github.com/kubernetes/kubernetes/issues/18982))
-
-- As a result, we don't have an easy way to terminate someone's access
-
- (if their key is compromised, or they leave the organization)
-
-- Option 1: re-create a new CA and re-issue everyone's certificates
-
- → Maybe OK if we only have a few users; no way otherwise
-
-- Option 2: don't use groups; grant permissions to individual users
-
- → Inconvenient if we have many users and teams; error-prone
-
-- Option 3: issue short-lived certificates (e.g. 24 hours) and renew them often
-
- → This can be facilitated by e.g. Vault or by the Kubernetes CSR API
-
---
## Authentication with tokens
@@ -238,6 +161,7 @@ class: extra-details
```bash
kubectl get sa default -o yaml
SECRET=$(kubectl get sa default -o json | jq -r .secrets[0].name)
+ echo $SECRET
```
]
@@ -296,18 +220,6 @@ class: extra-details
---
-class: extra-details
-
-## Results
-
-- Without authentication, the user is `system:anonymous`
-
-- With authentication, it is shown as `system:serviceaccount:default:default`
-
-- The API "sees" us as a different user
-
----
-
## Authorization in Kubernetes
- There are multiple ways to grant permissions in Kubernetes, called [authorizers](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#authorization-modules):
@@ -398,264 +310,6 @@ class: extra-details
---
-## In practice
-
-- We are going to create a service account
-
-- We will use a default cluster role (`view`)
-
-- We will bind together this role and this service account
-
-- Then we will run a pod using that service account
-
-- In this pod, we will install `kubectl` and check our permissions
-
----
-
-## Creating a service account
-
-- We will call the new service account `viewer`
-
- (note that nothing prevents us from calling it `view`, like the role)
-
-.exercise[
-
-- Create the new service account:
- ```bash
- kubectl create serviceaccount viewer
- ```
-
-- List service accounts now:
- ```bash
- kubectl get serviceaccounts
- ```
-
-]
-
----
-
-## Binding a role to the service account
-
-- Binding a role = creating a *rolebinding* object
-
-- We will call that object `viewercanview`
-
- (but again, we could call it `view`)
-
-.exercise[
-
-- Create the new role binding:
- ```bash
- kubectl create rolebinding viewercanview \
- --clusterrole=view \
- --serviceaccount=default:viewer
- ```
-
-]
-
-It's important to note a couple of details in these flags...
-
----
-
-## Roles vs Cluster Roles
-
-- We used `--clusterrole=view`
-
-- What would have happened if we had used `--role=view`?
-
- - we would have bound the role `view` from the local namespace
-
(instead of the cluster role `view`)
-
- - the command would have worked fine (no error)
-
- - but later, our API requests would have been denied
-
-- This is a deliberate design decision
-
- (we can reference roles that don't exist, and create/update them later)
-
----
-
-## Users vs Service Accounts
-
-- We used `--serviceaccount=default:viewer`
-
-- What would have happened if we had used `--user=default:viewer`?
-
- - we would have bound the role to a user instead of a service account
-
- - again, the command would have worked fine (no error)
-
- - ...but our API requests would have been denied later
-
-- What's about the `default:` prefix?
-
- - that's the namespace of the service account
-
- - yes, it could be inferred from context, but... `kubectl` requires it
-
----
-
-## Testing
-
-- We will run an `alpine` pod and install `kubectl` there
-
-.exercise[
-
-- Run a one-time pod:
- ```bash
- kubectl run eyepod --rm -ti --restart=Never \
- --serviceaccount=viewer \
- --image alpine
- ```
-
-- Install `curl`, then use it to install `kubectl`:
- ```bash
- apk add --no-cache curl
- URLBASE=https://storage.googleapis.com/kubernetes-release/release
- KUBEVER=$(curl -s $URLBASE/stable.txt)
- curl -LO $URLBASE/$KUBEVER/bin/linux/amd64/kubectl
- chmod +x kubectl
- ```
-
-]
-
----
-
-## Running `kubectl` in the pod
-
-- We'll try to use our `view` permissions, then to create an object
-
-.exercise[
-
-- Check that we can, indeed, view things:
- ```bash
- ./kubectl get all
- ```
-
-- But that we can't create things:
- ```
- ./kubectl create deployment testrbac --image=nginx
- ```
-
-- Exit the container with `exit` or `^D`
-
-
-
-]
-
-- We will see the pod has terminated with an error
-
----
-
-## Testing directly with `kubectl`
-
-- We can also check for permission with `kubectl auth can-i`:
- ```bash
- kubectl auth can-i list nodes
- kubectl auth can-i create pods
- kubectl auth can-i get pod/name-of-pod
- kubectl auth can-i get /url-fragment-of-api-request/
- kubectl auth can-i '*' services
- ```
-
-- And we can check permissions on behalf of other users:
- ```bash
- kubectl auth can-i list nodes \
- --as some-user
- kubectl auth can-i list nodes \
- --as system:serviceaccount::
- ```
-
----
-
-class: extra-details
-
-## Where does this `view` role come from?
-
-- Kubernetes defines a number of ClusterRoles intended to be bound to users
-
-- `cluster-admin` can do *everything* (think `root` on UNIX)
-
-- `admin` can do *almost everything* (except e.g. changing resource quotas and limits)
-
-- `edit` is similar to `admin`, but cannot view or edit permissions
-
-- `view` has read-only access to most resources, except permissions and secrets
-
-*In many situations, these roles will be all you need.*
-
-*You can also customize them!*
-
----
-
-class: extra-details
-
-## Customizing the default roles
-
-- If you need to *add* permissions to these default roles (or others),
-
- you can do it through the [ClusterRole Aggregation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles) mechanism
-
-- This happens by creating a ClusterRole with the following labels:
- ```yaml
- metadata:
- labels:
- rbac.authorization.k8s.io/aggregate-to-admin: "true"
- rbac.authorization.k8s.io/aggregate-to-edit: "true"
- rbac.authorization.k8s.io/aggregate-to-view: "true"
- ```
-
-- This ClusterRole permissions will be added to `admin`/`edit`/`view` respectively
-
-- This is particulary useful when using CustomResourceDefinitions
-
- (since Kubernetes cannot guess which resources are sensitive and which ones aren't)
-
----
-
-class: extra-details
-
-## Where do our permissions come from?
-
-- When interacting with the Kubernetes API, we are using a client certificate
-
-- We saw previously that this client certificate contained:
-
- `CN=kubernetes-admin` and `O=system:masters`
-
-- Let's look for these in existing ClusterRoleBindings:
- ```bash
- kubectl get clusterrolebindings -o yaml |
- grep -e kubernetes-admin -e system:masters
- ```
-
- (`system:masters` should show up, but not `kubernetes-admin`.)
-
-- Where does this match come from?
-
----
-
-class: extra-details
-
-## The `system:masters` group
-
-- If we eyeball the output of `kubectl get clusterrolebindings -o yaml`, we'll find out!
-
-- It is in the `cluster-admin` binding:
- ```bash
- kubectl describe clusterrolebinding cluster-admin
- ```
-
-- This binding associates `system:masters` with the cluster role `cluster-admin`
-
-- And the `cluster-admin` is, basically, `root`:
- ```bash
- kubectl describe clusterrole cluster-admin
- ```
-
----
-
class: extra-details
## Pod Security Policies