Covers upgrading an existing DefectDojo Pro release to a newer chart version.
The recommended path is to pull the chart directly from the DefectDojo OCI
registry — no zip extraction required. The packaged-zip workflow used at
install time also works for upgrades and is documented below.
A DefectDojo Pro release is a chart version, a set of container image
versions, and the Pro settings files. Those are built and tested together and
have to move together. Upgrading the image tags on their own is not supported
and will break the deployment.
The same applies to settings. A new pro_settings.py ships with nearly every
release. Never carry a copy forward across an upgrade, and never hand-patch an
older one: the application has to run the pro_settings.py that matches its
version. Your own customizations belong in local_settings.py, which is
preserved across upgrades and is the only one of the two you should edit.
Using the chart handles this for you. It ships and mounts the matching
pro_settings.py alongside your local_settings.py, so there is nothing to
copy or migrate by hand.
Every upgrade should start the same way. Skipping these steps is the most
common cause of failed upgrades.
Read the release notes for every version between your current release
and the target. Breaking changes, new required fields, and migration
prerequisites are called out there. See the
DefectDojo Pro Changelog and the
general on-premise upgrade procedure,
which also explains the initializer’s exit codes.
Check your current chart version. This is the floor for the upgrade:
helm list -n $NAMESPACEhelm get metadata dojopro -n $NAMESPACE
Back up your database. Chart upgrades can include Django migrations
that alter schema. Take a logical dump (or a storage-level snapshot) of
the PostgreSQL instance before proceeding.
Have your values files available. The upgrade command must pass the
same platform preset, profile preset, and customer values file used at
install. Missing or drifted values files cause surprising diffs.
Confirm secret references still exist. If you installed with
--set dojo.existingSecret=... or --set license.existingSecret=...,
verify those Kubernetes secrets are still present in the namespace.
Render the upgrade locally first to catch missing fields, invalid
values, or template errors before touching the cluster. Render the target
chart with the same values files and flags you will pass to helm upgrade.
That includes the ddorch certificates: without them the render fails with
ddorch.tls.rootCa is required.
Work in a private directory, because the server’s private key is one of the
files:
RELEASE=dojopro
WORK=$(mktemp -d)
If you still have the files you installed with, copy them into "$WORK"
as orch_ca.crt, orch_server.crt and orch_server.key. Otherwise read
them back from the release’s stored values, which keep what you passed with
--set-file:
(umask077cd"$WORK"||exit1 helm get values "$RELEASE" -n "$NAMESPACE" -o json | jq -r '.ddorch.tls.rootCa // empty' > orch_ca.crt
helm get values "$RELEASE" -n "$NAMESPACE" -o json | jq -r '.ddorch.tls.cert // empty' > orch_server.crt
helm get values "$RELEASE" -n "$NAMESPACE" -o json | jq -r '.ddorch.tls.key // empty' > orch_server.key
test -s orch_ca.crt &&test -s orch_server.crt &&test -s orch_server.key \
&&echo"ddorch certificates copied"\
||echo"not all three are in the release values: use the fallback below")
If that reports a missing file (for example the release is managed by
Argo CD, which has no Helm release to read, or the key was never passed as
a value), take them from the objects the chart created instead. Their names
start with the chart’s full name, <fullname>: the release name when it
contains dojopro, otherwise <release>-dojopro, and a tenantPrefix or
fullnameOverride changes it. kubectl get configmap,secret -n "$NAMESPACE" | grep orch-certs
shows the exact names.
The CA and server certificate are in the ConfigMap
<fullname>-orch-certs-configmap, under the keys orch_tls_root.ca and
orch_tls.crt.
The private key is in the Secret <fullname>-orch-certs, under
orch_tls.key, on chart versions that keep it in a Secret. On chart
versions without that Secret, it is under orch_tls.key in the same
ConfigMap.
If you set ddorch.tls.existingSecret, the key is in your own Secret.
Do not copy it: leave out --set-file ddorch.tls.key below and pass
--set ddorch.tls.existingSecret=<your-secret> instead.
FULLNAME=dojopro
(umask077cd"$WORK"||exit1 kubectl get configmap "$FULLNAME-orch-certs-configmap" -n "$NAMESPACE"\
-o jsonpath='{.data.orch_tls_root\.ca}' > orch_ca.crt
kubectl get configmap "$FULLNAME-orch-certs-configmap" -n "$NAMESPACE"\
-o jsonpath='{.data.orch_tls\.crt}' > orch_server.crt
kubectl get secret "$FULLNAME-orch-certs" -n "$NAMESPACE"\
-o jsonpath='{.data.orch_tls\.key}' 2>/dev/null | base64 -d > orch_server.key
test -s orch_server.key || kubectl get configmap "$FULLNAME-orch-certs-configmap"\
-n "$NAMESPACE" -o jsonpath='{.data.orch_tls\.key}' > orch_server.key
test -s orch_ca.crt &&test -s orch_server.crt &&test -s orch_server.key \
&&echo"ddorch certificates copied"||echo"a file is still empty: stop and check the names")
Then point CHART at the target chart. If you extracted the release zip
(see Upgrade via Extracted Zip), use that
path. To use the registry instead, authenticate
and pull the chart into the same directory:
If you installed with inline secrets and the license file, use
-f my-secrets.yaml and --set-file license.contents=/path/to/license.lic
in place of the two existingSecret flags.
When you have reviewed the render, delete the directory. It holds the
private key, and the render can hold secret values too:
rm -rf "$WORK"
Set NAMESPACE once — every command in this guide uses $NAMESPACE:
NAMESPACE="dojopro"
Network policy default changed. NetworkPolicies are now governed by
networkPolicy.profile, which defaults to standard: all egress plus
ingress between this release’s own pods is allowed (external ingress is still
restricted to the ingress path). This is more permissive than the previous
always-granular egress allowlist. To keep the locked-down behavior, set
networkPolicy.profile: aggressive and review the carve-outs
(nodeLocalDns, dnsSelectors, externalAPIs) — see
Network Policies.
Orchestrator database requirement. The orchestrator (ddorch) uses a
second database named <main-db-name>-ddorch and creates it at startup if
it does not exist. If your application role lacks CREATEDB, pre-create it
(CREATE DATABASE "defectdojo-ddorch" OWNER defectdojo;) before upgrading
to a chart version that enables ddorch — otherwise the ddorch pod fails with
permission denied to create database (SQLSTATE 42501). See
Pre-flight: Orchestrator (ddorch) Database.
Organization/Asset relabel default.dojo.V3EnableOrganizationAssetRelabel
now defaults to null (auto): it is enabled for new installs and left
off on upgrades, so the UI relabel (Organization/Asset replacing
ProductType/Asset) never flips on unexpectedly for an existing release. To
opt an upgraded release in, set dojo.V3EnableOrganizationAssetRelabel: true
explicitly; an explicit true/false always wins over the auto default.
Each release is tagged with the chart version (for example 3.4.0). The
chart version matches the app version in Chart.yaml, so the tag you pass
to helm upgrade --version is the DefectDojo Pro release number in the
DefectDojo Pro Changelog.
Helm cannot list the versions in an OCI repository. Take the version from the
changelog, then confirm the registry has it (this needs the registry login
below):
helm show chart \
oci://us-south1-docker.pkg.dev/defectdojo-container-registry/dojo-pro-helm-v2/dojopro \
--version <chart-version>
The command prints the chart’s version and appVersion if the version
exists, and fails if it does not.
Why OCI for upgrades? The presets (presets/platforms/*.yaml,
presets/profiles/*.yaml) are packaged inside the chart. Referencing the
chart by its OCI URL pulls the correct preset versions for the target
chart automatically — no re-extraction step, no stale presets.
The registry is private. Helm must be logged in before it can pull the
chart. The simplest way is dojo-helm-cli register, which logs helm and
docker in with the registry key in your license (see
Installing on Kubernetes with dojo-helm-cli).
To log in without the CLI, use one of the options below. Option A never prints
the key and does not use gcloud, so it leaves your active gcloud account
alone.
gcloud auth login makes the account you sign in with the active gcloud
account. If you use gcloud for other work, check gcloud config list account
afterwards and switch back with gcloud config set account <your-usual-account>.
Access tokens from gcloud auth print-access-token expire after one hour.
Re-run helm registry login if you see a 401 Unauthorized during the
upgrade.
Air-gapped / firewalled environments: if your cluster nodes can reach
us-south1-docker.pkg.dev but your workstation cannot, use the
extracted-zip workflow below. The OCI workflow only works when the host
running helm upgrade can reach the registry.
Point helm upgrade directly at the OCI URL and pin the chart version with
--version. All values files, --set flags, and --set-file flags are the
same as the original install.
The platform and profile preset paths above are presets/platforms/...
(no $CHART/ prefix). When Helm pulls a chart from OCI, the presets live
inside the pulled chart, but -f here points at local copies of those
files. If you do not keep local copies of the presets, extract the chart
first with helm pull oci://... --version $VERSION --untar and reference
them from the extracted directory — or use the extracted-zip workflow.
Always pin --version. Omitting it pulls whatever tag the registry
resolves to at the moment of the command — not repeatable, not
auditable. Pin the version so reruns, rollbacks, and incident response
all reference the same artifact.
For workstations that cannot reach the OCI registry, or for customers who
prefer to stage the chart as a local file, the packaged zip that DefectDojo
provides for each release works the same way at upgrade time as it does at
install time. The only difference from install is the command verb
(helm upgrade instead of helm install).
Get dojo-pro-helm-bundled-<version>.zip, its detached signature
dojo-pro-helm-bundled-<version>.zip.asc, and the public key
dojo-pro-release-signing.asc for the target release.
Re-extract on every upgrade. Preset files evolve between chart
versions. Reusing an old extraction silently pins your upgrade to the old
preset defaults.
When DefectDojo Pro is managed by ArgoCD, upgrading is a single change to
targetRevision in the Application spec. The platform and profile presets
are versioned inside the chart, so they update in lockstep.
Sync the Application after editing targetRevision. ArgoCD will pull the
new chart from the OCI registry and reconcile.
ArgoCD needs its own credentials to the OCI registry. Configure the repo
secret with type: helm and enableOCI: "true". See the ArgoCD
Helm OCI docs
for the exact Secret shape.
After helm upgrade returns (or ArgoCD reports Synced / Healthy), confirm
the new revision is live:
# Chart revision bumped and status is deployedhelm list -n $NAMESPACE# All pods Running and Ready. On chart 3.4.0 with the standard profile:# django, django-import, celery-worker, celery-imports-worker, celery-beat,# connectors, integrators, ddorch, ddorch-workers and mcp-server, plus# webhook-gateway when the chart can create its secrets, redis unless you use# an external broker, and sensei if you enabled itkubectl get pods -n $NAMESPACE# Migrations succeeded — the initializer job should show Completedkubectl get jobs -n $NAMESPACE# App version matches the targetkubectl get deployment -n $NAMESPACE\
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}'
Hit the login page to confirm the UI comes up and the admin user can
authenticate. For programmatic checks, the light health check needs no
login and returns 200 when the application is up:
Helm keeps release history by revision. If the upgrade regresses behavior,
roll back to the previous revision:
# Inspect historyhelm history dojopro -n $NAMESPACE# Roll back to the previous revisionhelm rollback dojopro <previous-revision> -n $NAMESPACE --wait --timeout 15m
Database migrations do not roll back. Helm rollback restores the
manifest state (images, configs, secrets) but does not run
migrate --revert. If the upgrade applied a schema migration you need
to reverse, restore from the backup taken in
Before You Upgrade or coordinate a manual
migration reversal with DefectDojo support before rolling back the
Helm release.
ArgoCD users can roll back by reverting the targetRevision change in
git (or via argocd app rollback) and syncing.
401 Unauthorized pulling the chart.
Access token has expired. Re-run helm registry login with a fresh
gcloud auth print-access-token.
Error: UPGRADE FAILED: cannot patch ... field is immutable.
A selector or other immutable field drifted. The chart pins stable
selector labels, so this usually means a prior in-place edit to a
Deployment. Capture the diff, delete the offending resource, and re-run
the upgrade so Helm recreates it.
Error: UPGRADE FAILED: conflict occurred while applying object ... conflict with "kubectl-edit" ... .spec.replicas.
Helm 4 uses server-side apply, which tracks field ownership. This error
means another manager — kubectl edit, kubectl scale, or the HPA
controller (kube-controller-manager) — changed a field Helm renders,
most commonly .spec.replicas. Take ownership back once:
helm upgrade ... --force-conflicts
Chart versions with this fix omit replicas from Deployments whose HPA
is enabled, so the HPA scaling no longer conflicts with upgrades. If you
manually scaled a Deployment with kubectl, prefer adjusting the
corresponding replicas/horizontalpodautoscaler value instead so the
chart stays the owner.
Error: UPGRADE FAILED: timed out waiting for the condition.
Pods did not reach Ready within the --timeout window. Inspect the
laggy workload:
Common causes: image pull failures (registry auth), schema migration
still running (bump --timeout), or readiness probes failing against a
mis-configured FQDN.
Preset changed between versions and my values file now conflicts.
Re-render with helm template (see Before You Upgrade)
and reconcile your overrides against the new preset defaults before
running helm upgrade.
values don't meet the specifications of the schema ... got string, want boolean.
An on/off value in your override is quoted. Helm treats "false" as a
non-empty string, and a non-empty string is truthy, so the feature was
switching on when you meant to switch it off. The schema now rejects
the quoted form instead of letting it through. Drop the quotes:
networkPolicy:enabled:"false"# wrong: turns network policies ONenabled:false# right
The error message names the offending path. Unquoted false, no, and
off all parse as a real boolean and are accepted.