Quickstart
This guide helps you get started with PodLock.
Requirements
-
A Kubernetes cluster with:
-
Nodes running Linux kernel with Landlock support.
-
A container runtime that supports Node Resource Interface (NRI).
-
helminstalled locally -
kubectlinstalled locally -
cert-managerinstalled in the cluster
Preparing the cluster
It is not recommended to run PodLock with clusters spawned by kind, the nodes should be running inside a VM or physical machines with Landlock support.
Unfortunately, as of December 2025, the VM used by minikube does not support Landlock.
It’s recommended to use lima instead.
| Lima is a lightweight VM manager for Linux on macOS and Linux. See https://lima-vm.io/ for more information. |
limactl start \
--cpus 4 \
--memory 16 \
--name podlock \
--yes \
template:k3s
Then you can grab the kubeconfig using the following command:
export KUBECONFIG=$(limactl list podlock --format 'unix://{{.Dir}}/copied-from-guest/kubeconfig.yaml')
The container runtime engine must support Node Resource Interface (NRI).
Currently only containerd and CRI-O support NRI.
containerd support for NRI has been introduced starting from version 1.7, it has been enabled by default starting from version 2.0.
CRI-O supports NRI starting from version 1.25, please refer to the CRI-O documentation for enabling NRI support.
A container runtime like runC must be used as low-level runtime for the
container engine.
Install cert-manager
PodLock uses webhooks for validating resources, which require TLS certificates. cert-manager automates the creation and management of these certificates.
To install cert-manager, run the following commands:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true \
--wait
For more information on configuring cert-manager, please visit the cert-manager documentation.
Install PodLock
To install PodLock using Helm, run the following commands:
helm repo add podlock https://flavio.github.io/podlock
helm repo update podlock
helm install podlock podlock/podlock \
--namespace podlock \
--create-namespace \
--wait
Verify the installation
After installation, ensure all pods are running:
kubectl get pods -n podlock
Example output:
kubectl get all -n podlock
NAME READY STATUS RESTARTS AGE
pod/podlock-controller-6ccd46779d-v4fzz 1/1 Running 1 (29m ago) 29m
pod/podlock-nri-plugin-c676q 1/1 Running 1 (29m ago) 29m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/podlock-controller-webhook ClusterIP 10.43.82.139 <none> 443/TCP 29m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/podlock-nri-plugin 1 1 1 1 1 <none> 29m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/podlock-controller 1/1 1 1 29m
NAME DESIRED CURRENT READY AGE
replicaset.apps/podlock-controller-6ccd46779d 1 1 1 29m
Applying a Landlock Profile
In this example, we’ll create a Pod that performs various file operations and attempts to execute binaries. We’ll then apply a Landlock profile to restrict which operations are allowed.
Let’s start by creating a test Pod:
apiVersion: v1
kind: Pod
metadata:
name: landlock-test
namespace: default
labels:
podlock.kubewarden.io/profile: "demo"
spec:
restartPolicy: Never
containers:
- name: main
image: alpine:latest
command: ["/bin/ash", "-c"]
args:
- |
echo "Testing allowed read..."
cat /etc/hostname
echo "Testing forbidden execution"
apk version
echo "Testing forbidden write"
cp -v /etc/motd /motd
echo "Testing allowed read and allowed write"
cp -v /etc/motd /tmp
echo "Testing forbidden read"
cp -v /etc/passwd /tmp
echo "Test done, going to sleep"
sleep 1h
This Pod is based on the alpine:latest image, and it tries to perform
various file operations. It also tries to execute the apk binary.
Now let’s create a Landlock profile to restrict some of these operations:
apiVersion: podlock.kubewarden.io/v1alpha1
kind: LandlockProfile
metadata:
name: demo
namespace: default
spec:
profilesByContainer:
main:
"/bin/ash":
readExec:
- "/bin/echo"
- "/bin/cat"
- "/bin/cp"
- "/bin/sleep"
- "/lib"
readWrite:
- "/tmp"
readOnly:
- "/etc/hostname"
- "/etc/motd"
The LandlockProfile and the Pod are located in the same namespace (default).
The profile is bound to the Pod using the label podlock.kubewarden.io/profile: "demo".
Now let’s apply both resources:
kubectl apply -f landlock-profile.yaml
kubectl apply -f landlock-test-pod.yaml
You can check the Pod logs to see the results of the file operations:
kubectl logs landlock-test
You will see output similar to this:
Testing allowed read...
landlock-test
Testing forbidden execution
Testing forbidden write
/bin/ash: apk: Permission denied
cp: can't create '/motd': Permission denied
Testing allowed read and allowed write
'/etc/motd' -> '/tmp/motd'
Testing forbidden read
cp: can't open '/etc/passwd': Permission denied
Test done, going to sleep
As you can see, the Pod was able to read /etc/hostname and copy /etc/motd to /tmp.
However, it was not able to execute the apk command, nor write to the root filesystem
or read /etc/passwd, as those operations were not allowed by the Landlock profile.
You can now delete the Pod and the profile:
kubectl delete pod -n default landlock-test
kubectl delete landlockprofile demo -n default
Troubleshooting
If the PodLock controller pod is not running:
kubectl describe pod -n podlock -l app=podlock-controller
Verify Landlock support
The PodLock NRI plugin automatically detects the Landlock version supported by each node and adds a label to it.
Check the Landlock version on your nodes:
kubectl get nodes -L podlock.kubewarden.io/landlock-version
You should see output similar to this:
NAME STATUS ROLES AGE VERSION LANDLOCK-VERSION
lima-podlock Ready control-plane,master 22h v1.33.6+k3s1 4
The podlock.kubewarden.io/landlock-version label contains the Landlock version number (0, 1, 2, 3, etc.).
A value of 0 means the node has no Landlock support.
| PodLock requires Landlock version 3 or higher. Nodes with version 0, 1, or 2 do not provide the necessary Landlock features for PodLock to work. |