🧐 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.
IMPORTANT: This is alpha version and may include breaking changes in the future which will require updating.
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.
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
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).
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.
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
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.
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
As a first step, Monokle Admission Controller needs to be deployed to your cluster (see Installation section above).
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.
Monokle Admission Controller requires Automation Token to sync with Monokle Cloud. In order to obtain one:
- Login or sign-up to Monokle Cloud.
- Go to Workspaces and select a Workspace to assign cluster to.
- You will find
Clusters
tab in the Workspace menu, after navigating there useAdd Cluster
button. - Fill-in name and optional description and press
Create
. - 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.
Policies can be added to specific cluster namespaces from withing Cluster view:
- Navigate to your Workspace and then
Clusters
tab. - Click on a Cluster which you want to work with.
- After navigating to a Cluster Overview, you can see list of all namespaces.
- 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 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.
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
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
Monokle Admission Controller introduces 2 dedicated kinds through CRDs - MonoklePolicy
and MonoklePolicyBinding
.
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
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).
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
orsilent
. Useful for debugging.
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.