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.

  1. 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.

  2. 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"
    
  3. 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
    
  4. 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
    
  5. 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

  1. 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.

  1. 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