fix(mariadb): clean up orphaned operator-generated secrets (#3056)

The mariadb-operator creates <release>-metrics-password and
<release>-repl-password Secrets as a side effect of metrics/replication
being enabled. These are not Helm-owned and survive `helm uninstall`,
leaving orphaned Secrets in the tenant namespace after the app CR is
deleted.

Extend the existing post-delete cleanup hook to sweep them: grant the
cleanup Role RBAC on secrets and delete both password Secrets by name.
Add a helm-unittest suite locking in the behaviour (and a `test` Makefile
target so the package's tests run in CI).

Signed-off-by: Алексей Артамонов <aleksei.artamonov@aenix.io>
This commit is contained in:
Алексей Артамонов committed 2026-06-25 18:48:22 +03:00
1 parent 374cac1060
commit 7ef2b2f40f
3 files changed
+99 -1

No files matched your search

+4
View File
@@ -11,6 +11,10 @@ update:
hack/update-versions.sh
make generate
.PHONY: test
test:
helm unittest .
image:
docker buildx build images/mariadb-backup \
$(call image-tags,mariadb-backup,$(MARIADB_BACKUP_TAG)) \
@@ -18,16 +18,49 @@ spec:
spec:
serviceAccountName: {{ .Release.Name }}-cleanup
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: cleanup
image: docker.io/clastix/kubectl:v1.32
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
env:
- name: HOME
value: /tmp
resources:
requests:
cpu: 10m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
command:
- /bin/sh
- -c
- |
echo "Deleting orphaned PVCs for {{ .Release.Name }}..."
kubectl delete pvc -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} || true
kubectl delete pvc -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} --ignore-not-found \
|| echo "WARNING: PVC cleanup failed for {{ .Release.Name }}; orphaned PVCs may remain" >&2
echo "PVC cleanup complete."
echo "Deleting orphaned operator-generated Secrets for {{ .Release.Name }}..."
kubectl delete secret -n {{ .Release.Namespace }} \
{{ .Release.Name }}-metrics-password {{ .Release.Name }}-repl-password --ignore-not-found \
|| echo "WARNING: Secret cleanup failed for {{ .Release.Name }}; orphaned Secrets may remain" >&2
echo "Secret cleanup complete."
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
---
apiVersion: v1
kind: ServiceAccount
@@ -51,9 +84,18 @@ metadata:
"helm.sh/hook-weight": "5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
rules:
# PVCs are deleted by label selector, which requires list.
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "delete"]
# Operator-generated Secrets are deleted by name, so scope the rule to
# exactly those two resources (least privilege — no namespace-wide secret access).
- apiGroups: [""]
resources: ["secrets"]
resourceNames:
- {{ .Release.Name }}-metrics-password
- {{ .Release.Name }}-repl-password
verbs: ["get", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
@@ -0,0 +1,52 @@
suite: post-delete cleanup hook
# Locks in the post-delete cleanup behaviour. The mariadb-operator creates
# <release>-metrics-password and <release>-repl-password Secrets as a side
# effect of metrics/replication being enabled. These Secrets are not
# Helm-owned and survive `helm uninstall`, so the post-delete hook must
# sweep them (issue #3056) alongside the orphaned PVCs. The hook Role also
# needs RBAC on secrets to do so.
templates:
- templates/hooks/cleanup-pvc.yaml
release:
name: mariadb-test
namespace: tenant-test
tests:
- it: "cleanup Job deletes the operator-generated password Secrets by name"
documentSelector:
path: kind
value: Job
asserts:
- matchRegex:
path: spec.template.spec.containers[0].command[2]
pattern: "mariadb-test-metrics-password mariadb-test-repl-password --ignore-not-found"
- it: "cleanup Role grants get/list/delete on persistentvolumeclaims"
documentSelector:
path: kind
value: Role
asserts:
- contains:
path: rules
content:
apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "delete"]
- it: "cleanup Role scopes secret access to the two named secrets only (least privilege)"
documentSelector:
path: kind
value: Role
asserts:
- contains:
path: rules
content:
apiGroups: [""]
resources: ["secrets"]
resourceNames:
- mariadb-test-metrics-password
- mariadb-test-repl-password
verbs: ["get", "delete"]