Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.

Commit 44c1760

Browse files
authored
Merge pull request #1232 from flavio/run-crds
feat: allow running policies from CRD
2 parents e27ff44 + d79ca28 commit 44c1760

26 files changed

+3177
-1829
lines changed

Cargo.lock

Lines changed: 589 additions & 609 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ anyhow = "1.0"
1212
clap = { version = "4.5", features = ["cargo", "env"] }
1313
clap-markdown = "0.1.4"
1414
clap_complete = "4.5"
15+
color-print = "0.3"
1516
directories = "6.0.0"
1617
flate2 = "1.1"
1718
humansize = "2.1"
@@ -23,7 +24,7 @@ k8s-openapi = { version = "0.25.0", default-features = false, features = [
2324
] }
2425
lazy_static = "1.4.0"
2526
pem = "3"
26-
policy-evaluator = { git = "https://github.com/kubewarden/policy-evaluator", tag = "v0.25.2" }
27+
policy-evaluator = { git = "https://github.com/kubewarden/policy-evaluator", tag = "v0.26.0" }
2728
prettytable-rs = "^0.10"
2829
regex = "1"
2930
rustls-pki-types = { version = "1", features = ["alloc"] }
@@ -41,7 +42,7 @@ tracing = "0.1"
4142
tracing-subscriber = { version = "0.3", features = ["fmt"] }
4243
url = "2.5.0"
4344
walrus = "0.23.0"
44-
wasmparser = "0.233"
45+
wasmparser = "0.235"
4546

4647
hostname-validator = "1.1.1"
4748
# This is required to have reqwest built using the `rustls-tls-native-roots`

README.md

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,19 @@ This value can be obtained using a tool like [crane](https://github.com/google/g
104104
crane digest ghcr.io/kubewarden/policies/psp-capabilities:v0.1.6
105105
```
106106

107-
### Run a policy locally
107+
### Run
108108

109109
`kwctl` can be used to run a policy locally, outside of Kubernetes. This can be used
110110
to quickly evaluate a policy and find the right settings for it.
111111

112112
The evaluation is done against a pre-recorded [`AdmissionReview`](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#request).
113113

114-
Running a policy locally:
114+
> **Note:** it's possible to scaffodl an `AdmissionReview` object from a Kubernetes resource.
115+
> Take a look at [this section](#scaffold-kubernetes-custom-resources) for more details.
116+
117+
#### Run a local policy
118+
119+
To run a local `.wasm` file containing a policy:
115120

116121
```console
117122
kwctl run \
@@ -123,7 +128,33 @@ kwctl run \
123128
Policy configuration can be passed on the CLI via the `--settings-json` flag
124129
or can be loaded from the disk via the `--settings-path` flag.
125130

126-
#### Scaffold AdmissionReview from a Kubernetes resource
131+
#### Run a policy defined by a Kubewarden Custom Resource
132+
133+
To run a local YAML file containing the definition of any of the Kubewarden Custom
134+
Resources:
135+
136+
```console
137+
kwctl run \
138+
-r test_data/ingress.json \
139+
policy.yaml
140+
```
141+
142+
The YAML file can contain any of the Kubewarden CRDs, including policy groups.
143+
144+
**Warning:** kwctl considers only these attributes of the CRD:
145+
146+
- policy module to be evaluated
147+
- policy settings
148+
- context aware resources
149+
150+
All the other fields are ignored. For example, `rules`, `matchConditions`, `objectSelector`,
151+
`namespaceSelector` and other fields are not taken into account.
152+
153+
Moreover, the YAML file could contain multiple declarations of Kubewarden Custom Resources. In this case
154+
kwctl will evaluate each policy found inside of the YAML file. However, the same request is going to be used
155+
during each evaluation.
156+
157+
### [Scaffold AdmissionReview from a Kubernetes resource](#scaffold-admissionreview-from-a-kubernetes-resource)
127158

128159
It's possible to scaffold an `AdmissionReview` object from a Kubernetes resource:
129160

cli-docs.md

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,37 @@ Add Kubewarden metadata to a WebAssembly module
7979

8080
## `kwctl bench`
8181

82-
Benchmarks a Kubewarden policy
82+
Benchmarks a Kubewarden policy.
8383

84-
**Usage:** `kwctl bench [OPTIONS] --request-path <PATH> <uri_or_sha_prefix>`
84+
The policy can be specified in the following ways:
85+
- URI: e.g., `registry://ghcr.io/kubewarden/policies/psp-policy:latest` or `https://example.com/kubewarden/policies/main/psp-policy/psp-policy.wasm`
86+
- SHA prefix: e.g., `c3b80a10f9c3` (requires the policy to be already pulled)
87+
- Local WASM file: e.g., `file://home/tux/new-policy/psp-policy.wasm`
88+
- Local YAML file: e.g., `file://home/tux/cluster-admission-policy.yaml` (contains declarations of Kubewarden Custom Resources like `ClusterAdmissionPolicy`, `AdmissionPolicy`, etc.)
89+
90+
Default Behavior:
91+
If the schema is omitted, `file://` is assumed, rooted in the current directory.
92+
93+
Notes on Kubewarden Custom Resources:
94+
- Flags `--request-path`, `--settings-path`, and `--settings-json` are ignored; settings are read from the Custom Resource definition.
95+
- The `--execution-mode` flag applies to all policies in the YAML file.
96+
- The `--raw` flag cannot be used, as Kubewarden's Custom Resources do not support `raw` policies.
97+
98+
Only the following attributes of the Custom Resource Definition (CRD) are evaluated:
99+
- Policy module
100+
- Policy settings
101+
- Context-aware resources the policy can access
102+
103+
Other fields, such as `rules`, `matchConditions`, `objectSelector`, and `namespaceSelector`, are ignored.
104+
105+
A YAML file may contain multiple Custom Resource declarations. In this case, `kwctl` evaluates each policy in the file using the same request during each evaluation.
106+
107+
108+
**Usage:** `kwctl bench [OPTIONS] --request-path <PATH> <uri_or_sha_prefix_or_yaml_file>`
85109

86110
###### **Arguments:**
87111

88-
* `<URI_OR_SHA_PREFIX>` — Policy URI or SHA prefix. Supported schemes: registry://, https://, file://. If schema is omitted, file:// is assumed, rooted on the current directory.
112+
* `<URI_OR_SHA_PREFIX_OR_YAML_FILE>` — Policy URI, SHA prefix or YAML file containing Kubewarden policy resources. Supported schemes: registry://, https://, file://. If schema is omitted, file:// is assumed, rooted on the current directory.
89113

90114
###### **Options:**
91115

@@ -292,13 +316,37 @@ Removes a Kubewarden policy from the store
292316

293317
## `kwctl run`
294318

295-
Runs a Kubewarden policy from a given URI
319+
Run one or more Kubewarden policies locally.
296320

297-
**Usage:** `kwctl run [OPTIONS] --request-path <PATH> <uri_or_sha_prefix>`
321+
The policy can be specified in the following ways:
322+
- URI: e.g., `registry://ghcr.io/kubewarden/policies/psp-policy:latest` or `https://example.com/kubewarden/policies/main/psp-policy/psp-policy.wasm`
323+
- SHA prefix: e.g., `c3b80a10f9c3` (requires the policy to be already pulled)
324+
- Local WASM file: e.g., `file://home/tux/new-policy/psp-policy.wasm`
325+
- Local YAML file: e.g., `file://home/tux/cluster-admission-policy.yaml` (contains declarations of Kubewarden Custom Resources like `ClusterAdmissionPolicy`, `AdmissionPolicy`, etc.)
326+
327+
Default Behavior:
328+
If the schema is omitted, `file://` is assumed, rooted in the current directory.
329+
330+
Notes on Kubewarden Custom Resources:
331+
- Flags `--request-path`, `--settings-path`, and `--settings-json` are ignored; settings are read from the Custom Resource definition.
332+
- The `--execution-mode` flag applies to all policies in the YAML file.
333+
- The `--raw` flag cannot be used, as Kubewarden's Custom Resources do not support `raw` policies.
334+
335+
Only the following attributes of the Custom Resource Definition (CRD) are evaluated:
336+
- Policy module
337+
- Policy settings
338+
- Context-aware resources the policy can access
339+
340+
Other fields, such as `rules`, `matchConditions`, `objectSelector`, and `namespaceSelector`, are ignored.
341+
342+
A YAML file may contain multiple Custom Resource declarations. In this case, `kwctl` evaluates each policy in the file using the same request during each evaluation.
343+
344+
345+
**Usage:** `kwctl run [OPTIONS] --request-path <PATH> <uri_or_sha_prefix_or_yaml_file>`
298346

299347
###### **Arguments:**
300348

301-
* `<URI_OR_SHA_PREFIX>` — Policy URI or SHA prefix. Supported schemes: registry://, https://, file://. If schema is omitted, file:// is assumed, rooted on the current directory.
349+
* `<URI_OR_SHA_PREFIX_OR_YAML_FILE>` — Policy URI, SHA prefix or YAML file containing Kubewarden policy resources. Supported schemes: registry://, https://, file://. If schema is omitted, file:// is assumed, rooted on the current directory.
302350

303351
###### **Options:**
304352

src/backend.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl BackendDetector {
133133

134134
/// Check if policy server version is compatible with minimum kubewarden
135135
/// version required by the policy
136+
/// TODO: this should not take an Option
136137
pub fn has_minimum_kubewarden_version(opt_metadata: Option<&Metadata>) -> Result<()> {
137138
if let Some(metadata) = opt_metadata {
138139
if let Some(minimum_kubewarden_version) = &metadata.minimum_kubewarden_version {

src/bench.rs

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/callback_handler/mod.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
use crate::run::{HostCapabilitiesMode, PullAndRunSettings};
1+
use std::path::PathBuf;
2+
23
use anyhow::Result;
34
use policy_evaluator::{callback_requests::CallbackRequest, kube};
4-
use std::path::PathBuf;
55
use tokio::sync::{mpsc, oneshot};
66

7-
use self::proxy::CallbackHandlerProxy;
8-
97
mod proxy;
108

9+
use crate::{
10+
callback_handler::proxy::CallbackHandlerProxy,
11+
config::{pull_and_run::PullAndRunSettings, HostCapabilitiesMode},
12+
};
13+
1114
#[derive(Clone)]
1215
pub(crate) enum ProxyMode {
1316
Record { destination: PathBuf },
@@ -27,29 +30,29 @@ impl CallbackHandler {
2730
pub async fn new(
2831
cfg: &PullAndRunSettings,
2932
kube_client: Option<kube::Client>,
30-
shutdown_channel: oneshot::Receiver<()>,
33+
shutdown_channel_rx: oneshot::Receiver<()>,
3134
) -> Result<CallbackHandler> {
3235
match &cfg.host_capabilities_mode {
3336
HostCapabilitiesMode::Proxy(proxy_mode) => {
34-
new_proxy(proxy_mode, cfg, kube_client, shutdown_channel).await
37+
new_proxy(proxy_mode, cfg, kube_client, shutdown_channel_rx).await
3538
}
3639
HostCapabilitiesMode::Direct => {
37-
new_transparent(cfg, kube_client, shutdown_channel).await
40+
new_transparent(cfg, kube_client, shutdown_channel_rx).await
3841
}
3942
}
4043
}
4144

42-
pub async fn loop_eval(&mut self) {
45+
pub fn sender_channel(&self) -> mpsc::Sender<CallbackRequest> {
4346
match self {
44-
CallbackHandler::Direct(direct) => direct.loop_eval().await,
45-
CallbackHandler::Proxy(proxy) => proxy.loop_eval().await,
47+
CallbackHandler::Direct(handler) => handler.sender_channel(),
48+
CallbackHandler::Proxy(handler) => handler.sender_channel(),
4649
}
4750
}
4851

49-
pub fn sender_channel(&self) -> mpsc::Sender<CallbackRequest> {
52+
pub async fn loop_eval(self) {
5053
match self {
51-
CallbackHandler::Direct(direct) => direct.sender_channel(),
52-
CallbackHandler::Proxy(proxy) => proxy.sender_channel(),
54+
CallbackHandler::Direct(mut handler) => handler.loop_eval().await,
55+
CallbackHandler::Proxy(mut handler) => handler.loop_eval().await,
5356
}
5457
}
5558
}
@@ -58,11 +61,11 @@ async fn new_proxy(
5861
mode: &ProxyMode,
5962
cfg: &PullAndRunSettings,
6063
kube_client: Option<kube::Client>,
61-
shutdown_channel: oneshot::Receiver<()>,
64+
shutdown_channel_rx: oneshot::Receiver<()>,
6265
) -> Result<CallbackHandler> {
6366
let proxy = CallbackHandlerProxy::new(
6467
mode,
65-
shutdown_channel,
68+
shutdown_channel_rx,
6669
cfg.sources.clone(),
6770
cfg.sigstore_trust_root.clone(),
6871
kube_client,
@@ -75,10 +78,10 @@ async fn new_proxy(
7578
async fn new_transparent(
7679
cfg: &PullAndRunSettings,
7780
kube_client: Option<kube::Client>,
78-
shutdown_channel: oneshot::Receiver<()>,
81+
shutdown_channel_rx: oneshot::Receiver<()>,
7982
) -> Result<CallbackHandler> {
8083
let mut callback_handler_builder =
81-
policy_evaluator::callback_handler::CallbackHandlerBuilder::new(shutdown_channel)
84+
policy_evaluator::callback_handler::CallbackHandlerBuilder::new(shutdown_channel_rx)
8285
.registry_config(cfg.sources.clone())
8386
.trust_root(cfg.sigstore_trust_root.clone());
8487
if let Some(kc) = kube_client {

0 commit comments

Comments
 (0)