Kubewarden 1.27 Release
Author:
Published:
Updated:
Here’s a look at the key updates and improvements in the latest release.
New High-Risk Service Account Policy
In this release, we’ve introduced a new policy to improve cluster security. The High-Risk Service Account Blocker policy, as its name suggests, blocks workloads that attempt to run with a service account that has excessive permissions.
This policy leverages the Kubernetes authorization API and allows cluster operators to define a list of forbidden permissions. Workloads using a service account with any of these permissions will be blocked. Check out the policy’s repository to learn more about its configuration.
In the following example, any workload using a service account with some of the
permissions defined in the blockRules
will be rejected:
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
annotations:
io.kubewarden.policy.category: Resource validation
io.kubewarden.policy.severity: medium
name: high-risk-service-account
spec:
module: registry://ghcr.io/kubewarden/policies/high-risk-service-account:latest
settings:
blockRules:
# For listing secrets
- apiGroups: [""]
resources: ["secrets"]
verbs: ["list"]
# namespace: "default"
# For executing commands in containers
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
# Full access to all workload resources
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["*"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
verbs: ["*"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["*"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["*"]
# Full access to RBAC resources within a namespace
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles", "rolebindings"]
verbs: ["*"]
namespace: "default"
rules:
- apiGroups:
- ""
apiVersions:
- v1
resources:
- pods
operations:
- CREATE
- apiGroups:
- ""
apiVersions:
- v1
resources:
- replicationcontrollers
operations:
- CREATE
- UPDATE
- apiGroups:
- apps
apiVersions:
- v1
resources:
- deployments
- replicasets
- statefulsets
- daemonsets
operations:
- CREATE
- UPDATE
- apiGroups:
- batch
apiVersions:
- v1
resources:
- jobs
- cronjobs
operations:
- CREATE
- UPDATE
mutating: false
After deploying the above policy, a workload resource using the following service account will be blocked:
---
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: super-admin-sa
namespace: default
---
# Powerful Role with all requested permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: super-admin-role
namespace: default
rules:
resources: ["secrets"]
verbs: ["list"]
---
# RoleBinding for namespace-scoped permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: super-admin-rolebinding
namespace: default
subjects:
- kind: ServiceAccount
name: super-admin-sa
namespace: default
roleRef:
kind: ClusterRole
name: super-admin-role
apiGroup: rbac.authorization.k8s.io
Let’s try to deploy something:
kubectl create -f - << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: super-admin-deployment
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: super-admin-app
template:
metadata:
labels:
app: super-admin-app
spec:
serviceAccountName: super-admin-sa
containers:
- name: main
image: nginx:alpine
ports:
- containerPort: 80
- name: kubectl
image: bitnami/kubectl:latest
command: ["sleep", "infinity"]
EOF
Error from server: error when creating "STDIN": admission webhook "clusterwide-high-risk-service-account.kubewarden.admission" denied the request: Cannot use service account 'system:serviceaccount:default:super-admin-sa' with permissions to perform list /secrets in the cluster
New kubernetes/can-i Host Capability
To make the High-Risk Service Account Blocker policy more efficient, this
release introduces a new host capability:
kubernetes/can_i
.
This capability uses the Kubernetes SubjectAccessReview
API to check if
a service account has permission to perform certain operations. This approach
avoids the need to fetch numerous RBAC resources to determine if the service
account can perform the blocked operations, making the check faster and
more reliable.
To support this new capability, the default ServiceAccount
used in the Helm
chart to run the Policy Server has been updated to add permission to
create SubjectAccessReview
resources. If you want to use this new capability
with a Policy Server that uses a different ServiceAccount
, you must update
its permissions accordingly.
kwctl Now Mirrors policy-server Behavior
The kwctl
CLI now performs post-policy processing validations and changes
that were previously executed only by the policy-server
. We’ve moved the logic
for features like custom error messages and mutation permissions from the
policy-server
codebase to a shared evaluation
library.
As a result, users running policies with kwctl
now see the same
behavior that the policy-server
produces. This is great for testing
policy configurations before deploying them to a cluster.
The post-policy steps also performed by kwctl
are:
- policy mode enforcement: when the policy is in monitor mode,
kwctl
returns the request as allowed, even if the request was rejected by the policy. It prints a warning message with the original result. - custom error message:
kwctl
will return the error message defined in themessage
field when the policy is rejected - reject mutated requests:
kwctl
will reject a request if the policy mutates the request but themutating
field is set tofalse
Let’s take a look at some examples. Let’s consider the following policy in monitor mode. Therefore, all the evaluations should be allowed. When the policy is run against a request with a privileged container, it returns the evaluation as “allowed”:
$ cat policy.yaml
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
annotations:
io.kubewarden.policy.category: PSP
io.kubewarden.policy.severity: medium
name: pod-privileged-policy
spec:
module: registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3
settings: {}
mode: "Monitor"
rules:
- apiGroups:
- ""
apiVersions:
- v1
resources:
- pods
operations:
- CREATE
mutating: false
$ kwctl run policy.yaml --request-path test_data/privileged_container.json
Successfully pulled policy from registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3
2025-07-24T20:36:31.253373Z INFO validate{self=PolicyEvaluator { runtime: "wapc" } settings=PolicySettings({})}:policy_log{self=EvaluationContext { policy_id: "registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3", callback_channel: Some(...), allowed_kubernetes_resources: {} }}: policy_log: starting validation data={"column":5,"file":"src/lib.rs","line":33,"policy":"sample-policy"}
2025-07-24T20:36:31.253476Z INFO policy_evaluator::admission_response_handler: policy evaluation (monitor mode) policy_id="pod-privileged-policy" allowed_to_mutate=false response="AdmissionResponse { uid: \"1299d386-525b-4032-98ae-1949f69f9cfc\", allowed: false, patch_type: None, patch: None, status: Some(AdmissionResponseStatus { status: None, message: Some(\"Privileged container is not allowed\"), reason: None, details: None, code: None }), audit_annotations: None, warnings: None }"
{"uid":"1299d386-525b-4032-98ae-1949f69f9cfc","allowed":true,"auditAnnotations":null,"warnings":null}
Now let’s change the policy to protect mode, add a custom error message and run against the same request:
$ cat policy.yaml
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
annotations:
io.kubewarden.policy.category: PSP
io.kubewarden.policy.severity: medium
name: pod-privileged-policy
spec:
module: registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3
settings: {}
mode: "Protect"
message: "Nops! You cannot do that!"
rules:
- apiGroups:
- ""
apiVersions:
- v1
resources:
- pods
operations:
- CREATE
mutating: false
$ kwctl run policy.yaml --request-path test_data/privileged_container.json
Successfully pulled policy from registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3
2025-07-24T20:39:56.765807Z INFO validate{self=PolicyEvaluator { runtime: "wapc" } settings=PolicySettings({})}:policy_log{self=EvaluationContext { policy_id: "registry://ghcr.io/kubewarden/policies/pod-privileged:v1.0.3", callback_channel: Some(...), allowed_kubernetes_resources: {} }}: policy_log: starting validation data={"column":5,"file":"src/lib.rs","line":33,"policy":"sample-policy"}
{"uid":"1299d386-525b-4032-98ae-1949f69f9cfc","allowed":false,"status":{"message":"Nops! You cannot do that!","details":{"causes":[{"reason":null,"message":"Privileged container is not allowed","field":null}]}},"auditAnnotations":null,"warnings":null}
GSoC Update: JavaScript SDK Enhancements
This month also saw great enhancements to our JavaScript SDK. A big thank you to Esosa, our GSoC mentee!
Esosa is focused on making the SDK stable and production-ready. He has introduced a significant number of new host capabilities and improved the codebase, paving the way for a public release. With that in mind, he is now working on an alpha release of the SDK to validate the full release process and test it with a template policy.
Policy Fixes
We recently received a
request from
the community to implement an additional validation in one of our Rego
policies. The Kustomization Target Namespace policy, which validates FluxCD
Kustomizations, now ensures that the optional spec.targetNamespace
field is
set to one of the allowed namespaces. Prior to this change, requests were
accepted even if this field was not set.
SBOM Generation Update and maintenance tasks
In this release, beyond the usual dependency updates and maintenance work, we’ve removed all references to the deprecated spdx-sbom-generator tool. All our GitHub Actions now use Syft to generate SBOM files. The generated files are slightly different due to the change in tooling, but users should not be concerned, the files are equivalent.
Getting in touch
Join the conversation on Slack or GitHub discussions and let us know how you’re using Kubewarden 1.27!