Skip to content

Kubernetes Admission Controller for enforcing policies in your clusters

License

Notifications You must be signed in to change notification settings

kubeshop/monokle-admission-controller

Repository files navigation

Monokle Logo

Website | Discord | Blog

🧐 Monokle Admission Controller is an in-cluster policy enforcement tool with various build-in policy plugins (for PSS, NSA and CIS security frameworks) and integrated with Monokle ecosystem enabling centralized policy management and enforcement.

Latest Release

IMPORTANT: This is alpha version and may include breaking changes in the future which will require updating.

Table of contents

Overview

Monokle Admission Controller allows to validate in-cluster resources during their lifecycle events (create and update). It is based on native Kuberentes Admission Controlers mechanism and allows defining policies through dedicated CRDs. During resource creation or update it will show warnings related to all policy violations.

It comes with validation engine supporting number of plugins to provide you with comprehensive validation possibilities for K8s resources out of the box:

  • Pod Security Standards - validation for secure deployments.
  • Kubernetes Schema - validation to ensure your resource are compliant with their schemas and a target K8s version.
  • Metadata - validation for standard and custom labels/annotations.
  • Common practices - validation for basic configuration sanity.
  • Security policies - based on OPA (Open Policy Agent) to reduce your attack surface.
  • YAML Syntax - validates that your manifests have correct YAML syntax.

Learn more about each Core Plugin in the Core Plugins Documentation.

Installation

Installing Monokle Admission Controller bunch of resources so it is recommended to install it to separate namespace. This can be done with -n namespace flag for Helm. For install-*.yaml scripts, it will be installed to monokle namespace which needs to be created before running install script.

You can see all deployed resources with e.g. kubectl:

kubectl -n monokle get all,CustomResourceDefinition,ValidatingWebhookConfiguration,secrets

With Cloud Sync

Monokle Admission Controller can be installed with Monokle Cloud synchronization enabled. Such setup allows to manage policies in the cluster from the cloud. With integration with the rest of Monokle ecosystem - Monokle Desktop, VSCode extension and CLI, it allows for centralized policy enforcement for your project. This is recommended use which brings full potential of Monokle Ecosystem into your project lifecycle.

The only required configuration is an Automation Token which can be generated in Monokle Cloud (see how to generate it in Monokle Cloud in Monokle Cloud section below).

Helm

Latest Monokle Admission controller can be installed directly from DockerHub OCI registry:

helm install my-release oci://registry-1.docker.io/kubeshop/monokle-admission-controller --set automationToken=YOUR_AUTOMATION_TOKEN -n monokle

You can read more about DockerHub OCI registry here.

Or from GitHub release:

helm install my-release https://github.com/kubeshop/monokle-admission-controller/releases/download/v0.2.7/helm.tgz --set automationToken=YOUR_AUTOMATION_TOKEN -n monokle

Tip: To create namespace automatically as part of helm install, use --create-namespace flag.

See customization section below on what can be customized with Helm variables.

Kubectl

You can install Monokle Admission Controller using kubectl and dedicated cloud install manifest:

kubectl create ns monokle && \
kubectl apply -f https://github.com/kubeshop/monokle-admission-controller/releases/download/v0.2.7/install-cloud.yaml

Since Monokle Cloud automation token needs to be provided, there is a dedicated secret created which needs to be updated:

kubectl patch secret monokle-synchronizer-token -p "{ \"data\": { \".token\": \"${YOUR_AUTOMATION_TOKEN_BASE64}\" } }" -n monokle-admission-controller

Standalone

Helm

Latest Monokle Admission controller can be installed directly from DockerHub OCI registry:

helm install my-release oci://registry-1.docker.io/kubeshop/monokle-admission-controller -n monokle

You can read more about DockerHub OCI registry here.

Or from GitHub release:

helm install my-release https://github.com/kubeshop/monokle-admission-controller/releases/download/v0.2.7/helm.tgz -n monokle

Tip: To create namespace automatically as part of helm install, use --create-namespace flag.

See customization section below on what can be customized with Helm variables.

Kubectl

You can install Monokle Admission Controller using kubectl and dedicated standalone install manifest:

kubectl create ns monokle && \
kubectl apply -f https://github.com/kubeshop/monokle-admission-controller/releases/download/v0.2.7/install-standalone.yaml

Usage

As a first step, Monokle Admission Controller needs to be deployed to your cluster (see Installation section above).

Monokle Cloud

You can manage policies and bindings directly from Monokle Cloud. It allows you to define multiple policies and bind them to specific namespaces. The list of available namespaces (apart from ignored ones) will be synced to cloud for ease of use.

Getting Automation Token

Monokle Admission Controller requires Automation Token to sync with Monokle Cloud. In order to obtain one:

  1. Login or sign-up to Monokle Cloud.
  2. Go to Workspaces and select a Workspace to assign cluster to.
  3. You will find Clusters tab in the Workspace menu, after navigating there use Add Cluster button.
  4. Fill-in name and optional description and press Create.
  5. After creation you will get Automation Token and full command to deploy Monokle Admission Controller to your cluster (refer to Installation section in case of any doubts).

Soon after Monokle Admission Controller is deployed, you should see Cluster status as Connected in Workspace Clusters list.

Managing Policies synchronization

Policies can be added to specific cluster namespaces from withing Cluster view:

  1. Navigate to your Workspace and then Clusters tab.
  2. Click on a Cluster which you want to work with.
  3. After navigating to a Cluster Overview, you can see list of all namespaces.
  4. On this list, policies can be assigned to any namespaces using + button next to them.

Policies are defined on project level - each project can define single policy. If you don't have any projects yet, navigate to Projects to create one and then define policy via Policy tab.

Policies should be synchronized to the cluster within couple of minutes. You can verify by checking if policy resources are already in the cluster:

kubectl get policies,policybindings

And then when any resource is created or updated and violates specific policy, it can be seen in command output, for example:

kubectl apply -f examples/pod-warning.yaml -n sample-namespace
Warning: Monokle Admission Controller found 3 errors and 3 warnings:
Warning: KSV011 (error): Require the CPU to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV016 (error): Require the memory to be requested on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV018 (error): Require the memory to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV001 (warning): Disallow the process from elevating its privileges on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV003 (warning): Require default capabilities to be dropped on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV012 (warning): Requires the container to runs as non root user on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: You can use Monokle Cloud (https://monokle.io/) to fix those errors easily.
pod/pod-warning created

Standalone Configuration

Standalone deployment requires policies to be defined and deployed manually. You can read more about Policy format in Policies section below.

There is a examples folder provided in this repository where you can see example policies and bindings resources which can be used to test Monokle Admission Controller.

Defining Global policy

Global policy means the one not bound to any namespace. It will be applied to resources in all namespaces and those cluster-wide.

Start with policy definition, my-policy.yaml:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicy
metadata:
  name: my-policy
spec:
  plugins:
    yaml-syntax: true
    open-policy-agent: true
    kubernetes-schema: true
    annotations: true

Can be deployed with e.g. kubectl:

kubectl apply -f my-policy.yaml

And then bound it globally with my-policy-binding.yaml:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Warn]
kubectl apply -f my-policy-binding.yaml

At this stage my-policy is bound and Monokle Admission Controller knows that any resource (while being created or updated) should be validated with it.

For example, deploying sample resource like:

kubectl apply -f examples/pod-warning.yaml -n sample-namespace

Should result in similar output as below:

Warning: Monokle Admission Controller found 3 errors and 8 warnings:
Warning: KSV011 (error): Require the CPU to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV016 (error): Require the memory to be requested on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV018 (error): Require the memory to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV001 (warning): Disallow the process from elevating its privileges on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV003 (warning): Require default capabilities to be dropped on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV012 (warning): Requires the container to runs as non root user on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV013 (warning): Disallow images with the latest tag on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV014 (warning): Require a read-only root file system on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV015 (warning): Require the CPU to be requested on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV020 (warning): Disallow running with a low user ID on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV021 (warning): Disallow running with a low group ID on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: You can use Monokle Cloud (https://monokle.io/) to fix those errors easily.
pod/pod-warning created

Defining Namespaced policy

Namespaced policy is bound to specific namespace. This means only resources created or updated in this namespace will be validated with it.

Start with policy definition, my-policy.yaml:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicy
metadata:
  name: my-policy
spec:
  plugins:
    yaml-syntax: true
    open-policy-agent: true
    kubernetes-schema: true
    annotations: true

Can be deployed with e.g. kubectl:

kubectl apply -f my-policy.yaml

And then bound it namespace of your choice with my-policy-binding.yaml:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Warn]
  matchResources:
    namespaceSelector:
      matchLabels:
        namespace: my-namespace
kubectl apply -f my-policy-binding.yaml

At this stage my-policy is bound and Monokle Admission Controller knows that any resource in my-namespace namespace (while being created or updated) should be validated with it.

For example, deploying sample resource like:

kubectl apply -f examples/pod-warning.yaml -n my-namespace

Should result in similar output as below:

Warning: Monokle Admission Controller found 3 errors and 8 warnings:
Warning: KSV011 (error): Require the CPU to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV016 (error): Require the memory to be requested on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV018 (error): Require the memory to be limited on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV001 (warning): Disallow the process from elevating its privileges on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV003 (warning): Require default capabilities to be dropped on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV012 (warning): Requires the container to runs as non root user on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV013 (warning): Disallow images with the latest tag on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV014 (warning): Require a read-only root file system on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV015 (warning): Require the CPU to be requested on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV020 (warning): Disallow running with a low user ID on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: KSV021 (warning): Disallow running with a low group ID on container "busybox", in kind "Pod" with name "pod-warning/default/pod".
Warning: You can use Monokle Cloud (https://monokle.io/) to fix those errors easily.
pod/pod-warning created

While deploying to a different one:

kubectl apply -f examples/pod-warning.yaml -n other-namespace

Will be ignored by Monokle Admission Controller:

pod/pod-warning created

Policies

Monokle Admission Controller introduces 2 dedicated kinds through CRDs - MonoklePolicy and MonoklePolicyBinding.

MonoklePolicy

The MonoklePolicy kind is a policy definition. It contains only the definition with list of plugins and rules enabled and additional settings. If you are familiar with Monokle Ecosystem, this is the exact same policy format as Monokle Desktop, Cloud, CLI and other tools use.

The basic .yaml policy definition looks like:

plugins:
  yaml-syntax: true
  open-policy-agent: true
  kubernetes-schema: true
  annotations: true

While MonoklePolicy manifest would be:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicy
metadata:
  name: my-policy
spec:
  plugins:
    yaml-syntax: true
    open-policy-agent: true
    kubernetes-schema: true
    annotations: true

MonoklePolicyBinding

The MonoklePolicyBinding defines to what namespaces, given MonoklePolicy should be applied.

It can be bound globally (no namespace), meaning all namespaced and cluster-wide resources will be validated:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Warn]

To a single namespace:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchLabels:
        name: default

To a list of namespaces:

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Warn]
  matchResources:
    namespaceSelector:
      matchExpressions:
        - key: name
          operator: In
          values: [ns-dev, ns-stage]

Or as exclusion, meaning "apply to all other namespaces than the ones listed":

apiVersion: monokle.io/v1alpha1
kind: MonoklePolicyBinding
metadata:
  name: my-policy-binding
spec:
  policyName: my-policy
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchExpressions:
        - key: name
          operator: NotIn
          values: [ns-prod]

The policyName field refers to MonoklePolicy resource name, while matchResources is optional and can be used to narrow binding scope to specific namespace. If follows the same convention as in other Kubernetes kinds, supporting namespaceSelector with matchLabels and matchExpressions.

The validationActions supports Warn and Deny actions at this stage. Warn means "send a warning for every policy violation detected" and Deny will block resource creation/update when there are any violations. In the upcoming versions it will be expanded to more actions like - Ignore and Report (see #10).

Customizing Helm deployment

You can refer to helm/values.yaml file to see what can be change for Helm deployment. The most important values:

  • ignoreNamespaces - list of namespaces which should be ignored by admission controller (this option has priority over policy bindings and Cloud sync). By default Kubernetes system namespaces and Monokle Admission Controller namespace are ignored.
  • replicas - number of admission controller pod server replicas.
  • automationToken - Monokle Cloud automation token to enable syncing with the cloud.
  • image - admission controller container images related configuration. Allows the use of specific image or tag. However, since image versions are tightly bound with Helm chart version, we do not advise changing this one for production deployments.
  • logLevel - internal logging level. Supported values: error, warn, info, debug, trace or silent. Useful for debugging.

Contributing and development

This is an open source project and we would love to hear your feedback and suggestions!

Feel free to drop us any questions on Monokle Discord server. If you found a bug or would like to request a new feature, report it as GitHub issue.

We are happy to help and assist you in case of any doubts or questions.

For contributing code and development workflow see CONTRIBUTING.md.