Security in Kubernetes¶
The Contain Platform is designed with a defense-in-depth security model, providing multiple layers of protection to secure your applications and the underlying infrastructure. This guide provides an overview of the core security mechanisms that control access, manage resources, and enforce policies within your Kubernetes cluster.
Authentication (IAM via Keycloak)¶
Authentication is the process of verifying a user's identity. On the Contain Platform, user authentication and Identity and Access Management (IAM) are managed through Keycloak.
When you access the Kubernetes API (for example, using kubectl), your identity
is first verified by Keycloak. This provides a centralized, single sign-on (SSO)
experience and allows for consistent user and group management across all
platform services.
The GitOps Workflow
While Keycloak and RBAC control direct access to the Kubernetes API, the primary way you will interact with the cluster on the Contain Platform is through Git.
In a GitOps workflow, you declare the desired state of your applications in a Git repository, and the Deployment service automatically applies that state to the cluster. Therefore, managing the security of your Git repositories—controlling who can commit and approve pull requests—becomes the most critical day-to-day security practice. Access control for your Git server is responsible for the authentication and authorization of changes to your applications.
Authorization (RBAC)¶
Once your identity is authenticated, Role-Based Access Control (RBAC) determines what actions you are authorized to perform. RBAC is a standard Kubernetes feature that allows you to define granular permissions for users and service accounts.
The main RBAC resources are:
Role/ClusterRole: These resources define a set of permissions. ARoleis specific to a namespace, while aClusterRoleis cluster-wide. Permissions consist of verbs (likeget,list,create,delete) applied to resources (likepods,deployments,services).RoleBinding/ClusterRoleBinding: These resources link a user, group, or service account to aRoleorClusterRole. This is how you grant the permissions to the user.
Example¶
This Role grants read-only access to pods within a specific namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "list", "watch"]
This RoleBinding then grants those permissions to a user named developer-jane:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jane-read-pods
subjects:
- kind: User
name: developer-jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Service Accounts: Identity for Applications¶
While Users and Groups are for humans, a ServiceAccount provides an
identity for processes that run inside a pod. This is the mechanism that allows
your application to securely authenticate against the Kubernetes API.
By default, every namespace has a default service account. If you don't
specify one for your pod, it will automatically use this default account.
It is a critical security best practice to create a dedicated ServiceAccount
for each of your applications and grant it only the minimal permissions it needs
to function (the principle of least privilege). You grant permissions by binding
the ServiceAccount to a Role or ClusterRole.
Example¶
This example creates a dedicated ServiceAccount for an application, then binds
it to the pod-reader role we created earlier, allowing the application to list
pods in its namespace.
# 1. Create the ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
---
# 2. Bind the ServiceAccount to the Role
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-read-pods
subjects:
- kind: ServiceAccount
name: my-app-sa # The name of the ServiceAccount
roleRef:
kind: Role
name: pod-reader # The name of the Role
apiGroup: rbac.authorization.k8s.io
Finally, you would update your Deployment to use this new ServiceAccount:
spec:
template:
spec:
serviceAccountName: my-app-sa # Use the dedicated ServiceAccount
containers:
- # ...
Predefined Roles¶
To simplify permissions management and enforce the principle of least privilege,
the Contain Platform provides a set of predefined ClusterRoles that you can
bind to users and groups in your namespaces. These roles are designed to cover
common use cases, such as:
view: Provides read-only access to most resources in a namespace.edit: Provides read-write access to most application-level resources, but prevents the modification ofRolesorRoleBindings.admin: Provides full control over a namespace, including the ability to manage roles and permissions.
By using these standardized roles, you can ensure consistent and secure access control across your projects without having to create and manage custom roles from scratch.
Resource Quotas¶
A ResourceQuota is a tool for managing and limiting the total amount of
resources that can be consumed within a single namespace. This is crucial for
preventing a single team or application from accidentally (or maliciously)
consuming a cluster's resources, which could impact other tenants.
You can set quotas for:
- Compute Resources: Total CPU and memory requests and limits.
- Storage Resources: Total number and size of persistent volumes.
- Object Count: The total number of objects of a certain type (e.g., pods,
services, secrets).
Example¶
This ResourceQuota sets limits on the production namespace:
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "20"
secrets: "30"
Admission Control¶
Admission Controllers are powerful gatekeepers for the Kubernetes API. After a request is authenticated and authorized, but before it is persisted, it must pass through a chain of admission controllers. These controllers can validate, mutate, or reject requests to enforce cluster-wide policies and security best practices.
The Contain Platform uses a combination of two powerful admission controllers:
Pod Security Standards (PSS) and Pod Security Admission (PSA)¶
The Pod Security Standards (PSS) are the official Kubernetes policies that define different security levels for pods. These standards range from the most permissive to the most highly restrictive. The three defined levels are:
privileged: Unrestricted, for trusted system-level workloads.baseline: A minimally restrictive policy that prevents known privilege escalations.restricted: A highly restrictive policy that follows current pod hardening best practices.
Pod Security Admission (PSA) is the built-in Kubernetes admission controller responsible for enforcing these standards. You can apply a PSS level to an entire namespace, and the PSA controller will then automatically validate all pods created in that namespace against the specified policy level. This provides a straightforward way to enforce a minimal security baseline for your workloads.
OPA Gatekeeper¶
For more complex and custom policies, the platform uses OPA (Open Policy Agent) Gatekeeper. Gatekeeper is a flexible, policy-as-code solution that allows you to define and enforce custom rules for any Kubernetes resource.
This is a core component of our clusters. In addition to the baseline defined by Pod Security Standards, Gatekeeper can be used to enforce a comprehensive set of application security best practices, including:
- Running as non-root: Containers are forbidden from running as the
rootuser. - Immutable Filesystems: The container's root filesystem is required to be read-only.
- Privilege Escalation: Disallowing
allowPrivilegeEscalationto prevent a process from gaining more privileges than its parent. - Limited Capabilities: Restricting the Linux capabilities granted to a
container, dropping potentially dangerous ones like
NET_RAWorSYS_ADMIN. - Resource Limits: Requiring all pods to have CPU and memory requests and limits defined to ensure stability.
- Priority Class: Ensuring all pods have a
priorityClassNameset to manage scheduling and preemption. - Trusted Registries: Requiring that all container images are pulled from a list of approved, trusted container registries.
- Labeling: Enforcing that all resources have specific labels for cost allocation, team ownership, or other organizational policies.
We do not enforce these policies by default but issue a warning if any of these policies are not met. But we strongly recommend implementing them to enhance security and compliance. We already enforce these policies for our own workloads that provide the services you use.
Image Security & Vulnerability Scanning¶
Security for your applications begins before they are even deployed. A common attack vector is to exploit known vulnerabilities in application dependencies or the base container images. The Contain Platform provides tools to mitigate this risk.
The Container Registry service, which is built on Harbor, includes integrated vulnerability scanning. When you push a new image to the registry, it is automatically scanned against a continuously updated database of common vulnerabilities and exposures (CVEs).
This allows you to establish a secure software supply chain. You can use the scan results in your CI/CD pipeline to prevent the deployment of images with high-severity vulnerabilities, ensuring that only trusted and vetted code runs in your cluster.
Audit Logging¶
Security is not just about prevention; it is also about detection, response, and forensic analysis. For compliance and security investigations, it is critical to have a detailed record of all actions performed within the cluster.
The Contain Platform enables the Kubernetes API Server's audit logging feature by default. Every authenticated request to the Kubernetes API is recorded, providing a detailed, chronological audit trail. This log includes information such as:
- Who made the request (the user or service account).
- The action taken (e.g.,
create,delete). - The affected resource (e.g., a
Pod,Secret, orConfigMap). - The source IP address of the request.
These audit logs are a critical tool for security analysis, incident investigation, and meeting compliance requirements. Access to audit logs can be provided through the platform's observability services.
Node and Host Security¶
The security of your applications depends on the security of the underlying infrastructure they run on. As a managed service, the Contain Platform is responsible for securing the host operating system and configuration of every Kubernetes node.
Our approach to host security includes:
- Hardened, Minimal Operating Systems: We use minimal, security-hardened OS images for all cluster nodes. This reduces the attack surface by removing all non-essential packages and services.
- Regular Security Patching: We continuously monitor for new vulnerabilities and apply security patches to the node operating systems and key components without interrupting your workloads.
- Restricted Access: Direct access (such as via SSH) to Kubernetes nodes is strictly controlled and is not provided to users. This prevents manual configuration changes that could lead to security vulnerabilities or configuration drift, and it ensures that all actions are performed via the secure Kubernetes API.
Network Policies¶
By default, all new namespaces on the Contain Platform are configured with a
"default deny" NetworkPolicy. This means that, out of the box, no pod is
allowed to receive incoming traffic. This least-privilege starting point is a
critical security measure that forces you to explicitly define the communication
paths that your application requires.
To enable traffic to your pods, you must create NetworkPolicy resources that
allows the specific connections. This reduces the attack surface and prevents
unauthorized lateral movement within the cluster in the event of a compromise.
Example¶
This NetworkPolicy allows pods with the label app: api to receive traffic on
port 8080 from other pods in the same namespace that have the label app: web:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-web
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
Network Encryption (mTLS)¶
While NetworkPolicy resources control which pods are allowed to communicate,
they do not encrypt the content of that communication. For applications that
handle highly sensitive data, encrypting traffic between pods (East-West
traffic) is a critical component of a defense-in-depth security strategy.
The Service Mesh service, which is built on Istio, can automatically enforce mutual TLS (mTLS) for all communication between services in the mesh. This means that all traffic is authenticated and encrypted, without requiring any changes to your application code. This provides an extra layer of security for your runtime environment.
By combining these security layers, the Contain Platform provides a secure and robust environment for running your applications.