Repository: kubewarden/docs
Pull request #556: Cover mTLS
Author: login: flavio
Created: 2025-03-06T13:24:24Z | Merged: 2025-03-11T10:42:42Z

Each link below points to the new page from our live preview:

- [x] [add howto about mTLS and k3s](https://deploy-preview-556--docs-kubewarden-io.netlify.app/next/howtos/security-hardening/webhook-mtls)
- [x] [add reference documentation for the mTLS feature](https://deploy-preview-556--docs-kubewarden-io.netlify.app/next/reference/security-hardening/webhook-mtls)
- [x] [update ArgoCD docs](https://deploy-preview-556--docs-kubewarden-io.netlify.app/next/howtos/argocd-installation)
- [x] [update threat model](https://deploy-preview-556--docs-kubewarden-io.netlify.app/next/reference/threat-model)

Fixes https://github.com/kubewarden/docs/issues/540

Open questions for the reviewers:

- Is it worth to have a "Security" folder under "reference" and "howto" like I did? Should we just move the single document I wrote one level up?
- The reference doc: the name of the url and of the document mentions "mTLS", however this is much more, because we also have the optional network policies. Should we do a rename?



Diff:
diff --git a/docs/howtos/argocd-installation.md b/docs/howtos/argocd-installation.md
index 554233f9d22..222cdebac38 100644
--- a/docs/howtos/argocd-installation.md
+++ b/docs/howtos/argocd-installation.md
@@ -94,6 +94,12 @@ spec:
     namespace: kubewarden-system
     jsonPointers:
       - /data
+  - group: ""
+    kind: "Secret"
+    name: kubewarden-audit-scanner-client-cert
+    namespace: kubewarden-system
+    jsonPointers:
+      - /data
   - group: "admissionregistration.k8s.io"
     kind: "MutatingWebhookConfiguration"
     jqPathExpressions:
diff --git a/docs/howtos/security-hardening/_category_.json b/docs/howtos/security-hardening/_category_.json
new file mode 100644
index 00000000000..b2ea062b3a1
--- /dev/null
+++ b/docs/howtos/security-hardening/_category_.json
@@ -0,0 +1,5 @@
+{
+  "label": "Security",
+  "position": 100,
+  "collapsed": true
+}
diff --git a/docs/howtos/security-hardening/webhook-mtls.md b/docs/howtos/security-hardening/webhook-mtls.md
new file mode 100644
index 00000000000..c9b0b6ef001
--- /dev/null
+++ b/docs/howtos/security-hardening/webhook-mtls.md
@@ -0,0 +1,159 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide shows you how to enable mutual TLS (mTLS) for all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate to use to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, change directory to the `/etc/rancher/k3s/admission/certs` directory and
+create all needed certificates:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to complete.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA, that issued the Kubernetes client certificate, must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+has to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` in it. The following command, run on the Kubernetes node,
+does that:
+
+```console
+kubectl create configmap -n kubewarden api-server-mtls \
+    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt
+```
+
+The resulting `ConfigMap` is named `api-server-mtls`.
+
+### Install the Kubewarden stack
+
+Install the Kubewarden stack as described in the [quickstart guide](../../quick-start.md).
+Follow all the steps, but when installing the `kubewarden-controller` Helm chart, make sure to
+enable the following values:
+
+- `mTLS.enable`: must be set to `true`.
+- `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller`
+is:
+
+```console
+helm install --wait -n kubewarden kubewarden-controller kubewarden/kubewarden-controller \
+    --set mTLS.enable=true \
+    --set mTLS.configMapName=api-server-mtls
+```
+
+Once this command finishes, the Kubewarden stack is installed and its webhooks are secured with mTLS.
diff --git a/docs/reference/security-hardening/_category_.json b/docs/reference/security-hardening/_category_.json
new file mode 100644
index 00000000000..550acd130ba
--- /dev/null
+++ b/docs/reference/security-hardening/_category_.json
@@ -0,0 +1,5 @@
+{
+  "label": "Security",
+  "position": 70,
+  "collapsed": true
+}
diff --git a/docs/reference/security-hardening/webhook-mtls.md b/docs/reference/security-hardening/webhook-mtls.md
new file mode 100644
index 00000000000..7526ed1e1fd
--- /dev/null
+++ b/docs/reference/security-hardening/webhook-mtls.md
@@ -0,0 +1,244 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses various webhooks to enforce policies in a Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, you should limit access to these webhooks to the only valid callers they have: 
+
+- the Kubernetes API server
+- the [audit scanner](../../explanations/audit-scanner/) component.
+You can do this using network policies and authentication independently, or together, to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+Webhooks are only expected to accept requests from the Kubernetes API server and the audit scanner component. By default, however, webhooks can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/component in {"kubewarden-controller", "policy-server"}'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector: 'app.kubernetes.io/component in {"kubewarden-controller", "policy-server"}'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: 'kubernetes.io/metadata.name == "kubewarden"' # namespace where the kubewarden stack is deployed
+      destination:
+        selector: 'app.kubernetes.io/component in {"kubewarden-controller", "policy-server"}'
+```
+
+:::warning
+
+This network policy uses label selectors that have been introduced in Kubewarden 1.23.0. If you are using an older version,
+you must update the labels in the policy to match the ones used in your deployment.
+
+More specifically, the
+
+```yaml
+selector: 'app.kubernetes.io/component in {"kubewarden-controller", "policy-server"}'
+```
+
+selectors should be written as:
+
+
+```yaml
+selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+:::
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group to define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/component
+        operator: In
+        values:
+          - policy-server
+          - controller
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+:::warning
+
+This network policy uses label selectors that have been introduced in Kubewarden 1.23.0. If you are using an older version,
+you must update the labels in the policy to match the ones used in your deployment.
+
+More specifically, the
+
+```yaml
+matchExpressions:
+  - key: app.kubernetes.io/component
+    operator: In
+    values:
+      - policy-server
+      - controller
+```
+
+expression should be written as:
+
+
+```yaml
+endpointSelector:
+matchExpressions:
+  - key: app.kubernetes.io/name
+    operator: In
+    values:
+      - kubewarden-controller
+  - key: kubewarden/policy-server
+    operator: Exists
+```
+
+:::
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+See [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+configuring the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. They will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+See the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers) for more information.
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is the same configuration file used to configure other plugins, such as `PodSecurity`.
+    If your distribution or setup uses additional admission plugins, you should also configure those.
+
+2. Create the `kubeconfig` file the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
+    and set the kubeconfig to use either client-certificate and client-key or client-certificate-data and client-key-data.
+
+    For example:
+
+    ```yaml
+    # /etc/k8s/admission/kubeconfig
+    apiVersion: v1
+    kind: Config
+    users:
+    - name: '*.kubewarden.svc'
+      user:
+        client-certificate: /path/to/client/cert
+        client-key: /path/to/client/key
+    ```
+
+3. Start the `kube-apiserver` binary with the flag `--admission-control-config-file` pointing to your `AdmissionConfiguration` file.
+   The way to do this varies by distribution, and it isn't supported universally, such as in hosted Kubernetes providers.
+   Consult the documentation for your Kubernetes distribution.
+
+4. The certificate of the root CA that issued the API server client certificate must be made available to
+   the Kubewarden stack.
+
+   Its content has to be put into a `ConfigMap` under the `kubewarden` namespace using a key named `client-ca.crt`.
+
+   Assuming the root CA is available at `/etc/k8s/admission/certs/rootCA.crt`, create the `ConfigMap`
+   with the following command:
+
+    ```console
+    kubectl create configmap -n kubewarden api-server-mtls \
+        --from-file=client-ca.crt=/etc/k8s/admission/certs/rootCA.crt
+    ```
+
+5. Finally, when installing the `kubewarden-controller` Helm chart,
+   make sure to enable the following values:
+
+     - `mTLS.enable`: must be set to `true`.
+     - `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+    Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller` is:
+
+    ```console
+    helm install --wait -n kubewarden kubewarden-controller kubewarden/kubewarden-controller \
+        --set mTLS.enable=true \
+        --set mTLS.configMapName=api-server-mtls
+    ```
+
+    The Kubewarden controller creates a client certificate for use by the audit scanner component.
+    The certificate is automatically rotated, by the controller, when needed.
diff --git a/docs/reference/threat-model.md b/docs/reference/threat-model.md
index f28fc7f11d0..242310f5257 100644
--- a/docs/reference/threat-model.md
+++ b/docs/reference/threat-model.md
@@ -135,6 +135,8 @@ and admission controller webhook.
 
 Configure the cluster with mTLS authentication for the Webhooks and enable the mTLS feature in the
 Kubewarden stack. Alternatively, setup mTLS using a CNI that supports Network Policies.
+See [here](./security-hardening/webhook-mtls.md) for more information.
+
 Use the
 [capabilities-psp](https://artifacthub.io/packages/kubewarden/capabilities-psp/capabilities-psp)
 policy and configure it to drop NET_RAW capabilities.
@@ -150,6 +152,7 @@ for the admission controller webhook, by spoofing.
 
 Configure the cluster with mTLS authentication for the Webhooks and enable the mTLS feature in the
 Kubewarden stack. Alternatively, setup mTLS using a CNI that supports Network Policies.
+See [here](./security-hardening/webhook-mtls.md) for more information.
 
 ### Threat 10 - Abusing a mutation rule to create a privileged container
 


Reviews:
user: login: viccuad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T09:40:56Z
user: login: viccuad
body: LGTM. I think the security section is a good idea, but I would also move "how-tos/secure supply chain" there, and on the references, "references/threat model".

They would need to get one of those link preserving configs, too.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T09:45:03Z
user: login: viccuad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T09:49:05Z
user: login: jvanz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T12:21:20Z
user: login: jvanz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T12:23:12Z
user: login: flavio
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T12:28:19Z
user: login: flavio
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T12:43:25Z
user: login: fabriziosestito
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:37:33Z
user: login: fabriziosestito
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:39:43Z
user: login: jhkrug
body: Minor suggestions and an occasional typo. Thanks.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T18:03:31Z
user: login: flavio
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T16:15:05Z
user: login: jhkrug
body: lgtm
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T09:34:29Z
user: login: viccuad
body: LGTM
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-11T10:14:02Z

Review comments:
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc'
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: viccuad
body: ```suggestion
- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
```

Maybe too obvious?
created_at: 2025-03-07T09:40:55Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,188 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
path: docs/reference/security-hardening/webhook-mtls.md
user: login: viccuad
body: Should we update to the new labels already, with a `managed-by`?
created_at: 2025-03-07T09:49:05Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,188 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jvanz
body: Yeah, I agree. As we are about to merge the [PR](https://github.com/kubewarden/kubewarden-controller/pull/1037) adding the recommended policies, I think we can hold this PR until we merge that one. 
created_at: 2025-03-07T12:21:20Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,188 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jvanz
body: As this section is pretty similar to the on in the 'howto' page, shouldn't we mention that page in case the user want to see a full example on how to enable it?
created_at: 2025-03-07T12:23:03Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc'
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: flavio
body: I think that's a good point
created_at: 2025-03-07T12:28:19Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,188 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
path: docs/reference/security-hardening/webhook-mtls.md
user: login: flavio
body: Good point, I've added a `tip` section that contains a reference to the howto
created_at: 2025-03-07T12:43:25Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
path: docs/reference/security-hardening/webhook-mtls.md
user: login: fabriziosestito
body: ```suggestion
The Kubewarden stack uses utilizes various webhooks to enforce policies within the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
```
created_at: 2025-03-07T16:37:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: 
I would suggest

```suggestion
The Kubewarden stack uses various webhooks to enforce policies in a Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
```
created_at: 2025-03-07T17:32:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
To decrease their attack surface, you should limit access to these webhooks to the only valid callers they have: 

- the Kubernetes API server
- the [audit scanner](../../explanations/audit-scanner/) component.
```
created_at: 2025-03-07T17:39:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
You can do this using network policies and authentication independently, or together, to harden the webhooks against attacks.
```
created_at: 2025-03-07T17:40:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Webhooks are only expected to accept requests from the Kubernetes API server and the audit scanner component. By default, however, webhooks can accept traffic from any source.
```
created_at: 2025-03-07T17:42:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: Maybe?
```suggestion
Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group to define a network policy like the following one:
```
created_at: 2025-03-07T17:44:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
See [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
configuring the Kubernetes API server of k3s to authenticate to the webhook.
```
created_at: 2025-03-07T17:45:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
By default, these webhooks don't require clients to authenticate to it. They will accept any request.
```
created_at: 2025-03-07T17:46:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
See the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers) for more information.
```
created_at: 2025-03-07T17:46:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
    This is the same configuration file used to configure other plugins, such as `PodSecurity`.
```
created_at: 2025-03-07T17:48:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
    If your distribution or setup uses additional admission plugins, you should also configure those.
```
created_at: 2025-03-07T17:49:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
+
+2. Create the `kubeconfig` file that the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
2. Create the `kubeconfig` file the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
```
created_at: 2025-03-07T17:50:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
+
+2. Create the `kubeconfig` file that the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
+    and set the kubeconfig to use either client-certificate and client-key or client-certificate-data and client-key-data.
+
+    For example:
+
+    ```yaml
+    # /etc/k8s/admission/kubeconfig
+    apiVersion: v1
+    kind: Config
+    users:
+    - name: '*.kubewarden.svc'
+      user:
+        client-certificate: /path/to/client/cert
+        client-key: /path/to/client/key
+    ```
+
+3. Start the `kube-apiserver` binary with the flag `--admission-control-config-file` pointing to your `AdmissionConfiguration` file.
+   The way to do this varies by distro, and it isn't supported universally, such as in hosted Kubernetes providers.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
   The way to do this varies by distribution, and it isn't supported universally, such as in hosted Kubernetes providers.
```
created_at: 2025-03-07T17:51:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
+
+2. Create the `kubeconfig` file that the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
+    and set the kubeconfig to use either client-certificate and client-key or client-certificate-data and client-key-data.
+
+    For example:
+
+    ```yaml
+    # /etc/k8s/admission/kubeconfig
+    apiVersion: v1
+    kind: Config
+    users:
+    - name: '*.kubewarden.svc'
+      user:
+        client-certificate: /path/to/client/cert
+        client-key: /path/to/client/key
+    ```
+
+3. Start the `kube-apiserver` binary with the flag `--admission-control-config-file` pointing to your `AdmissionConfiguration` file.
+   The way to do this varies by distro, and it isn't supported universally, such as in hosted Kubernetes providers.
+   Consult the documentation for your Kubernetes distribution.
+
+4. The certificate of the root CA that issued the API server client certificate must be made available to
+   the Kubewarden stack.
+
+   Its content have to be put into a `ConfigMap` under the `kubewarden` namespace using a key named `client-ca.crt`.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
   Its content has to be put into a `ConfigMap` under the `kubewarden` namespace using a key named `client-ca.crt`.
```
created_at: 2025-03-07T17:51:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
+
+2. Create the `kubeconfig` file that the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
+    and set the kubeconfig to use either client-certificate and client-key or client-certificate-data and client-key-data.
+
+    For example:
+
+    ```yaml
+    # /etc/k8s/admission/kubeconfig
+    apiVersion: v1
+    kind: Config
+    users:
+    - name: '*.kubewarden.svc'
+      user:
+        client-certificate: /path/to/client/cert
+        client-key: /path/to/client/key
+    ```
+
+3. Start the `kube-apiserver` binary with the flag `--admission-control-config-file` pointing to your `AdmissionConfiguration` file.
+   The way to do this varies by distro, and it isn't supported universally, such as in hosted Kubernetes providers.
+   Consult the documentation for your Kubernetes distribution.
+
+4. The certificate of the root CA that issued the API server client certificate must be made available to
+   the Kubewarden stack.
+
+   Its content have to be put into a `ConfigMap` under the `kubewarden` namespace using a key named `client-ca.crt`.
+
+   Assuming the root CA is available at `/etc/k8s/admission/certs/rootCA.crt`, create the `ConfigMap`
+   with the following command:
+
+    ```console
+    kubectl create configmap -n kubewarden api-server-mtls \
+        --from-file=client-ca.crt=/etc/k8s/admission/certs/rootCA.crt
+    ```
+
+5. Finally, when installing the `kubewarden-controller` Helm chart,
+   make sure to enable the following values:
+
+     - `mTLS.enable`: must be set to `true`.
+     - `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+    Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller`
+    will be:
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
    Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller` is:
```
created_at: 2025-03-07T17:52:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,195 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+  types:
+    - Ingress
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        nets:
+        # CIDR of the control plane host. May list more than 1 if the hosts are in different subnets.
+        - 192.168.42.0/24
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - action: Allow
+      protocol: TCP
+      source:
+        # namespace where the kubewarden stack is deployed
+        namespaceSelector: kubewarden
+      destination:
+        selector:
+          'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
+```
+
+### Cilium
+
+Use the CiliumNetworkPolicy resource in the `cilium.io/v2` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: "cilium.io/v2"
+kind: CiliumNetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  endpointSelector:
+    matchExpressions:
+      - key: app.kubernetes.io/name
+        operator: In
+        values:
+          - kubewarden-controller
+      - key: kubewarden/policy-server
+        operator: Exists
+  ingress:
+    # this allows the Kubernetes API server to reach the kubewarden controller and
+    # all the policy server instances
+    - fromEntities:
+      - host
+      - remote-node
+    # this allows all the workloads defined inside of the kubewarden namespace
+    # (including audit-scanner) to reach the kubewarden controller and all the
+    # policy server instances
+    - fromEndpoints:
+        - matchLabels:
+            # namespace where the kubewarden stack is deployed
+            k8s:io.kubernetes.pod.namespace: kubewarden
+```
+
+## Require the Kubernetes API Server to Authenticate to the Webhook
+
+:::tip
+
+Checkout [this how-to](../../howtos/security-hardening/webhook-mtls/) for a step-by-step guide on
+how to configure the Kubernetes API server of k3s to authenticate to the webhook.
+
+:::
+
+The webhooks exposed by the Kubewarden stack should only accept requests from the Kubernetes API server or
+from the audit scanner component.
+By default, these webhooks don't require clients to authenticate to it. Theny will accept any request.
+
+You can configure the webhooks to require credentials so that only the API server and the audit scanner processes
+can access them.
+More information can be found in the [Kubernetes documentation](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
+
+1. Configure the API server to present a client certificate to the webhook, pointing to an `AdmissionConfiguration`
+    file to configure the `ValidatingAdmissionWebhook` and `MutatingAdmissionWebhook` plugins:
+
+    Create a file named `admission.yaml` with the following contents:
+
+    ```yaml
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: AdmissionConfiguration
+    plugins:
+    - name: ValidatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    - name: MutatingAdmissionWebhook
+      configuration:
+        apiVersion: apiserver.config.k8s.io/v1
+        kind: WebhookAdmissionConfiguration
+        kubeConfigFile: "/etc/k8s/admission/kubeconfig"
+    ```
+
+    This is also the same config file where other admission plugins are configured, such as `PodSecurity`.
+    If your distro or your setup uses additional admission plugins, configure those as well.
+
+2. Create the `kubeconfig` file that the admission plugins refer to. Kubewarden only supports client certificate authentication, so generate a TLS key pair,
+    and set the kubeconfig to use either client-certificate and client-key or client-certificate-data and client-key-data.
+
+    For example:
+
+    ```yaml
+    # /etc/k8s/admission/kubeconfig
+    apiVersion: v1
+    kind: Config
+    users:
+    - name: '*.kubewarden.svc'
+      user:
+        client-certificate: /path/to/client/cert
+        client-key: /path/to/client/key
+    ```
+
+3. Start the `kube-apiserver` binary with the flag `--admission-control-config-file` pointing to your `AdmissionConfiguration` file.
+   The way to do this varies by distro, and it isn't supported universally, such as in hosted Kubernetes providers.
+   Consult the documentation for your Kubernetes distribution.
+
+4. The certificate of the root CA that issued the API server client certificate must be made available to
+   the Kubewarden stack.
+
+   Its content have to be put into a `ConfigMap` under the `kubewarden` namespace using a key named `client-ca.crt`.
+
+   Assuming the root CA is available at `/etc/k8s/admission/certs/rootCA.crt`, create the `ConfigMap`
+   with the following command:
+
+    ```console
+    kubectl create configmap -n kubewarden api-server-mtls \
+        --from-file=client-ca.crt=/etc/k8s/admission/certs/rootCA.crt
+    ```
+
+5. Finally, when installing the `kubewarden-controller` Helm chart,
+   make sure to enable the following values:
+
+     - `mTLS.enable`: must be set to `true`.
+     - `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+    Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller`
+    will be:
+
+    ```console
+    helm install --wait -n kubewarden kubewarden-controller kubewarden/kubewarden-controller \
+        --set mTLS.enable=true \
+        --set mTLS.configMapName=api-server-mtls
+    ```
+
+    The Kubewarden controller will create a client certificate to be used by the audit scanner component.
+    The certificate will be automatically rotated by the controller when needed.
path: docs/reference/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
    The Kubewarden controller creates a client certificate for use by the audit scanner component.
    The certificate is automatically rotated, by the controller, when needed.
```
created_at: 2025-03-07T17:54:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
This guide shows you how to enable mutual TLS (mTLS) for all the webhooks used by the Kubewarden
```
created_at: 2025-03-07T17:55:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Before installing k3s, you need to create a certificate authority (CA) and a client certificate to use to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
```
created_at: 2025-03-07T17:56:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
As `root` user, change directory to the `/etc/rancher/k3s/admission/certs` directory and
```
created_at: 2025-03-07T17:57:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
create all needed certificates:
```
created_at: 2025-03-07T17:57:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Wait for the installation to complete.
```
created_at: 2025-03-07T17:58:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
The certificate of the root CA, that issued the Kubernetes client certificate, must be made available to
the Kubewarden stack.
```
created_at: 2025-03-07T17:58:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
has to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
must be stored in a key named `client-ca.crt`.
```
created_at: 2025-03-07T17:59:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` inside of it. The following command, run on the Kubernetes node,
+will take care of that:
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Then create the `ConfigMap` in it. The following command, run on the Kubernetes node,
does that:
```
created_at: 2025-03-07T18:00:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` inside of it. The following command, run on the Kubernetes node,
+will take care of that:
+
+```console
+kubectl create configmap -n kubewarden api-server-mtls \
+    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt
+```
+
+The resulting `ConfigMap` will be named `api-server-mtls`.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
The resulting `ConfigMap` is named `api-server-mtls`.
```
created_at: 2025-03-07T18:00:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` inside of it. The following command, run on the Kubernetes node,
+will take care of that:
+
+```console
+kubectl create configmap -n kubewarden api-server-mtls \
+    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt
+```
+
+The resulting `ConfigMap` will be named `api-server-mtls`.
+
+### Install the Kubewarden stack
+
+Install the Kubewarden stack as reported in the [quickstart guide](../../quick-start.md).
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Install the Kubewarden stack as described in the [quickstart guide](../../quick-start.md).
```
created_at: 2025-03-07T18:00:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` inside of it. The following command, run on the Kubernetes node,
+will take care of that:
+
+```console
+kubectl create configmap -n kubewarden api-server-mtls \
+    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt
+```
+
+The resulting `ConfigMap` will be named `api-server-mtls`.
+
+### Install the Kubewarden stack
+
+Install the Kubewarden stack as reported in the [quickstart guide](../../quick-start.md).
+Follow all the steps, but when installing the `kubewarden-controller` Helm chart, make sure to
+enable the following values:
+
+- `mTLS.enable`: must be set to `true`.
+- `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller`
+will be:
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
is:
```
created_at: 2025-03-07T18:01:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+---
+sidebar_label: Enable mTLS with k3s
+title: Secure webhooks with mutual TLS with k3s
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [howto]
+doc-topic: [operator-manual, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/howtos/security-hardening/webhook-mtls"/>
+</head>
+
+This guide will show you how to enable mutual TLS (mTLS) for the all the webhooks used by the Kubewarden
+stack when using [k3s](https://k3s.io/) as your Kubernetes distribution.
+
+## Prerequisites
+
+Before installing k3s, you need to create a certificate authority (CA) and a client certificate that
+will be used to secure the communication between the Kubewarden webhooks and the Kubernetes API server.
+
+As a first step, create the `/etc/rancher/k3s/admission/certs` directory:
+
+```console
+sudo mkdir -p /etc/rancher/k3s/admission/certs
+```
+
+### Create a root CA and the client certificate
+
+As `root` user, move into the `/etc/rancher/k3s/admission/certs` directory and
+create all the certificates needed:
+
+```console
+export FQDN=mtls.kubewarden.io
+
+# Create CA
+openssl req -nodes -batch -x509 -sha256 -days 365 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
+
+# Create CSR
+openssl req -nodes -batch -newkey rsa:2048 -keyout client.key -out client.csr \
+    -addext "subjectAltName = DNS:$FQDN"
+
+# Create CRT
+openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 365 -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:$FQDN")
+
+# Print CRT
+openssl x509 -text -noout -in client.crt
+```
+
+The following files should have been created:
+
+- `client.crt`
+- `client.csr`
+- `client.key`
+- `rootCA.crt`
+- `rootCA.key`
+- `rootCA.srl`
+
+### Create the Kubernetes configuration file
+
+Create the `/etc/rancher/admission/admission.yaml` file with the following content:
+
+```yaml
+# /etc/rancher/admission/admission.yaml
+apiVersion: apiserver.config.k8s.io/v1
+kind: AdmissionConfiguration
+plugins:
+- name: ValidatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+- name: MutatingAdmissionWebhook
+  configuration:
+    apiVersion: apiserver.config.k8s.io/v1
+    kind: WebhookAdmissionConfiguration
+    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
+```
+
+Finally, create a `kubeconfig` file at `/etc/rancher/k3s/admission/kubeconfig`:
+
+```yaml
+# /etc/rancher/admission/kubeconfig
+apiVersion: v1
+kind: Config
+users:
+- name: '*.kubewarden.svc' # namespace where the kubewarden stack is deployed
+  user:
+    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
+    client-key: /etc/rancher/k3s/admission/certs/client.key
+```
+
+### Create a k3s configuration file
+
+Create a k3s configuration file at `/etc/rancher/k3s/config.yaml`:
+
+```yaml
+# /etc/rancher/k3s/config.yaml
+kube-apiserver-arg:
+- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml
+```
+
+## Install k3s
+
+Install k3s using the following command:
+
+```console
+curl -sfL https://get.k3s.io | sh -
+```
+
+Wait for the installation to be completed.
+
+## Install the Kubewarden stack
+
+### Prerequisites
+
+The certificate of the root CA that issued the Kubernetes client certificate must be made available to
+the Kubewarden stack.
+
+The root CA is available at `/etc/rancher/k3s/admission/certs/rootCA.crt` on the Kubernetes node. Its content
+have to be put into a `ConfigMap` under the `kubewarden` namespace. The contents of the `rootCA.crt` file
+must be stored in a key named `client-ca.crt`.
+
+First, create the `kubewarden` namespace:
+
+```console
+kubectl create namespace kubewarden
+```
+
+Then create the `ConfigMap` inside of it. The following command, run on the Kubernetes node,
+will take care of that:
+
+```console
+kubectl create configmap -n kubewarden api-server-mtls \
+    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt
+```
+
+The resulting `ConfigMap` will be named `api-server-mtls`.
+
+### Install the Kubewarden stack
+
+Install the Kubewarden stack as reported in the [quickstart guide](../../quick-start.md).
+Follow all the steps, but when installing the `kubewarden-controller` Helm chart, make sure to
+enable the following values:
+
+- `mTLS.enable`: must be set to `true`.
+- `mTLS.configMapName`: must be set to name of the `ConfigMap` that was previously created.
+
+Given the `ConfigMap` was named `api-server-mtls`, the Helm command to install the `kubewarden-controller`
+will be:
+
+```console
+helm install --wait -n kubewarden kubewarden-controller kubewarden/kubewarden-controller \
+    --set mTLS.enable=true \
+    --set mTLS.configMapName=api-server-mtls
+```
+
+Once this command completes, the Kubewarden stack will be installed and all its webhooks will be secured with mTLS.
path: docs/howtos/security-hardening/webhook-mtls.md
user: login: jhkrug
body: ```suggestion
Once this command finishes, the Kubewarden stack is installed and its webhooks are secured with mTLS.
```
created_at: 2025-03-07T18:02:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,188 @@
+---
+sidebar_label: Webhook Mutual TLS
+title: Secure webhooks with mutual TLS
+description: Harden the webhook configuration.
+keywords: [kubewarden, kubernetes, security]
+doc-persona: [kubewarden-operator, kubewarden-integrator]
+doc-type: [reference]
+doc-topic: [reference, security]
+---
+
+<head>
+  <link rel="canonical" href="https://docs.kubewarden.io/reference/security-hardening/webhook-mtls"/>
+</head>
+
+The Kubewarden stack uses different webhooks to enforce policies on the Kubernetes cluster. Each `PolicyServer` instance exposes a webhook
+that the Kubernetes API server calls to validate and mutate resources. Moreover, the `kubewarden-controller` exposes webhooks to validate and mutate
+the custom resources provided by the Kubewarden project.
+
+To decrease their attack surface, access to these webhooks should be limited to the only valid callers they have: the Kubernetes API server
+and the [audit scanner](../../explanations/audit-scanner/) component.
+This can be done by using network policies and authentication independently or in conjunction with each other to harden the webhooks against attacks.
+
+## Block External Traffic Using Network Policies
+
+The webhooks are only expected to accept requests from the Kubernetes API server and from the audit scanner component. By default, however, the webhooks
+can accept traffic from any source.
+If you are using a CNI that supports Network Policies, you can create a policy that blocks traffic that doesn't originate from the API server.
+
+The built-in NetworkPolicy resource in Kubernetes can't block or admit traffic from the cluster hosts, and the `kube-apiserver` process is always running on the host network.
+Therefore, you must use the advanced network policy resources from the CNI in use. Examples for Calico and Cilium follow. Consult the documentation for your CNI for more details.
+
+### Calico
+
+Use the NetworkPolicy resource in the `crd.projectcalico.org/v1` API group, define a network policy like the following one:
+
+```yaml
+apiVersion: crd.projectcalico.org/v1
+kind: NetworkPolicy
+metadata:
+  name: allow-k8s-and-audit-scanner
+  namespace: kubewarden # namespace where the kubewarden stack is deployed
+spec:
+  selector: 'app.kubernetes.io/name == "kubewarden-controller" || has(kubewarden/policy-server)'
path: docs/reference/security-hardening/webhook-mtls.md
user: login: flavio
body: done with https://github.com/kubewarden/docs/pull/556/commits/eaf1347265c63c3cdff7a31e48d8e1c4c2152252
created_at: 2025-03-10T16:15:05Z
author_association: MEMBER

PR comments:
user: login: netlify[bot]
created_at: 2025-03-06T13:24:42Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *docs-kubewarden-io* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 0a8bcfb6b6f59f4b7ddc67063285a11f7ba839db |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/docs-kubewarden-io/deploys/67d01399a8faca00087bd7d0 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-556--docs-kubewarden-io.netlify.app](https://deploy-preview-556--docs-kubewarden-io.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTU1Ni0tZG9jcy1rdWJld2FyZGVuLWlvLm5ldGxpZnkuYXBwIn0.7QC5hSbuIssipDIJXq-vwJERIvcsVzG7xh-bVhg1YiI)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [docs-kubewarden-io Preview](https://deploy-preview-556--docs-kubewarden-io.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/docs-kubewarden-io/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: jvanz
created_at: 2025-03-07T12:23:38Z
body: > LGTM. I think the security section is a good idea, but I would also move "how-tos/secure supply chain" there, and on the references, "references/threat model".

+1 
author_association: MEMBER
user: login: flavio
created_at: 2025-03-07T12:27:58Z
body: I'm fine moving more docs under the "security" folder, however I want to hear @jhkrug's opinion on the matter.
Moreover, if we were to do that, I would use a dedicated PR for that.
author_association: MEMBER
user: login: jhkrug
created_at: 2025-03-07T17:31:06Z
body: > I'm fine moving more docs under the "security" folder, however I want to hear @jhkrug's opinion on the matter. Moreover, if we were to do that, I would use a dedicated PR for that.

It makes sense to me.
author_association: CONTRIBUTOR
user: login: flavio
created_at: 2025-03-10T16:15:32Z
body: I've update the howto to make use of the new labels, see https://github.com/kubewarden/docs/pull/556/commits/eaf1347265c63c3cdff7a31e48d8e1c4c2152252

Once everybody is fine with the changes I'll squash everything into a single commit
author_association: MEMBER