ServerlessBase Blog
  • Understanding Kubernetes API Server

    The Kubernetes API server is the central control plane component that exposes the Kubernetes API. Learn how it handles authentication, authorization, and request processing.

    Understanding Kubernetes API Server

    You've probably run kubectl get pods a dozen times, but have you ever stopped to think about what actually happens when that command hits the cluster? The Kubernetes API server is the single point of entry for all cluster operations. Every kubectl command, every webhook call, and every internal component communication goes through this component. It's the brain of the cluster, translating human intent into Kubernetes objects and validating every request against the cluster's state.

    What the API Server Actually Does

    The API server doesn't just accept requests and return responses. It's the central nervous system of Kubernetes, orchestrating authentication, authorization, admission control, and request processing. Every change to cluster state—creating a deployment, scaling a replica set, updating a service—must pass through the API server. This centralized control is what makes Kubernetes both powerful and predictable.

    Think of the API server as a gatekeeper that sits at the entrance of your cluster. Before any request can modify cluster state, it must pass through several validation layers. If any layer rejects the request, the entire operation fails immediately. This design prevents partial updates and ensures cluster consistency.

    Authentication: Who Are You?

    Authentication is the first gate the API server checks. It determines whether the request comes from a valid user or service account. Kubernetes supports multiple authentication methods, and you can configure them in any order. The first successful authentication method wins.

    Service Account Tokens

    Service accounts are the primary way internal components authenticate with the API server. When a pod runs, Kubernetes automatically creates a service account for it and injects a token into the pod's filesystem. This token is mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. When the pod makes API requests, it includes this token in the Authorization header.

    # View the service account token in a pod
    kubectl exec -it <pod-name> -- cat /var/run/secrets/kubernetes.io/serviceaccount/token

    The API server validates this token by checking it against the service account's secret in the kube-system namespace. This token has a limited lifetime and can be rotated automatically.

    Client Certificates

    For external users or services, you can use client certificates. You generate a certificate signing request (CSR), submit it to the cluster, and once approved, the certificate is issued. This is more secure than tokens because certificates can be revoked without changing the underlying token.

    # Generate a client certificate for a user
    openssl req -new -keyout client.key -out client.csr -subj "/CN=admin/O=system:masters"
    kubectl create certificate-request client.csr --save-to-file=client.crt
    kubectl certificate approve client.crt

    Basic Authentication

    Basic authentication is the simplest method but least secure. It uses username and password credentials stored in a file. Kubernetes can load these credentials from a file on the API server node. This method is rarely used in production because passwords are stored in plaintext.

    # Create a basic auth file
    echo -n "username:password" | base64
    # Output: dXNlcm5hbWU6cGFzc3dvcmQ=

    Token Files

    Token files are similar to basic auth but use bearer tokens instead of passwords. You create a file with token username entries and place it on the API server. This is useful for integrating with external systems that generate tokens.

    # Create a token file
    echo "abc123def456 user1" > /etc/kubernetes/token-file

    Authorization: What Can You Do?

    Once authentication succeeds, the API server must determine if the authenticated principal has permission to perform the requested action. Kubernetes uses authorization plugins to make this decision. You can configure multiple authorization plugins, and the first one that grants permission wins.

    Node Authorizer

    The node authorizer is special—it grants permissions to nodes for managing their own resources. This is critical for kubelet operations. The node authorizer checks if the request comes from a node's service account and if the resource is in the node's namespace.

    # Example: Node authorizer grants kubelet permission to manage pods in its namespace
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: node-admin
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

    ABAC (Attribute-Based Access Control)

    ABAC grants permissions based on attributes of the request, such as the user, namespace, resource type, and operation. You define rules in JSON format. This is flexible but can become complex to manage at scale.

    {
      "kind": "Policy",
      "apiVersion": "authorization.k8s.io/v1",
      "spec": {
        "subjects": [
          {
            "kind": "User",
            "name": "jane.doe@example.com"
          }
        ],
        "resources": [
          {
            "apiGroups": [""],
            "resources": ["pods"]
          }
        ],
        "verbs": ["get", "list", "watch"]
      }
    }

    RBAC (Role-Based Access Control)

    RBAC is the most widely used authorization method in Kubernetes. It uses roles and role bindings to grant permissions. Roles define what actions are allowed on which resources, and role bindings associate subjects (users, groups, service accounts) with roles.

    # Create a role that allows reading pods in the default namespace
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: pod-reader
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
     
    # Bind the role to a user
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-pods
      namespace: default
    subjects:
    - kind: User
      name: jane.doe@example.com
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: pod-reader
      apiGroup: rbac.authorization.k8s.io

    RBAC is powerful because you can create roles for different namespaces and bind them to different subjects. You can also create cluster-wide roles and cluster role bindings for cross-namespace access.

    Admission Control: Validating Requests

    Admission control is the final gate before a request is processed. It runs after authentication and authorization but before the request is applied to the cluster state. Admission controllers can reject requests, modify them, or allow them to proceed.

    Validating Admission Controllers

    Validating admission controllers check if a request is valid according to certain rules. If a request violates these rules, it's rejected. Examples include validating resource limits, checking namespace existence, and ensuring required labels are present.

    # Example: Validating admission controller configuration
    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: validating-webhook
    webhooks:
    - name: validating.example.com
      rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
      clientConfig:
        service:
          name: validating-webhook
          namespace: default
        caBundle: LS0tLS1CRUdJTi...
      admissionReviewVersions: ["v1"]
      sideEffects: None

    Mutating Admission Controllers

    Mutating admission controllers can modify requests before they're applied. This is useful for automatically adding default values, setting labels, or injecting sidecar containers. Mutating controllers run before validating controllers.

    # Example: Mutating admission controller configuration
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      name: mutating-webhook
    webhooks:
    - name: mutating.example.com
      rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
      clientConfig:
        service:
          name: mutating-webhook
          namespace: default
        caBundle: LS0tLS1CRUdJTi...
      admissionReviewVersions: ["v1"]
      sideEffects: None
      mutation: true

    Request Processing Flow

    When a request arrives at the API server, it goes through several stages:

    1. Authentication: The API server checks the request's authentication credentials. If authentication fails, the request is rejected with a 401 Unauthorized error.

    2. Authorization: If authentication succeeds, the API server checks if the authenticated principal has permission to perform the requested action. If authorization fails, the request is rejected with a 403 Forbidden error.

    3. Request Validation: The API server validates the request against the schema for the requested resource. This checks for required fields, valid values, and correct data types.

    4. Admission Control: The API server runs all configured admission controllers. Mutating controllers modify the request, and validating controllers check if the modified request is valid.

    5. State Modification: If all checks pass, the API server modifies the cluster state. This might involve creating, updating, or deleting resources.

    6. Response: The API server returns a response to the client, indicating success or failure.

    API Endpoints and Resources

    The API server exposes a RESTful API with various endpoints for different resources. You can interact with these endpoints directly using curl, or use tools like kubectl that wrap these endpoints.

    Common API Groups

    • "" (core group): Core resources like pods, services, and nodes
    • apps: Deployments, replica sets, stateful sets
    • batch: Jobs and cron jobs
    • networking.k8s.io: Ingress resources
    • rbac.authorization.k8s.io: Role-based access control resources
    • storage.k8s.io: Storage class and persistent volume claims

    Resource Endpoints

    Each resource has a corresponding endpoint. For example, pods are accessed via /api/v1/pods, deployments via /apis/apps/v1/deployments, and nodes via /api/v1/nodes.

    # List all pods using the API directly
    curl -k https://localhost:6443/api/v1/pods -H "Authorization: Bearer $TOKEN"
     
    # Create a new deployment using the API
    curl -k https://localhost:6443/apis/apps/v1/namespaces/default/deployments \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d @deployment.json

    Scaling the API Server

    The API server is a critical component, and its performance directly impacts cluster responsiveness. In production clusters with many nodes and workloads, you might need to scale the API server horizontally.

    Horizontal Pod Autoscaler

    You can use the Kubernetes Horizontal Pod Autoscaler to automatically scale the API server deployment based on CPU and memory usage. This ensures the API server can handle high request volumes during peak times.

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: api-server-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: kube-apiserver
      minReplicas: 2
      maxReplicas: 5
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 70

    High Availability

    For production clusters, you should run multiple API server instances behind a load balancer. This provides redundancy and prevents single points of failure. The control plane components (etcd, scheduler, controller manager) also run in HA configurations.

    Common Issues and Troubleshooting

    API Server Not Responding

    If the API server stops responding, first check if it's running:

    kubectl get pods -n kube-system | grep kube-apiserver

    Check the API server logs for errors:

    kubectl logs -n kube-system <apiserver-pod-name>

    Verify etcd connectivity, as the API server depends on etcd for storing cluster state.

    Authentication Failures

    If you're getting authentication errors, check your authentication configuration:

    kubectl get configmap -n kube-system kube-apiserver -o yaml | grep -A 10 "authentication"

    Verify that your token or certificate is valid and hasn't expired.

    Authorization Denied

    Authorization errors usually indicate a misconfigured RBAC policy. Check the role bindings for your user or service account:

    kubectl get rolebindings --all-namespaces -o wide
    kubectl get clusterrolebindings --all-namespaces -o wide

    Use kubectl auth can-i to test what actions are allowed:

    kubectl auth can-i get pods --as=system:anonymous
    kubectl auth can-i create deployments --as=jane.doe@example.com

    Best Practices

    1. Use RBAC: Always use RBAC for authorization instead of ABAC or node authorizer unless you have a specific reason not to.

    2. Principle of Least Privilege: Grant only the minimum permissions needed for each user or service account.

    3. Rotate Credentials: Regularly rotate service account tokens and client certificates.

    4. Monitor API Server: Set up monitoring for API server metrics, including request rate, latency, and error rates.

    5. Use Admission Controllers: Implement admission controllers to enforce policies and prevent invalid configurations.

    6. Secure the API Server: Run the API server with minimal privileges, use network policies to restrict access, and enable TLS for all communications.

    7. Test Changes: Always test changes to API server configuration in a staging environment before applying to production.

    Conclusion

    The Kubernetes API server is the central component that makes the cluster controllable and predictable. It handles authentication, authorization, admission control, and request processing, ensuring that only valid, authorized requests modify cluster state. Understanding how the API server works is essential for anyone working with Kubernetes, whether you're a developer, operator, or platform engineer.

    The API server's design—centralized control with multiple validation layers—prevents partial updates and ensures cluster consistency. This is what makes Kubernetes both powerful and reliable. By following best practices for authentication, authorization, and admission control, you can build secure, well-governed Kubernetes clusters that meet your organization's requirements.

    If you're managing complex deployments with multiple teams and services, platforms like ServerlessBase can help automate the reverse proxy configuration and SSL certificate provisioning, simplifying the management of your Kubernetes infrastructure while you focus on building applications.

    Leave comment