Day 21-22 of 40 Days Challenge : Understanding TLS Certificates, Authentication, and Authorization in Kubernetes
Introduction
In the previous blog, we discussed how SSL/TLS certificates work. In brief, the server requests a certificate from a Certificate Authority (CA), the CA issues the certificate, and then the server presents this certificate to the client. The client validates the certificate, and a secure connection is established. This same concept is used in Kubernetes to secure connections between the user and the cluster using TLS certificates. Let’s dive deeper into this with a hands-on example.
TLS Certificates in cluster
In the diagram above, we see one master node and three worker nodes. There is also an external user who wants to interact with the kube-apiserver
on the master node. In this scenario, the user acts as the client, and the master node acts as the server. When the master node interacts with the worker nodes, the roles reverse, with the master node becoming the client and the worker nodes becoming the servers. These connections must be secured, and we achieve this by using TLS certificates, which work the same way as described in the earlier section.
In the diagram, you can see that each component in the cluster and the user has both a public certificate and a private key.
Understanding the Difference: Certificate vs. Private Key
Before proceeding with the hands-on example, it's crucial to understand how to distinguish between a certificate and a private key:
Certificate: If the file has a
.crt
or.pem
extension, it is likely a public certificate.Private Key: If the file name includes the keyword
key
or has a.key
extension, it is a private key.
Issuing a Certificate for a New User
Let’s say a new user, "learner", has joined the team and needs access to the Kubernetes cluster. To do this, we need to issue a certificate for the user.
Create a Private Key:
The first step is to generate a private key for the user:
openssl genrsa -out learner.key 2048
Now, the user (learner) has their private key.
Generate a Certificate Signing Request (CSR):
Using this private key, the user generates a CSR:
openssl req -new -key learner.key -out learner.csr -subj "/CN=learner"
Create a CertificateSigningRequest Object:
As an admin, you will create an object to add the user’s signing request for approval:
apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: name: learner spec: request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo= signerName: kubernetes.io/kube-apiserver-client expirationSeconds: 604800 # Valid for 1 week usages: - client auth
Before pasting the user request into this YAML file, first, decode the request and make it a single line. This is necessary because, in YAML files, the request is encoded:
cat learner.csr | base64 | tr -d "\n"
After pasting the request, apply this file using:
kubectl apply -f csr.yaml
Approve the CertificateSigningRequest:
Until now, the user has created a certificate-signing request and shared it with the admin. As an admin, we create an object, but it is in a pending state because the request needs to be approved by an authorized CA. Since we are not using an external CA, the admin can approve this request manually:
kubectl certificate approve learner
Retrieve the Issued Certificate:
Once approved, get the issued certificate to share it with the user:
kubectl get csr learner -o yaml > issuedcsr.yaml
The
issuedcsr.yaml
file will contain the issued certificate, which can then be shared with the user.apiVersion: certificates.k8s.io/v1 kind: CertificateSigningRequest metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"learner"},"spec":{"expirationSeconds":604800,"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1Z6Q0NBVDhDQVFBd0VqRVFNQTRHQTFVRUF3d0hiR1ZoY201bGNqQ0NBU0l3RFFZSktvWklodmNOQVFFQgpCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFOZ29JbzVXenF2aUgyNEVNMmNPb3dRZWZyYUczREpLbFNFM3VSUERNZlNZCmt6RDhKUEZyaU55ZmUzRnEza2hJUkgxR3Jkd1ZrMUhhZ1Q4OEFleTJ4U29FdVpYbnA3em1yQmFNbG1hMEZIWHkKNWtyaFJtdWRSY2RyT1ZlT3NhSC8xUzBqS052R2VickxNU3o2Z2lDcHh2a1g2a3k3QlV1QlNJQzVQRGhQS3dxKwp6anJQVWhaOSttVGhjRkpLUnI4NTRYRVBWOXQrY2FyN3NBWTBXL0F5RytzNGRYSGpXVFJrUEliNGRVK0daNEQxCmQ4ZnZyOWpPY0pSallzZXFMcUNQeXNHTEtFZzFzTUlDbUJnRVg5UGdFaHYzSnhBQWMwYjQ1OEdJd3ZNS29KMHUKbzZnUFVEdUpMY3l1Q3VFZEMyR2M0a2hVVXZ5NTJEaUh6cEFMQWF2M00rOENBd0VBQWFBQU1BMEdDU3FHU0liMwpEUUVCQ3dVQUE0SUJBUUFINFpsdkZoYTFlZUM0TDRZLzM3NlFJVWVJbmxhaE1RZDRkQjZSUmlvelhzWG9VYzZzClRpbkg2LzA4andVeHZzRTVGbzFMRVlWNTQ0ZUZKSlRCRkpNRkt5V200bUE1eEsvbmJaa0Fqa2NTbzNYb1RvREQKQkVqbkNYRGZCOUFjZTBKdXp0WW9XMjJwRW5ab3VKd2pDMVRmZEpYdDY1YzV2RVU4Z3VvV3JsR2NMeWF3cUpMVQpNVHZ5MXhVczBpRjNlQVB1dFJ6aWhMZHBQUFFMWFZSS3A0ZU9zSUdnTmxTYTJHdmMzd1ZScHVBbmNUVm1QdjRuClhzcEUrNHVCY21rdkVkTFJmSWRRdHhNVkpFR2hmNCs2Mk81NnBhTXFYdXphQWk3NHJKWlg4d01IS1FPZEx3WFAKWkFEa1R3YjkrS2NMUzhieHdybTFwUFpzcFRaR09tWld0eFN0Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=","signerName":"kubernetes.io/kube-apiserver-client","usages":["client auth"]}} creationTimestamp: "2024-08-10T18:38:54Z" name: learner resourceVersion: "798963" uid: 82988f68-0883-4604-8b16-716faba151be spec: expirationSeconds: 604800 groups: - kubeadm:cluster-admins - system:authenticated request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1Z6Q0NBVDhDQVFBd0VqRVFNQTRHQTFVRUF3d0hiR1ZoY201bGNqQ0NBU0l3RFFZSktvWklodmNOQVFFQgpCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFOZ29JbzVXenF2aUgyNEVNMmNPb3dRZWZyYUczREpLbFNFM3VSUERNZlNZCmt6RDhKUEZyaU55ZmUzRnEza2hJUkgxR3Jkd1ZrMUhhZ1Q4OEFleTJ4U29FdVpYbnA3em1yQmFNbG1hMEZIWHkKNWtyaFJtdWRSY2RyT1ZlT3NhSC8xUzBqS052R2VickxNU3o2Z2lDcHh2a1g2a3k3QlV1QlNJQzVQRGhQS3dxKwp6anJQVWhaOSttVGhjRkpLUnI4NTRYRVBWOXQrY2FyN3NBWTBXL0F5RytzNGRYSGpXVFJrUEliNGRVK0daNEQxCmQ4ZnZyOWpPY0pSallzZXFMcUNQeXNHTEtFZzFzTUlDbUJnRVg5UGdFaHYzSnhBQWMwYjQ1OEdJd3ZNS29KMHUKbzZnUFVEdUpMY3l1Q3VFZEMyR2M0a2hVVXZ5NTJEaUh6cEFMQWF2M00rOENBd0VBQWFBQU1BMEdDU3FHU0liMwpEUUVCQ3dVQUE0SUJBUUFINFpsdkZoYTFlZUM0TDRZLzM3NlFJVWVJbmxhaE1RZDRkQjZSUmlvelhzWG9VYzZzClRpbkg2LzA4andVeHZzRTVGbzFMRVlWNTQ0ZUZKSlRCRkpNRkt5V200bUE1eEsvbmJaa0Fqa2NTbzNYb1RvREQKQkVqbkNYRGZCOUFjZTBKdXp0WW9XMjJwRW5ab3VKd2pDMVRmZEpYdDY1YzV2RVU4Z3VvV3JsR2NMeWF3cUpMVQpNVHZ5MXhVczBpRjNlQVB1dFJ6aWhMZHBQUFFMWFZSS3A0ZU9zSUdnTmxTYTJHdmMzd1ZScHVBbmNUVm1QdjRuClhzcEUrNHVCY21rdkVkTFJmSWRRdHhNVkpFR2hmNCs2Mk81NnBhTXFYdXphQWk3NHJKWlg4d01IS1FPZEx3WFAKWkFEa1R3YjkrS2NMUzhieHdybTFwUFpzcFRaR09tWld0eFN0Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo= signerName: kubernetes.io/kube-apiserver-client usages: - client auth username: kubernetes-admin status: certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5ekNDQWQrZ0F3SUJBZ0lRTmRWMzBjTWtPYlJ6TXZoOS9RMU4rakFOQmdrcWhraUc5dzBCQVFzRkFEQVYKTVJNd0VRWURWUVFERXdwcmRXSmxjbTVsZEdWek1CNFhEVEkwTURneE1ERTRNemsxT1ZvWERUSTBNRGd4TnpFNApNemsxT1Zvd0VqRVFNQTRHQTFVRUF4TUhiR1ZoY201bGNqQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQCkFEQ0NBUW9DZ2dFQkFOZ29JbzVXenF2aUgyNEVNMmNPb3dRZWZyYUczREpLbFNFM3VSUERNZlNZa3pEOEpQRnIKaU55ZmUzRnEza2hJUkgxR3Jkd1ZrMUhhZ1Q4OEFleTJ4U29FdVpYbnA3em1yQmFNbG1hMEZIWHk1a3JoUm11ZApSY2RyT1ZlT3NhSC8xUzBqS052R2VickxNU3o2Z2lDcHh2a1g2a3k3QlV1QlNJQzVQRGhQS3dxK3pqclBVaFo5CittVGhjRkpLUnI4NTRYRVBWOXQrY2FyN3NBWTBXL0F5RytzNGRYSGpXVFJrUEliNGRVK0daNEQxZDhmdnI5ak8KY0pSallzZXFMcUNQeXNHTEtFZzFzTUlDbUJnRVg5UGdFaHYzSnhBQWMwYjQ1OEdJd3ZNS29KMHVvNmdQVUR1SgpMY3l1Q3VFZEMyR2M0a2hVVXZ5NTJEaUh6cEFMQWF2M00rOENBd0VBQWFOR01FUXdFd1lEVlIwbEJBd3dDZ1lJCkt3WUJCUVVIQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JRZWp5TXRsTkoza0lNQ09MUUEKYk5RWXhWcGEzakFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBbS9wUFluTUpyY05OMjdlVmluYlVRNEI2VW11MgpwMmpaMitqT1ZXK3YyLzkwY3dFeUtudTJhS3VxZVlZWG92WE1PWkpxbUFRS0pKQTdmM2ptSTBSREhqWVQwMXNJCnNHQkhmQk9ReHV3OXdzWVZTQVlxY1RXb0tQa2p6cGRTSGt2L0pNZTY4cGxlNUh5eUV4dkxxSWlRVmcyUGtkbFEKWHZCcWQvZEtOcW1tZjhXVkd3emsySWYyVzhjaHFkSnFJOUFocFFOQUhwZ1o3elVxbWJZOFFhRlphU2JQK0tKeQpFaENPMnpnRVZPMXQrY0xWUnNyMVVRYnowRW9zeGUxM1E0TU9DaXozVGFtK3dMWjZBVDJ5WWNucW93ZWYxdkh4CmN2a250SzY2YWF4ZTBTUlZPcDZUeTlhS2ZYUm9EOW5aQ2JQclhyaXlLYURkUnc1S2tDenpNaUlqRFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== conditions: - lastTransitionTime: "2024-08-10T18:44:59Z" lastUpdateTime: "2024-08-10T18:44:59Z" message: This CSR was approved by kubectl certificate approve. reason: KubectlApprove status: "True" type: Approved-
In the status section, you can see the certificate, but before giving it to the user, decode it using
echo "csr" | base64 -d
.Now you can share this certificate with any user or add it to a kubeconfig file to perform tasks in the cluster. We will cover this in more detail in our next blog.
Authentication and Authorization
Authentication
Authentication in Kubernetes is the process of verifying the identity of a user or a service.
Kubernetes supports multiple authentication mechanisms:
Client Certificates: Users or services authenticate using certificates signed by a trusted Certificate Authority (CA).
Bearer Tokens: Tokens issued by a trusted entity, often used for service accounts.
Basic Authentication: Simple username and password authentication (not recommended for production).
OIDC (OpenID Connect): Integration with identity providers like Google, Azure AD, etc.
Webhook Token Authentication: Custom authentication using webhooks.
We already did a hands-on client certificates.
Authorization
Authorization in Kubernetes determines what actions an authenticated user or service can perform on resources in the cluster. Kubernetes supports several authorization mechanisms:
RBAC (Role-Based Access Control): The most common mechanism, which grants permissions to users based on roles.
ABAC (Attribute-Based Access Control): Permissions based on attributes like user, group, or labels.
Webhook Authorization: Custom authorization via a webhook.
Node Authorization: Limits access based on the node's identity, typically for Kubelets.
Conclusion
In this blog, we explored how TLS certificates are used within Kubernetes to secure communication between different components and users in the cluster. We also touched upon the concepts of authentication and authorization, which ensure that only authorized users and components can interact with the Kubernetes API.
By understanding these security mechanisms, you can better manage and secure your Kubernetes cluster, ensuring that it remains robust and resilient against unauthorized access.
Stay tuned for more hands-on Kubernetes learning as we continue our journey in the #40DaysOfKubernetes challenge!
Resources
https://www.youtube.com/watch?v=LvPA-z8Xg4s&list=PLl4APkPHzsUUOkOv3i62UidrLmSB8DcGC&index=22
https://www.youtube.com/watch?v=P0bogYEyfeI&list=PLl4APkPHzsUUOkOv3i62UidrLmSB8DcGC&index=24