Kubernetes validation admission policies
What are Kubernetes validation admission policies?
Kubernetes admission controllers are one of the latest plugins in the Kubernetes suite of tools that enables security improvement in clusters. The plugin provides access to advanced security features which allow DevOps engineers to encode validation policies into the cluster, which manages configurations and permissions of diverse resources in the Kubernetes infrastructure.
The direct result of an admission controller is enhanced security of the Kubernetes structure via restricted access and privileges of pods, containers, and other resources. Overall, Kubernetes admission controllers and validation admission policies harden the containerized applications and remove vulnerabilities that can be exploited by malicious attackers. Thus, Kubernetes admission controllers can be considered a gatekeeper for the infrastructure which gates authenticated requests to different objects and the host itself.
Validation Admission Policies in Kubernetes
Validation admission policies are a declarative way of defining and deploying a policy. It is an alternative to admission webhooks and is carried out during the process. The validation admission policy is written using the Common Expression Language (CEL).
Admission controllers usually run in the mutating and validation phases. The mutating phase is before the object schema validation, and the validation phase is after. The key benefits of using validation admission policies are as follows:
- Validation admission policies provide an additional layer of security to the cluster infrastructure by limiting access and the number of requests a resource must handle.
- These limit the attack surface by restricting unnecessary communication between different resources.
- The admission policies using admission controllers also ensure that the management of configurations and governance of the Kubernetes infrastructure is simple and streamlined.
- With admission controllers, validation policies ensure the right labels are used, and automatically add annotations, and limits to the resources, thus simplifying the tasks for DevOps personnel.
Policy Types
There are numerous types of validation admission policies, and each has a distinct function. Some of the crucial ones include:
- DefaultAdmissionConfig: This ensures that different admission plug-ins are admitted into the infrastructure by default.
- AlwaysDeny: The primary use case for the “AlwaysDeny” policy is to establish a strong security posture by denying all admission requests. This ensures that no changes are allowed within the cluster unless explicitly permitted by other admission rules. Here are a few scenarios where the “AlwaysDeny” validation admission policy can be beneficial:
- Preventing unauthorized access – By denying all requests, including the creation of new resources or updates, the policy ensures that only authorized actions are permitted within the cluster.
- Implementing strict compliance requirements – In highly regulated environments the “AlwaysDeny” policy can enforce strict controls and prevent changes that may violate compliance standards.
- Zero-trust security approach – The “AlwaysDeny” policy aligns with the zero-trust security model, where no action is implicitly trusted, and every request must be explicitly approved.
It is important to note that the “AlwaysDeny” policy should be used judiciously, as it can potentially lead to operational challenges or hinder legitimate operations if not properly configured.
- AlwaysAllow: The primary use case for the “AlwaysAllow” validation admission policy is to facilitate rapid development, testing, or experimentation within a cluster. Here are a few scenarios where the “AlwaysAllow” policy can be beneficial:
- Development and testing environments – In non-production environments, the “AlwaysAllow” policy can be employed to streamline the development process. It eliminates the need for constant validation and approvals, allowing developers to quickly iterate and deploy their applications.
- Exploration and experimentation – When exploring new features, trying out different configurations, or experimenting with various Kubernetes resources, the “AlwaysAllow” policy provides the freedom to make changes without any restrictions.
- Rapid prototyping – The early stages of application development often involves frequent changes and iterations. The “AlwaysAllow” policy allows developers to make modifications and deploy new resources without encountering any admission-related obstacles.
It is important to note that in production environments, it is strongly recommended to have stringent admission policies in place. The “AlwaysAllow” policy should only be used in controlled, non-production environments for rapid development, exploration, or experimentation.
- MutatingAdmissionWebhook: Used in the mutating phase, this policy type calls different admission webhooks in succession that match the request and allows the policy to modify the object. However, based on how the object is modified, there must be a mechanism that prevents conflicts with subsequent webhooks and enables them to be finished.
- ValidatingAdmissionWebhook: In the validating phase, this policy calls webhooks that match the request. It calls the webhooks in parallel, and if any request is rejected by them, then the request fails. Furthermore, these cannot mutate the object.
- NetworkPolicy: Network policies facilitate traffic management and define how pods will communicate with different network entities.
- ResourceQuota: This enables enforcement of constraints on objects and ensures the incoming request is only allowed if it doesn’t violate the constraints given in the ResourceQuota object in the namespace.
Implementation
Validation admission policies can be created with and without parameter resources. A simple example of creating, binding, and deploying a validation policy is as follows:
Creating
apiVersion: admissionregistration.k8s.io/v1alpha1 kind: ValidatingAdmissionPolicy metadata: name: "demo-policy.example.com" spec: failurePolicy: Fail matchConstraints: resourceRules: - apiGroups: ["apps"] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["deployments"] validations: - expression: "object.spec.replicas <= 5"
Here spec.validations mentions the expression which enforces the constraint to be checked and spec.failurePolicy enforces the action to be taken if the constraint is not met.
Binding
apiVersion: admissionregistration.k8s.io/v1alpha1 kind: ValidatingAdmissionPolicyBinding metadata: name: "demo-binding-test.example.com" spec: policyName: "demo-policy.example.com" validationActions: [Deny] matchResources: namespaceSelector: matchLabels: environment: test
Binding is necessary for the validation policy to be used in the cluster.
Deploying
ValidatingAdmissionPolicy 'demo-policy.example.com' with binding 'demo-binding-test.example.com' denied request: failed expression: object.spec.replicas <= 5
The above is an example of a validation policy without parameter resources. However, constraint expressions and parameter resources are commonly used in validation admission policies. A few of the common expressions include:
Expression | Purpose |
object.minReplicas <= object.replicas && object.replicas <= object.maxReplicas | Validate that the three fields defining replicas are ordered appropriately |
‘Available’ in object.stateCounts | Validate that an entry with the ‘Available’ key exists in a map |
(size(object.list1) == 0) != (size(object.list2) == 0) | Validate that one of two lists is non-empty, but not both |
!(‘MY_KEY’ in object.map1) || object[‘MY_KEY’].matches(‘^[a-zA-Z]*$’) | Validate the value of a map for a specific key, if it is in the map |
object.envars.filter(e, e.name == ‘MY_ENV’).all(e, e.value.matches(‘^[a-zA-Z]*$’) | Validate the ‘value’ field of a listMap entry where key field ‘name’ is ‘MY_ENV’ |
has(object.expired) && object.created + object.ttl < object.expired | Validate that ‘expired’ date is after a ‘create’ date plus a ‘ttl’ duration |
object.health.startsWith(‘ok’) | Validate a ‘health’ string field has the prefix ‘ok’ |
object.widgets.exists(w, w.key == ‘x’ && w.foo < 10) | Validate that the ‘foo’ property of a listMap item with a key ‘x’ is less than 10 |
type(object) == string ? object == ‘100%’ : object == 1000 | Validate an int-or-string field for both the int and string cases |
object.metadata.name.startsWith(object.prefix) | Validate that an object’s name has the prefix of another field value |
object.set1.all(e, !(e in object.set2)) | Validate that these two listSets do not contain any common elements |
size(object.names) == size(object.details) && object.names.all(n, n in object.details) | Validate the ‘details’ map is keyed by the items in the ‘names’ listSet |
size(object.clusters.filter(c, c.name == object.primary)) == 1 | Validate that the ‘primary’ property has one and only one occurrence in the ‘clusters’ listMap |
Alternatives
Before the use of validation admission policies, admission webhooks were used for validating objects which strengthened the infrastructure’s security. However, these had several drawbacks. A few of those were:
- The process of creating and deploying admission webhooks is much more tedious than creation validation admission policies.
- Each webhook had to be created separately and required a distinct upgrade and rollback plan. As a result, the process of operating, monitoring, and managing such admission webhooks was quite difficult, and scalability became an issue.
Best practices
- Leverage admission controllers by enabling them to access and implement advanced security features.
- Ensure NamespaceLifecycle, LimitRanger, ServiceAccount, DefaultStorageClass, DefaultTolerationSeconds, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, Priority, ResourceQuota, are enabled by default.
- Create customized webhook-based admission controllers based on the cluster or infrastructure’s requirements.
- Use the above-mentioned admission controllers to restrict access, permissions, and privileges. This will result in a smaller attack surface and remove vulnerabilities caused by misconfigurations, thus strengthening the security.
- The root file system must be mounted as read-only.
- Containers must be prevented from running as root.
- Only allow the usage of an approved registry to pull images from.
- Deploy label validation to ensure the right labels are used, making it simpler for DevOps engineers to configure various resources.
- Regularly audit the configurations of the cluster using admission controllers and validation admission policies to prevent vulnerabilities.
Summary
Kubernetes validation admission policies and admission controllers are an advanced way for DevOps engineers to tap into advanced security measures of the Kubernetes infrastructure. These enable organizations to harden their security system, prevent misconfigurations, lower the attack surface area, and prevent malicious attacks and breaches in a simple and efficient manner.