Testing for cluster operators
As a Kubernetes cluster operator, you'll want to perform testing for Kubewarden policies you want to use.
You'll have questions like:
- What are the correct policy settings to get the validation/mutation outcome needed?
- How can I be sure everything keeps working as expected when I:
- upgrade the policy to a newer version?
- add/change Kubernetes resources?
- change the configuration parameters of the policy?
- and so forth?
 
Kubewarden has a utility, kwctl,
that permits testing of the policies outside of Kubernetes.
To use kwctl you invoke it with following inputs:
- A WebAssembly binary file URI of the policy to be run.
The Kubewarden policy can load from the:
- local filesystem file://
- a HTTP(s) server https://
- an OCI registry registry://.
 
- local filesystem 
- The admission request object to test.
You give it with the --request-pathargument. Usestdinby setting--request-pathto-.
- The policy settings for runtime as an inline JSON via --settings-jsonflag. Or a JSON, or a YAML file, loaded from the file system via--settings-path.
After the test kwctl, prints the ValidationResponse object to the standard output.
You can download pre-built binaries of kwctl
here.
A testing example​
This section describes how to test the psp-apparmor policy with different configurations and validation request objects.
Create AdmissionReview requests​
You need to create files holding the AdmissionReview objects to test the policy.
You can create a file named pod-req-no-specific-apparmor-profile.json with the following contents:
pod-req-no-specific-apparmor-profile.json
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "kind": {
    "kind": "Pod",
    "version": "v1"
  },
  "object": {
    "metadata": {
      "name": "no-apparmor"
    },
    "spec": {
      "containers": [
        {
          "image": "nginx",
          "name": "nginx"
        }
      ]
    }
  },
  "operation": "CREATE",
  "requestKind": {"version": "v1", "kind": "Pod"},
  "userInfo": {
    "username": "alice",
    "uid": "alice-uid",
    "groups": ["system:authenticated"]
  }
}
This request tries to create a Pod that doesn't specify any AppArmor profile to use.
This is because it doesn't have an annotation with the
container.apparmor.security.beta.kubernetes.io/<container-name> key.
You can create a file named pod-req-apparmor-unconfined.json with the
following contents:
pod-req-apparmor-unconfined.json
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "kind": {
    "kind": "Pod",
    "version": "v1"
  },
  "object": {
    "metadata": {
      "name": "privileged-pod",
      "annotations": {
        "container.apparmor.security.beta.kubernetes.io/nginx": "unconfined"
      }
    },
    "spec": {
      "containers": [
        {
          "image": "nginx",
          "name": "nginx"
        }
      ]
    }
  },
  "operation": "CREATE",
  "requestKind": {"version": "v1", "kind": "Pod"},
  "userInfo": {
    "username": "alice",
    "uid": "alice-uid",
    "groups": ["system:authenticated"]
  }
}
This request tries to create a Pod with a container called nginx running with the unconfined AppArmor profile.
This is for tutorial purposes only.
Running in unconfined mode is a bad security practice.
Now you can create a file named
pod-req-apparmor-custom.json with the following contents:
pod-req-apparmor-custom.json
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "kind": {
    "kind": "Pod",
    "version": "v1"
  },
  "object": {
    "metadata": {
      "name": "privileged-pod",
      "annotations": {
        "container.apparmor.security.beta.kubernetes.io/nginx": "localhost/nginx-custom"
      }
    },
    "spec": {
      "containers": [
        {
          "image": "nginx",
          "name": "nginx"
        }
      ]
    }
  },
  "operation": "CREATE",
  "requestKind": {"version": "v1", "kind": "Pod"},
  "userInfo": {
    "username": "alice",
    "uid": "alice-uid",
    "groups": ["system:authenticated"]
  }
}
These are all simplified AdmissionReview objects.
Only the fields relevant to our testing of the policy are used.
Test the policy​
Now you can use kwctl to test the creation of a Pod not specifying an AppArmor profile:
$ kwctl run \
    --request-path pod-req-no-specific-apparmor-profile.json \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4 \
    | jq
The policy accepts the request and produces output like:
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "allowed": true
}
The policy rejects the creation of a Pod with an unconfined AppArmor profile:
$ kwctl run \
    --request-path pod-req-apparmor-unconfined.json \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4 \
    | jq
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "allowed": false,
  "status": {
    "message": "These AppArmor profiles are not allowed: [\"unconfined\"]"
  }
}
On both occasions you ran the policy without providing any kind of setting. As the policy's documentation states, this results in preventing the usage of non-default profiles.
The Pod using a custom nginx profile gets rejected by the policy too:
$ kwctl run \
    --request-path pod-req-apparmor-custom.json \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4 \
    | jq
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "allowed": false,
  "status": {
    "message": "These AppArmor profiles are not allowed: [\"localhost/nginx-custom\"]"
  }
}
You can change the default behavior, allowing chosen AppArmor profiles to be used:
$ kwctl run \
    --request-path pod-req-apparmor-custom.json \
    --settings-json '{"allowed_profiles": ["runtime/default", "localhost/nginx-custom"]}' \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4 \
    | jq
Now the request succeeds:
{
  "uid": "1299d386-525b-4032-98ae-1949f69f9cfc",
  "allowed": true
}
Automation​
You can automate all these steps using bats.
You can write a series of tests and integrate their execution inside your existing CI and CD pipelines.
The commands can be "wrapped" into a bats test:
A batstest
@test "all is good" {
  run kwctl run \
    --request-path pod-req-no-specific-apparmor-profile.json \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4
  # this prints the output when one the checks below fails
  echo "output = ${output}"
  # request accepted
  [ $(expr "$output" : '.*"allowed":true.*') -ne 0 ]
}
@test "reject" {
  run kwctl run \
    --request-path pod-req-apparmor-custom.json \
    registry://ghcr.io/kubewarden/policies/psp-apparmor:v0.1.4
  # this prints the output when one the checks below fails
  echo "output = ${output}"
  # request rejected
  [ $(expr "$output" : '.*"allowed":false.*') -ne 0 ]
}
If the bats code is in the file e2e.bats, you can run the test as:
$ bats e2e.bats
 ✓ all is good
 ✓ reject
2 tests, 0 failures
This section has more about writing end-to-end tests for your policies.