Kubernetes Security Simplified: Protecting with API Groups and RBAC

vikash kumarvikash kumar
13 min read

Hey there, Kubernetes enthusiasts! ๐Ÿ‘‹ Today, we're diving into some important security topics that will help you ace the Certified Kubernetes Administrator (CKA) exam and make you a Kubernetes security expert. We'll cover API Groups, Authorization, Role-Based Access Controls (RBAC), and Cluster Roles and Role Bindings. Get ready, because we're about to connect all the dots in the Kubernetes security landscape!

1. API Groups: The Building Blocks of Kubernetes API

API Groups in Kubernetes are like organizing your closet - they help keep things tidy and make it easier to find what you need. They're the foundation of how Kubernetes structures its API, allowing for better organization and future extensibility.

Core Concepts:

  1. Core API Group: Also known as the legacy group, it includes fundamental resources like Pods, Services, and Nodes.

  2. Named Groups: These include apps, batch, networking.k8s.io, and more.

Discovering API Groups:

To see all available API resources and their groups:

kubectl api-resources

To get more details about a specific API group:

kubectl explain <resource>

Using API Groups in YAML:

When creating resources, you'll use the API group in the apiVersion field:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

API Group Versioning:

API groups can have multiple versions (e.g., v1, v1beta1). This allows Kubernetes to evolve the API while maintaining backwards compatibility.

kubectl api-versions

This command shows all available API versions in your cluster.

๐Ÿ’ก Pro Tip: Always use the most stable version of an API group in production. Beta versions may change in future releases.

Custom Resource Definitions (CRDs) and API Groups:

When creating Custom Resource Definitions, you define your own API group:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

2. Authorization: Who Can Do What?

Authorization in Kubernetes is all about controlling who can do what in your cluster. It's like being a bouncer at an exclusive club - you need to know who's allowed in and what they're allowed to do.

Authorization Modes:

Kubernetes supports several authorization modes:

  1. Node: Grants permissions to kubelets based on the pods they are scheduled to run.

  2. ABAC (Attribute-Based Access Control): Grants rights based on user attributes.

  3. RBAC (Role-Based Access Control): Uses roles and bindings to control access.

  4. Webhook: Allows for an external REST endpoint for authorization decisions.

You can enable multiple modes. The kube-apiserver flag looks like this:

--authorization-mode=Node,RBAC,Webhook

Checking Authorization:

To check if a user can perform an action:

kubectl auth can-i create pods --namespace development

As an admin, you can check permissions for other users:

kubectl auth can-i list secrets --namespace kube-system --as system:serviceaccount:default:default

๐Ÿ’ก Pro Tip: Regularly audit your authorization policies. What made sense yesterday might not make sense today!

3. Role-Based Access Control (RBAC): Fine-Grained Access Management

RBAC is the gold standard for authorization in Kubernetes. It's like assigning roles in a play - each actor (user) has specific lines (permissions) they're allowed to say.

Key RBAC Components:

  1. Rules: Define what actions can be taken on what resources.

  2. Roles: A set of rules that apply within a namespace.

  3. ClusterRoles: Like Roles, but apply across the entire cluster.

  4. RoleBindings: Link a Role to a user or set of users within a namespace.

  5. ClusterRoleBindings: Link a ClusterRole to a user or set of users across the entire cluster.

Creating a Role:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

To create this role:

kubectl apply -f role.yaml

Creating a RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Apply it with:

kubectl apply -f rolebinding.yaml

Viewing RBAC Resources:

kubectl get roles
kubectl get rolebindings
kubectl describe role pod-reader
kubectl describe rolebinding read-pods

๐Ÿ’ก Pro Tip: Use kubectl auth reconcile to update RBAC policies from a file. It's safer than kubectl apply as it handles deletions correctly.

Verbs in RBAC: Understanding Permissions

In RBAC, verbs define the actions that can be performed on resources. Understanding these verbs is crucial for setting up precise and effective permissions.

Common Verbs:

  • get: Read a specific resource (e.g., kubectl get pod my-pod).

  • list: List resources of a specific type (e.g., kubectl get pods).

  • watch: Watch for changes to resources (e.g., kubectl get pods --watch).

  • create: Create a new resource (e.g., kubectl create -f pod.yaml).

  • update: Modify an existing resource (e.g., kubectl edit pod my-pod).

  • patch: Partially update a resource (e.g., kubectl patch pod my-pod -p '{"spec":{"containers":[{"name":"my-container","image":"my-image"}]}}').

  • delete: Remove a resource (e.g., kubectl delete pod my-pod).

  • exec: Execute a command in a container (e.g., kubectl exec my-pod -- ls).

  • proxy: Proxy requests to a resource (e.g., kubectl proxy).

  • impersonate: Act as another user or service account (e.g., kubectl auth can-i impersonate user).

Understanding these verbs helps in crafting precise RBAC policies that grant only the necessary permissions to users and service accounts.

4. Cluster Roles and Role Bindings: Cluster-Wide Access Control

ClusterRoles and ClusterRoleBindings are the cluster-wide equivalents of Roles and RoleBindings. They're like the executive board of your Kubernetes cluster, making decisions that affect the entire organization.

Creating a ClusterRole:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Apply with:

kubectl apply -f clusterrole.yaml

Creating a ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

Apply with:

kubectl apply -f clusterrolebinding.yaml

Viewing Cluster-wide RBAC Resources:

kubectl get clusterroles
kubectl get clusterrolebindings
kubectl describe clusterrole secret-reader
kubectl describe clusterrolebinding read-secrets-global

๐Ÿ’ก Pro Tip: Use ClusterRoles for permissions that should apply across all namespaces or for non-namespaced resources like nodes or persistent volumes.

Putting It All Together: Real-World Scenarios

Let's walk through some real-world scenarios to see how all these concepts work together.

Scenario 1: Multi-tenant Cluster

Imagine you're managing a cluster for multiple development teams. Each team needs different levels of access to their namespaces.

  1. Create namespaces for each team:
kubectl create namespace team-frontend
kubectl create namespace team-backend
  1. Create roles for different access levels:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: team-frontend
  name: frontend-developer
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "services", "deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: team-backend
  name: backend-developer
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "services", "deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["secrets", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  1. Bind roles to groups:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: frontend-access
  namespace: team-frontend
subjects:
- kind: Group
  name: frontend-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: frontend-developer
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-access
  namespace: team-backend
subjects:
- kind: Group
  name: backend-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: backend-developer
  apiGroup: rbac.authorization.k8s.io
  1. Create a ClusterRole for monitoring:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-viewer
rules:
- apiGroups: [""]
  resources: ["pods", "nodes", "services", "events"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "daemonsets", "statefulsets"]
  verbs: ["get", "list", "watch"]
  1. Bind the ClusterRole to the monitoring team:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-team-access
subjects:
- kind: Group
  name: monitoring-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: monitoring-viewer
  apiGroup: rbac.authorization.k8s.io

With this setup:

  • Frontend developers can fully manage deployments, pods, and services in their namespace, but only view configmaps.

  • Backend developers have full access to their namespace, including secrets.

  • The monitoring team can view key resources across all namespaces.

Scenario 2: Graduated Access for New Developers

For new developers joining the team, you might want to grant limited access initially and increase it as they gain experience.

  1. Create a limited developer role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: junior-developer
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get"]
  1. Create a more permissive role for senior developers:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: senior-developer
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["pods/exec", "pods/log"]
  verbs: ["create", "get"]
  1. Bind the junior role to a new developer:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: junior-access
  namespace: development
subjects:
- kind: User
  name: new-dev@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: junior-developer
  apiGroup: rbac.authorization.k8s.io

As the developer gains experience, you can update their access by creating a new RoleBinding to the senior-developer role.

Scenario 3: Temporary Elevated Access

Sometimes, you need to grant temporary elevated access for specific tasks, like debugging or maintenance.

  1. Create a temporary admin role:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: temporary-admin
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
  1. Create a time-limited RoleBinding (you'll need to manually remove this after the specified time):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: emergency-access
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "false"
subjects:
- kind: User
  name: emergency-user@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: temporary-admin
  apiGroup: rbac.authorization.k8s.io

Apply this with:

kubectl apply -f emergency-access.yaml --validate=false

Remember to remove this binding after the maintenance window:

kubectl delete clusterrolebinding emergency-access

๐Ÿ’ก Pro Tip: Always have a process for granting and, more importantly, revoking temporary elevated access. Time-boxing these permissions is crucial for maintaining security.

Best Practices and Tips

  1. Least Privilege: Always start with the minimum necessary permissions and add more as needed.

  2. Use Groups: Assign roles to groups rather than individual users for easier management.

  3. Namespace Isolation: Use namespaces to isolate resources and permissions between teams or environments.

  4. Regular Audits: Periodically review and clean up RBAC policies. Use:

     kubectl auth reconcile -f rbac-policy.yaml
    
  5. Default Deny: Structure your RBAC policies to deny by default and explicitly grant needed permissions.

  6. Avoid Cluster-Admin: Limit the use of the cluster-admin role. Create more specific roles for administrative tasks.

  7. Version Control: Keep your RBAC policies in version control, just like your application code.

  8. Use Aggregated ClusterRoles: For complex permission sets, use aggregated ClusterRoles:

     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRole
     metadata:
       name: monitoring-pods
       labels:
         rbac.example.com/aggregate-to-monitoring: "true"
     rules:
     - apiGroups: [""]
       resources: ["pods"]
       verbs: ["get", "list", "watch"]
    
    1. Automate RBAC Management: Use tools like rbac-manager or rbac-lookup to simplify RBAC management in large clusters.

    2. Use RBAC Simulator: Before applying RBAC changes, use a tool like rbac-tool to simulate the effects:

      rbac-tool simulate --user=jane@example.com --resource=pods --verb=list
      
    3. Implement Break-Glass Procedures: Have a well-documented process for emergency access, including how to grant and revoke it.

    4. Use Kubernetes PSP (Pod Security Policies) or PSA (Pod Security Admission): These complement RBAC by controlling security-sensitive aspects of pod specifications.

    5. Monitor RBAC Changes: Set up alerts for changes to RBAC policies, especially for sensitive roles or bindings.

    6. Use Service Accounts Wisely: For applications running in your cluster, use specific Service Accounts with minimal permissions rather than the default one.

    7. Regularly Rotate Credentials: Implement a process to regularly rotate service account tokens and user credentials.

Connecting the Dots: The Big Picture of Kubernetes Security

Now that we've deep-dived into API Groups, Authorization, RBAC, and Cluster Roles and Bindings, let's step back and see how it all fits together in the grand scheme of Kubernetes security.

  1. API Groups form the foundation of the Kubernetes API structure. They organize resources and allow for API evolution without breaking existing clients. When you're setting up RBAC rules, you'll often reference these API groups to specify which resources a role can access.

  2. Authorization is the process of determining whether a user or service account has permission to perform a requested action. RBAC is the primary method of implementing authorization in Kubernetes.

  3. RBAC ties everything together. It uses the concept of API Groups to define what resources can be accessed, and it implements the authorization decisions by defining who can do what in your cluster.

  4. Roles and RoleBindings operate at the namespace level, allowing you to implement fine-grained access control within specific namespaces. This is perfect for multi-tenant clusters or for separating environments (dev, staging, prod) within a cluster.

  5. ClusterRoles and ClusterRoleBindings operate cluster-wide, allowing you to define permissions for cluster-level resources or to set up roles that apply across all namespaces. These are crucial for cluster administrators and for managing resources that aren't namespaced.

By understanding and properly implementing these concepts, you create a robust security model for your Kubernetes cluster:

  • API Groups help you understand and organize the resources in your cluster.

  • Authorization ensures that every action is checked against defined policies.

  • RBAC provides a flexible and powerful way to implement those authorization policies.

  • Roles, ClusterRoles, and their bindings give you the tools to implement principle of least privilege and separation of duties in your cluster.

Real-World Application: Securing a Microservices Architecture

Let's tie all of this together with a real-world example. Imagine you're running a microservices-based e-commerce platform on Kubernetes. Here's how you might apply these concepts:

  1. Namespace Separation: Create separate namespaces for different components:

     kubectl create namespace frontend
     kubectl create namespace backend
     kubectl create namespace data
     kubectl create namespace monitoring
    
  2. API Group Usage: When defining roles, you'll use different API groups:

    • "" (core) for Pods, Services

    • "apps" for Deployments, StatefulSets

    • "networking.k8s.io" for Ingresses

  3. Role Creation: Create roles for different teams:

     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: Role
     metadata:
       namespace: frontend
       name: frontend-developer
     rules:
     - apiGroups: ["", "apps", "networking.k8s.io"]
       resources: ["pods", "services", "deployments", "ingresses"]
       verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: Role
     metadata:
       namespace: backend
       name: backend-developer
     rules:
     - apiGroups: ["", "apps"]
       resources: ["pods", "services", "deployments", "statefulsets"]
       verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
     - apiGroups: [""]
       resources: ["secrets", "configmaps"]
       verbs: ["get", "list", "watch"]
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: Role
     metadata:
       namespace: data
       name: data-engineer
     rules:
     - apiGroups: ["", "apps"]
       resources: ["pods", "services", "statefulsets", "persistentvolumeclaims"]
       verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    
  4. ClusterRole for Monitoring: Create a ClusterRole for your monitoring team:

     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRole
     metadata:
       name: monitoring-viewer
     rules:
     - apiGroups: [""]
       resources: ["pods", "services", "nodes", "persistentvolumeclaims"]
       verbs: ["get", "list", "watch"]
     - apiGroups: ["apps"]
       resources: ["deployments", "daemonsets", "statefulsets"]
       verbs: ["get", "list", "watch"]
     - apiGroups: [""]
       resources: ["pods/log", "pods/status"]
       verbs: ["get"]
    
  5. Binding Roles: Bind these roles to your teams:

     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: RoleBinding
     metadata:
       name: frontend-access
       namespace: frontend
     subjects:
     - kind: Group
       name: frontend-team
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: Role
       name: frontend-developer
       apiGroup: rbac.authorization.k8s.io
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRoleBinding
     metadata:
       name: monitoring-access
     subjects:
     - kind: Group
       name: monitoring-team
       apiGroup: rbac.authorization.k8s.io
     roleRef:
       kind: ClusterRole
       name: monitoring-viewer
       apiGroup: rbac.authorization.k8s.io
    
  6. Service Account for CI/CD: Create a service account for your CI/CD pipeline:

     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: ci-cd-bot
       namespace: default
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRole
     metadata:
       name: ci-cd-role
     rules:
     - apiGroups: ["", "apps", "networking.k8s.io"]
       resources: ["pods", "services", "deployments", "ingresses"]
       verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: ClusterRoleBinding
     metadata:
       name: ci-cd-role-binding
     subjects:
     - kind: ServiceAccount
       name: ci-cd-bot
       namespace: default
     roleRef:
       kind: ClusterRole
       name: ci-cd-role
       apiGroup: rbac.authorization.k8s.io
    

With this setup:

  • Frontend developers can fully manage their resources in the frontend namespace.

  • Backend developers can manage core resources in the backend namespace but only view secrets and configmaps.

  • Data engineers have full access to stateful applications and persistent storage in the data namespace.

  • The monitoring team can view key resources across all namespaces.

  • Your CI/CD pipeline has the necessary permissions to deploy across namespaces.

Conclusion: Mastering Kubernetes Security

Congratulations! You've just taken a deep dive into the world of Kubernetes security, focusing on API Groups, Authorization, RBAC, and Cluster Roles and Bindings. Let's recap the key takeaways:

  1. API Groups are the building blocks of the Kubernetes API, helping organize and evolve the API efficiently.

  2. Authorization in Kubernetes determines who can do what, with RBAC being the recommended approach.

  3. RBAC provides fine-grained access control through Roles, ClusterRoles, and their respective bindings.

  4. Proper use of namespaces with RBAC allows for strong multi-tenancy and environment separation.

  5. ClusterRoles and ClusterRoleBindings are powerful tools for managing cluster-wide permissions.

Remember, Kubernetes security is not a one-time setup but an ongoing process. Regularly review and update your RBAC policies, keep your cluster updated, and always follow the principle of least privilege.

As you continue your Kubernetes journey, whether you're preparing for the CKA exam or managing production clusters, these concepts will be crucial. They form the backbone of a secure Kubernetes environment, allowing you to confidently deploy and manage applications at scale.

Keep experimenting, stay curious, and happy clustering! ๐Ÿš€๐Ÿ”

0
Subscribe to my newsletter

Read articles from vikash kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

vikash kumar
vikash kumar

Hey folks! ๐Ÿ‘‹ I'm Vikash Kumar, a seasoned DevOps Engineer navigating the thrilling landscapes of DevOps and Cloud โ˜๏ธ. My passion? Simplifying and automating processes to enhance our tech experiences. By day, I'm a Terraform wizard; by night, a Kubernetes aficionado crafting ingenious solutions with the latest DevOps methodologies ๐Ÿš€. From troubleshooting deployment snags to orchestrating seamless CI/CD pipelines, I've got your back. Fluent in scripts and infrastructure as code. With AWS โ˜๏ธ expertise, I'm your go-to guide in the cloud. And when it comes to monitoring and observability ๐Ÿ“Š, Prometheus and Grafana are my trusty allies. In the realm of source code management, I'm at ease with GitLab, Bitbucket, and Git. Eager to stay ahead of the curve ๐Ÿ“š, I'm committed to exploring the ever-evolving domains of DevOps and Cloud. Let's connect and embark on this journey together! Drop me a line at thenameisvikash@gmail.com.