Monokle blog

Prevent Kubernetes Misconfigurations with Monokle’s Custom Policy Validators

Aug 31, 2023
5 min
read
Sonali Srivastava
Technology Evangelist
monokle

Enforcing policies for higher-quality deployment doesn't have to be difficult. Build and leverage the power of Monokle's Custom Policy Validators to optimize your pre-commit workflows.

Prevent Kubernetes Misconfigurations with Monokle’s Custom Policy Validators
Share on Twitter
Share on LinkedIn
Share on Reddit
Share on HackerNews
Copy URL

Table of Contents

Get started with Monokle today

Get started with Monokle today

Imagine a company named ACME Technologies that has been using Argo CD for continuous delivery to their Kubernetes clusters. They use resource hooks to schedule certain jobs which can be deleted automatically based on pre-configured hook deletion policies. However, a developer failed to use the recommended guidelines to set the parameter '/metadata/name` with 'BeforeHookCreation' as its value. This led to jobs not being cleaned up and a misconfiguration in production.

Situations like these can easily be avoided by putting a policy in place to check the parameter value automatically before deployment. Different tools allow you to create policies and take preventive action. Tools like OPA, Rego, and, Trivy allow us to enforce security policies and ensure compliance. However, for scenarios like the above where enforcing generic policies is required, Monokle shines as it allows us to create custom policies and validations.

By leveraging Monokle's custom policy validation framework, we can efficiently enforce such policies, and ensure that they are applied consistently helping to mitigate risks and ensuring that your organization complies with its obligations for security and best practices. In this blog post, we will explore custom policy validators, write a policy rule, and demonstrate how to enable it for a manifest using Monokle.

What are Custom Policy Validators?

A policy validator is a tool to verify that manifests conform to specific rules and guidelines, such as compliance regulations or security best practices. Monokle has its implementation of a policy validator, called the custom policy validator that allows organizations or developers to define their own policy validation rules that are tailored to their unique needs.

  • Custom Policy: A custom policy is a set of rules to ensure an application complies with your organization’s requirements. Custom policies can be written in programming languages like Go or Typescript. Monokle Cloud provides the capability to enable these custom policies as a plugin to validate your application’s YAML configurations.
  • Plugin: A policy or any utility can not be directly imported into an application. We need to package it. A plugin is a package of utilities like policies for validation along with its metadata.

The Monokle validation framework offers several benefits, including

  • Policy As Code: Monokle allows developers to write a policy as code using Typescript, making it easier to implement and manage policies within their codebase.
  • Efficient Validation Process: By automating the policy validation process, Monokle reduces the risk of human error that can occur with manual checks. This feature also saves time and resources by eliminating the need for repetitive manual checks.
  • Customization and Flexibility: Monokle can be easily adapted to fit specific organizational needs, making it a versatile tool for managing policies across different teams and projects.

By using the Monokle validation framework, organizations can improve their policy management processes, reduce the risk of errors, and increase overall efficiency.

How to write a custom policy using Monokle?

Monokle provides a library that makes getting started with policy validation much more convenient. Using this library, we will create the template files which are essential for plugin development. To get started, we will make some basic changes and then write a custom policy. Using Monokle Cloud, we will enable it to validate our manifest for compliance. You can also make use of Monokle CLI to enable the custom policy.

Use Case

To understand how custom policy works in Monokle, we will create a policy that checks the memory consumption of deployment resource containers on the development server. Complying with this policy will limit the developers from exceeding the optimum resource utilization for the dev environment.

Solution

The solution to this use case can be split into two parts as policies:

  1. Check the resources for the dev environment: Monokle provides a default plugin called Metadata. We will make use of it to check if the resources have the `env` label set as `dev`.
  1. Check memory consumption of deployment resource containers: This requires us to create a custom plugin that will contain the written policies. Monokle provides a library to get started with setup. The developer mode imports the plugin to Monokle Cloud.

Let us go ahead and set up the prerequisites to get started with configuring and enabling the above two policies.

Prerequisites

Pre-configuration

With the pre-requisite setup, we can get started with configuring the first policy using the Metadata plugin. Once done, we will then set up the plugin for creating a custom policy using the library provided by Monokle.

Enable Metadata Plugin

With Metadata Plugin, we can create a policy on the go to check for the metadata. It allows us to add metadata as a key value for labels and annotations. In this use case, we need to check if the env label is set for resource and has a value `dev`.

Access the repository in Monokle Cloud. In the Toolbar, click on the validation icon, scroll to the bottom, and use the toggle button to enable the Metadata plugin.

Click on Configure and select the metadata type as Label. Enter the key and the expected possible values. Click on `OK`.

Great! The policy to check if resources are for the dev environment only is ready to use. Let us go ahead and get started with creating a custom policy for checking memory consumption, importing it as a plugin, and enabling developer mode to allow integration in Monokle Cloud.

Enable Developer Mode

The developer mode allows interaction with the policy plugin in Monokle Cloud. Once enabled, you can configure the plugin after development. To get started, select your Kubernetes resources repository for which you want to enable validation in Monokle Cloud.

Select the validation icon from the Toolbar, scroll to the bottom in the Validate your resources pane, and click on the toggle button to enable developer mode.

Great! Now that developer mode is enabled, when you run the development server on your local machine, Monokle will automatically sync the changes you make in the plugin in real time.

Setup Plugin

Clone the GitHub repository of the library.

```

$ git clone https://github.com/kubeshop/monokle-core.git

```

Change the directory to `create-monokle-plugin` directory and initiate the creation of the plugin package using the following commands:


```

$ cd monokle-core/packages/create-monokle-plugin/
$ npm create monokle-plugin@latest

```

This will initiate the plugin setup in interactive mode as shown below: 

```

$ npm create monokle-plugin@latest
✔ Plugin name: … resource-limit
✔ Select a plugin type: › validation
✔ Select a variant: › validation-ts
✔ Select a template: › basic
Scaffolding plugin in /kubeshop/test_setup/resource-limit...
Done. Now run:
  cd resource-limit
  npm install
  npm run dev

```

Let’s dig into what happens in each of these steps.

  • Plugin name: Enter the plugin name and press enter. 
  • Plugin type: Monokle currently supports validation plugins. Press enter to use the default value.
  • Variant: Select the variant or the programming language of your policies. Monokle currently supports Typescript. Press enter to use the default value.
  • Template: Monokle provides some template files to get started with writing the policies.
  • basic: Contains a sample plugin with a simple rule in Typescript.
  • with-custom-crd: Contains a sample Typescript plugin using a Custom Resource Definition.

You can continue pressing enter for each step further as Monokle takes care of filling in all default values.

Once the plugin setup is complete, a directory will be created with the `plugin name` provided that contains the package for the plugin.

Install the Plugin Package

Change the directory to the newly created directory for the plugin and initiate installation.
```
$ cd resource-limit/
~/resource-limit$ npm install
> resource-limit@1.0.0 postinstall
> npm run codegen
> resource-limit@1.0.0 codegen
> monokle-plugin-toolkit codegen
added 166 packages, and audited 167 packages in 5s
14 packages are looking for funding
  run `npm fund` for details
```

Refer to our tutorial to understand the autogenerated files that are essential for plugin development.

Modifying Plugin Files 

The package.json maintains the package details. Update `author` in `package.json` for the unique identification of who is maintaining the package.

```
{
  "name": "resource-limit",
  "author": "Sonali Srivastava",
  "description": "Validates with custom rules.",
  "license": "MIT",
  "version": "1.0.0",
  "main": "dist/plugin.js",
  "type": "module",
  "scripts": {
    "postinstall": "npm run codegen",
    "codegen": "monokle-plugin-toolkit codegen",
    "dev": "monokle-plugin-toolkit dev",
    "build": "monokle-plugin-toolkit build",
    "debug": "monokle-plugin-toolkit build --debug"
  },
  "dependencies": {
    "@monokle/plugin-toolkit": "^0.1.0"
  }
}
```

In the above codebase for `package.json`, we have updated the `author` value from unknown to maintainer name.

Next, update `/src/plugin.ts` which maintains the plugin metadata. This information will be visible in Monokle Cloud when the plugin is imported which will help in identifying it.

```
import { definePlugin } from "@monokle/plugin-toolkit";
import { noEmptyAnnotations } from "./rules/1-example.js";
export default definePlugin({
  id: "YCP",
  name: "ycp",
  displayName: "Resource Limit Check Plugin",
  description: "Optimize your resource utilization!",
  rules: {
    noEmptyAnnotations
  },
});
```

In the above codebase for `/src/plugin.ts`, update the `displayName` and `description` for the plugin specific to your requirements. Once the file is saved and the development server starts, you should be able to see the custom basic changes in the plugin in Monokle Cloud. Now, let’s head over to the terminal and start the development server.

Run the Development Server

Execute the following command to make the plugin available in Monokle Cloud. This command will start the development server, ensuring that any saved changes to the plugin package are immediately reflected in the Monokle Cloud in developer mode.

```
~/resource-limit$ npm run dev
> resource-limit@1.0.0 dev
> monokle-plugin-toolkit dev
Monokle dev server (beta)
You can now develop and preview your rules in real-time within Monokle Cloud.
tip: make sure you have developer mode enabled.
```

Verify in Monokle Cloud

The custom display information and the default rule are available in Monokle Cloud and can be enabled using the toggle button. Click on Configure to view the default rule.

Plugin available in Monokle Cloud

Write a Custom Policy

Now that the plugin is ready, we can add our custom policy to it. In this section, we will write a custom policy. As per the policy, each Kubernetes deployment resource for the `dev` environment can only consume 1G of memory.

Create a new Typescript file named `2-ensureMemLimit.ts` in the /src/rules directory. Import function `defineRule` which will be used for defining the policy rule. Set a name for the policy and get started with writing the policy. The `defineRule` function takes a unique ID, a description, help text, and the validation rule. 

In this rule, for each deployment resource, check for the memory limit of containers. The value allowed for memory consumption is 1G. In case the value does not match, report a violation of policy along with the line where the violation is happening. All the configuration files in this setup are available on GitHub.

```
import { defineRule } from "@monokle/plugin-toolkit";
import { isDeployment } from "../schemas/__generated__/deployment.apps.v1.js";
export const ensureMemLimit = defineRule({
  id: 2,
  description: "Please ensure mem limit is set to 1G for dev env deployments",
  help: "Value allowed is 1G",
  validate({ resources }, { report }) {
    resources.filter(isDeployment).forEach((deployment) => {
      const containers = deployment.spec?.template?.spec?.containers;
      if (containers) {
        for (const container of containers) {
            if( container.resources?.limits?.memory !== '1G' ){
              report(deployment, { path: "spec.template.spec.containers" });
           }
        }
      }
    });
  },
});
```

Save the file. The policy created above that contains the rule needs to be imported into the plugin.

Import the Custom Policy and Package as a Plugin

`/src/plugin.ts` maintains the plugin metadata including the display information and rules. Add the policy by importing it to the rule path as shown below and adding the rule in `rules`:

```
import { definePlugin } from "@monokle/plugin-toolkit";
import { noEmptyAnnotations } from "./rules/1-example.js";
import { ensureMemLimit } from "./rules/2-ensureMemLimit.js";
export default definePlugin({
  id: "YCP",
  name: "ycp",
  displayName: "Resource Limit Check Plugin",
  description: "Optimize your resource utilization!",
  rules: {
    noEmptyAnnotations,
    ensureMemLimit
  },
});
```

Save both files that have the policy and the plugin metadata. Run the development server in the terminal. That should allow us to directly view and manage the plugin in Monokle Cloud.

Enable the Custom Policy Plugin

Open Monokle Cloud in the browser and click on the validation icon in the toolbar to access the validation setup. The new plugin is added, and the policy is enabled to apply to the manifest. For verification purposes, change the memory limit value and see if a warning is returned.

Congratulations!! Your memory consumption validator is ready to use. The policy is set to notify as a warning when the policy is violated. Monokle Cloud highlights the issue with a warning sign along with a simple description and a helpful dialogue text box to assist all project members in setting the memory limit to 1G as established by the custom policy you created and plugged into Monokle for the dev environment.

Thus, Monokle saves a lot of time and effort in manually checking every time the env for which the resource limit is intended. Also, it will reduce the risk of accidentally deploying resources with misconfigurations to specific environments. In case you want to develop a plugin and share it across your organization, you can do so by maintaining a repository like the Monokle community plugin

For scenarios like complex data analysis or parameterized data, the organization needs custom policy validation to mitigate risk and comply with its obligation. Monokle's policy as a code approach streamlines the development process and increases developer productivity. 

Moreover, Monokle fosters collaboration and community contribution by providing a platform for developers to create and share custom plugins. All you have to do is fork this repository, add your plugin in `/validation`, and raise a PR.

Conclusion

With Monokle, we have seen how much easier it is to frame your organization's custom policy into a validator and enable that in Monokle to apply on Kubernetes manifests. Future versions of Kubernetes will add similar rules for ingress policies. With Monokle’s custom policy validators, you can tailor your policy enforcement to your specific needs, ensuring that you're always in compliance and reducing the risk of costly mistakes. So, whether you're an IT professional, a compliance officer, or just someone interested in keeping your organization on track, custom policy validators are an absolute must-have.

You can also reach out to Monokle Product Leader Ole if you have feedback about how we can make Monokle work better for you or drop a mail to ole@kubeshop.io for information/assistance. You can also join in conversation with other users via Discord as part of our growing community.

Related Content