From SUSE Security Admission Controller 1.36 to 1.37

This page describes how to migrate an existing SUSE Security Admission Controller installation based on the suse-security-admission-controller version 0.8.0 Helm chart to the suse-security-admission-controller version 1.0.0 chart, both published in the SUSE Application Collection.

The version 0.8.0 chart is an umbrella chart that embeds three Kubewarden subcharts (kubewarden-crds, kubewarden-controller, and kubewarden-defaults) as Helm dependencies. Version 1.0.0 replaces this structure with a single flat chart that contains all Admission Controller components directly, removing the subchart nesting.

As described in the upgrade path documentation, version jumping is not allowed. You must migrate from SUSE Security Admission Controller chart version 0.8.0 (appVersion 1.36.0) to version 1.0.0 (appVersion 1.37.0).

Unlike the migration from the community three-chart setup, this is an AppCo-to-AppCo migration. The image registry (dp.apps.rancher.io), the registry key (global.imageRegistry), and the pull secrets key (global.imagePullSecrets) all remain the same. The main work is flattening your values file by removing the subchart key prefixes.

This migration involves a short window, between uninstalling the old chart and the new chart becoming ready, when policies do not protect your cluster. You can use the Audit Scanner after the migration completes to identify any resources that may have entered the cluster without being evaluated during that window.

What changes in this migration

Aspect Old chart (v0.8.0) New chart (v1.0.0)

Chart version

0.8.0 (appVersion 1.36.0)

1.0.0 (appVersion 1.37.0)

Internal structure

Umbrella chart with three subcharts: kubewarden-crds, kubewarden-controller, kubewarden-defaults

All Kubewarden components in one flat chart; no Kubewarden subcharts

Helm releases

One release managing three subcharts

One release, one flat chart

Values shape

Subchart keys required: kubewarden-controller., kubewarden-defaults., kubewarden-crds.*

All keys at top level; subchart key prefixes removed

Image registry

dp.apps.rancher.io

dp.apps.rancher.io (unchanged)

Registry key

global.imageRegistry

global.imageRegistry (unchanged)

Pull secrets key

global.imagePullSecrets

global.imagePullSecrets (unchanged)

Policy module registry

ghcr.io (via recommendedPolicies.defaultPoliciesRegistry)

ghcr.io (unchanged)

CRD ownership

kubewarden-crds subchart, with no helm.sh/resource-policy: keep annotation

Flat chart CRDs annotated with helm.sh/resource-policy: keep

Because this is an AppCo-to-AppCo migration, you do not need to change global.imageRegistry, global.imagePullSecrets, or your Application Collection registry credentials. Those values carry over unchanged. The only structural change is removing the subchart key prefixes from your values.

The kubewarden-crds subchart embedded in the v0.8.0 chart does not annotate its CRDs with helm.sh/resource-policy: keep. Uninstalling the v0.8.0 chart deletes the five policy CRDs (policyservers.policies.kubewarden.io, clusteradmissionpolicies.policies.kubewarden.io, admissionpolicies.policies.kubewarden.io, clusteradmissionpolicygroups.policies.kubewarden.io, admissionpolicygroups.policies.kubewarden.io), which cascade-deletes every custom resource of those types from the cluster.

The kubewarden-controller subchart also runs a pre-delete hook on uninstall that deletes all PolicyServer resources before the controller itself is removed.

Nothing policy-related survives the uninstall. The backup taken in Step 1 is the only copy of your policies and policy server definitions. Step 6 restores them after the new chart is running.

Prerequisites

  • Helm v3 or later.

  • kubectl with access to your cluster.

  • yq v4 (github.com/mikefarah/yq) for filtering backed-up resources and transforming your values file.

  • The SUSE Security Admission Controller chart installed at chart version 0.8.0 (appVersion 1.36.0).

  • Valid credentials for dp.apps.rancher.io (already configured from your existing installation).

  • The SUSE Security Admission Controller chart version 1.0.0 available at oci://dp.apps.rancher.io/charts/suse-security-admission-controller.

Migration steps

Set shell variables used throughout the following steps. Replace the placeholders with values matching your installation:

NAMESPACE=<your-namespace>

$NAMESPACE is the namespace where the SUSE Security Admission Controller chart is installed.

Step 1: Back up your policies and policy servers

Back up all your PolicyServer instances and policy custom resources. The backup is the only copy — the uninstall in Step 3 deletes everything (see that step’s warning).

Resources managed by the v0.8.0 chart’s kubewarden-defaults subchart — the default PolicyServer and the recommended ClusterAdmissionPolicies — are excluded from the backup using a label selector. The v1.0.0 chart recreates them on install (via its kubewarden-defaults ConfigMap) when policyServer.enabled or recommendedPolicies.enabled is set, so restoring the backed-up copies would collide with the chart-managed ones that already exist.

The selector uses the chart-name label (app.kubernetes.io/name=kubewarden-defaults), which identifies subchart-managed resources. In the 0.8.0 umbrella the app.kubernetes.io/instance label carries the umbrella release name, not kubewarden-defaults, so the filter keys on the name label only.

FILTER='del(.items[].metadata.uid, .items[].metadata.resourceVersion, .items[].metadata.creationTimestamp, .items[].metadata.generation, .items[].metadata.managedFields, .items[].status)'

kubectl get clusteradmissionpolicies -l app.kubernetes.io/name!=kubewarden-defaults -A -o yaml | yq "$FILTER" > clusteradmissionpolicies-backup.yaml
kubectl get admissionpolicies -A -o yaml | yq "$FILTER" > admissionpolicies-backup.yaml
kubectl get clusteradmissionpolicygroups -A -o yaml | yq "$FILTER" > clusteradmissionpolicygroups-backup.yaml
kubectl get admissionpolicygroups -A -o yaml | yq "$FILTER" > admissionpolicygroups-backup.yaml
kubectl get policyservers -l app.kubernetes.io/name!=kubewarden-defaults -A -o yaml | yq "$FILTER" > policyservers-backup.yaml

Step 2: Capture your existing values

Save your current user-supplied values from the existing release for reference. You will transform this file in Step 4.

helm get values suse-security-admission-controller \
  -n "$NAMESPACE" \
  -o yaml > old-values.yaml

Step 3: Uninstall the old chart

Uninstall the v0.8.0 chart. Because there is a single Helm release, only one command is needed:

helm uninstall suse-security-admission-controller -n "$NAMESPACE"

As noted in What changes in this migration, uninstalling the v0.8.0 chart deletes the five policy CRDs and cascade-deletes every policy custom resource. The kubewarden-controller subchart pre-delete hook also deletes all PolicyServer resources before the controller pod is removed.

Nothing policy-related survives the uninstall. The backup taken in Step 1 is the only copy.

Step 4: Flatten your values file

The central change between v0.8.0 and v1.0.0 is that subchart key prefixes are removed. Every key previously nested under kubewarden-controller, kubewarden-defaults, or kubewarden-crds is now at the top level.

Use the following yq command to promote all subchart keys automatically:

yq eval '
  . * (.["kubewarden-controller"] // {}) |
  . * (.["kubewarden-defaults"] // {}) |
  . * (.["kubewarden-crds"] // {}) |
  del(.["kubewarden-controller"]) |
  del(.["kubewarden-defaults"]) |
  del(.["kubewarden-crds"])
' old-values.yaml > new-values.yaml

The transformation converts a v0.8.0 values file like this:

global:
  imagePullSecrets:
    - application-collection
kubewarden-controller:
  auditScanner:
    policyReporter: true
  policy-reporter:
    ui:
      service:
        type: NodePort
kubewarden-defaults:
  recommendedPolicies:
    enabled: true

Into the flat v1.0.0 form:

global:
  imagePullSecrets:
    - application-collection
auditScanner:
  policyReporter: true
policy-reporter:
  ui:
    service:
      type: NodePort
recommendedPolicies:
  enabled: true

Then strip policyServer.imagePullSecret if it flattened to null. The v0.8.0 kubewarden-defaults subchart defaults that key to null, so if you seeded your override file from the chart’s default values.yaml, the flatten promotes it rather than dropping it. The v1.0.0 chart expects the key to be absent or set to "":

yq eval 'del(select(.policyServer.imagePullSecret == null) | .policyServer.imagePullSecret)' \
  -i new-values.yaml

This command is a no-op if policyServer.imagePullSecret is absent or holds a real value, so it is safe to run regardless.

After running the yq commands, review new-values.yaml manually before proceeding. Pay attention to:

  • policyServer.imagePullSecret: the v0.8.0 subchart defaults this to null. If your override file was seeded from the chart’s default values.yaml, that null ends up in new-values.yaml after flattening. The cleanup command above strips it. If you set the key to a real secret name, the command leaves it alone.

  • kubewarden-controller.fullnameOverride: if you had set kubewarden-controller.fullnameOverride: suse-security-admission-controller, the yq command promotes it to fullnameOverride at the top level. Verify this is what you intend.

See Mapping your values to the new chart for the complete key mapping reference.

Step 5: Install the new chart

Install the v1.0.0 chart using the flattened values file produced in Step 4. The chart ships its own CRDs and installs them directly, so no ownership adoption is needed.

helm install suse-security-admission-controller \
  oci://dp.apps.rancher.io/charts/suse-security-admission-controller \
  --version 1.0.0 \
  -n "$NAMESPACE" \
  --values new-values.yaml \
  --wait

Step 6: Restore your policies and policy servers

The --wait flag in Step 5 only blocks until the Helm-managed workloads are ready, like the controller Deployment. It does not wait for the default PolicyServer, because the controller (not Helm) creates that from the kubewarden-defaults ConfigMap once the install finishes. It appears a moment after helm install returns. The PolicyServers you restore below are handled the same way: the controller reconciles each one and starts its Deployment and webhook. So don’t be surprised if a policy shows pending right after you apply the backup. It moves to active on its own once the controller finishes reconciling.

Update the PolicyServer images in your backup file before applying. The backed-up PolicyServers carry a spec.image field pinned to the v0.8.0 policy-server image. Update it to the v1.0.0 image:

yq eval '.items[].spec.image = "dp.apps.rancher.io/containers//kubewarden-policy-server:1.37.0"' \
  -i policyservers-backup.yaml

Now restore the backed-up resources. Use kubectl create rather than kubectl apply: the default PolicyServer and recommended ClusterAdmissionPolicies were excluded from the backup in Step 1 and are already present in the cluster (recreated by the new chart). kubectl create makes the intent explicit — these are new user resources, not updates to existing ones.

kubectl create -f policyservers-backup.yaml
kubectl create -f clusteradmissionpolicies-backup.yaml
kubectl create -f admissionpolicies-backup.yaml
kubectl create -f clusteradmissionpolicygroups-backup.yaml
kubectl create -f admissionpolicygroups-backup.yaml

Step 7: Verify the migration

Check that the CRDs are now owned by the new release and the controller is running:

# CRDs owned by the new release
kubectl get crd policyservers.policies.kubewarden.io \
  -o jsonpath='{.metadata.annotations.meta\.helm\.sh/release-name}'

# Controller running
kubectl get deployment -n $NAMESPACE \
  -l app.kubernetes.io/component=controller

Confirm that every backed-up resource is present in the cluster by comparing counts from the backup files against live cluster state. The expected and actual counts must match for each type:

for kind in policyservers clusteradmissionpolicies admissionpolicies \
            clusteradmissionpolicygroups admissionpolicygroups; do
  expected=$(yq '.items | length' "${kind}-backup.yaml")
  actual=$(kubectl get "$kind" -A --no-headers 2>/dev/null | wc -l)
  echo "$kind: expected=$expected actual=$actual"
done

If any count does not match, apply the corresponding backup file and check the controller logs for errors.

Check that all policies have reached active status. The controller reconciles them automatically:

kubectl get clusteradmissionpolicies
kubectl get admissionpolicies -A
kubectl get clusteradmissionpolicygroups
kubectl get admissionpolicygroups -A

Confirm that every PolicyServer is using the SUSE Security Admission Controller policy-server image. Every IMAGE value must start with dp.apps.rancher.io:

kubectl get policyservers \
  -o custom-columns=NAME:.metadata.name,IMAGE:.spec.image

Mapping your values to the new chart

The v1.0.0 chart uses a flat values.yaml that consolidates what the three subcharts configured through nested keys. The rule is straightforward: strip the subchart prefix. The key names themselves do not change.

global.* keys pass through unchanged, they already sit at the top level in both charts.

For everything else, drop the subchart parent key and keep the rest of the key path exactly as it was:

kubewarden-crds.<key>        ->  <key>
kubewarden-controller.<key>  ->  <key>
kubewarden-defaults.<key>    ->  <key>

For example, kubewarden-controller.auditScanner.policyReporter becomes auditScanner.policyReporter, and kubewarden-defaults.recommendedPolicies.enabled becomes recommendedPolicies.enabled. This is exactly what the yq command in Step 4 does automatically. policy-reporter stays a subchart in v1.0.0, so kubewarden-controller.policy-reporter. becomes policy-reporter..

A few keys need attention beyond stripping the prefix:

Key (after stripping the prefix) Note

fullnameOverride

Promoted from kubewarden-controller.fullnameOverride. Verify the value still matches your deployment; it controls the name prefix of controller resources.

policyServer.imagePullSecret

The v0.8.0 kubewarden-defaults subchart defaults this to null. The Step 4 cleanup command removes it if it flattened to null.

additionalLabels, additionalAnnotations

Set in both kubewarden-controller and kubewarden-defaults. The Step 4 merge applies them left-to-right, so kubewarden-defaults values win. Review the merged output and set the final value explicitly if needed.

Caveats

CRDs are recreated by the new chart

The kubewarden-crds subchart embedded in v0.8.0 does not annotate its CRDs with helm.sh/resource-policy: keep, so helm uninstall in Step 3 deletes them. The v1.0.0 chart ships its own copies of the five policy CRDs and installs them as part of a fresh install. No ownership adoption is required.

The v1.0.0 chart does annotate its CRDs with helm.sh/resource-policy: keep, so a future uninstall of the v1.0.0 chart will leave the CRDs in place to protect any policies still running in the cluster.

fullnameOverride after flattening

The v0.8.0 values.local.yaml example sets kubewarden-controller.fullnameOverride: suse-security-admission-controller. After flattening, this becomes top-level fullnameOverride. Verify that the promoted value matches what you need for your deployment; it controls the name prefix of controller resources such as the deployment and services.

Policy enforcement gap

Between Step 3 (uninstall the old chart) and Step 5 (the new chart becoming ready), no admission controller is running. The webhook configurations created by the old chart are deleted when the controller subchart is uninstalled, so no admission evaluation takes place during this window.

After the migration completes, run the Audit Scanner to identify any non-compliant resources that may have entered the cluster during the gap:

kubectl create job --from=cronjob/audit-scanner audit-scanner-manual -n "$NAMESPACE"

Image pull secrets for policy-server pods

Because this is an AppCo-to-AppCo migration, your existing global.imagePullSecrets value and the application-collection secret carry over unchanged into the new chart.

The SUSE Security Admission Controller chart pulls its component images from dp.apps.rancher.io, a private registry. The pull secret you create during installation is passed to the chart via global.imagePullSecrets. The controller reads this value and automatically adds those secrets to the imagePullSecrets field of every PolicyServer Deployment it manages, including any user-defined PolicyServer resources restored from a backup. No manual edit to individual PolicyServer resources is required.

All PolicyServer pods run in the same namespace as the controller, the namespace where the chart is installed. In this migration that namespace is $NAMESPACE. The pull secret you create when installing the chart already exists in that namespace, so restored PolicyServer resources can pull their images without any extra step.

PolicyServer.spec.imagePullSecret is a separate mechanism for providing credentials to the policy-server process when it fetches Wasm policy modules from a registry. It does not affect the pull secret used by the kubelet to pull the policy-server container image and will not resolve an ImagePullBackOff caused by a missing registry credential. Use global.imagePullSecrets (passed to the chart at install time) for container image pulls.

See the private registries how-to for policy servers and the Application Collection image verification how-to for more detail.

policyServer.imagePullSecret type change

The v0.8.0 kubewarden-defaults subchart defaults policyServer.imagePullSecret to null; the v1.0.0 chart defaults it to "" (empty string). If you seeded your override file from the chart’s default values.yaml, the flatten in Step 4 picks up that null and puts it at the top level of new-values.yaml. The cleanup command in Step 4 strips it. If you set this key to a real secret name, the command leaves it alone and there is nothing else to do.