Safely retire services and delete tenants in mctl without leaving namespace, database, Vault, or ArgoCD fallout behind. Use when removing a tenant, debugging failed retire/delete workflows, cleaning post-delete drift, or preventing shared-pg and root-app degradation after tenant cleanup.
Resources
2Install
npx skillscat add mctlhq/mctl-gitops/tenant-safe-cleanup Install via the SkillsCat registry.
Tenant Safe Cleanup
Treat tenant deletion as orchestration, not as a blind namespace delete.
Use this skill to make sure service retirement, shared resource cleanup, and tenant removal happen in the correct order and leave Argo healthy.
Required Order
Follow this order unless you have a strong reason not to:
- inventory tenant services
- retire each service
- wait for retire workflows to finish
- clean shared resources that do not live in the tenant namespace
- delete tenant GitOps and namespace
- verify post-delete health
Do not delete the tenant namespace first.
Core Workflow
1. Inspect current state
Check:
- tenant services under
platform-gitops/services/<tenant>/ - Argo apps for the tenant and shared dependencies
- shared resources in namespaces like
platform-db - failed or partial workflows in
argo-workflows
2. Prefer delete-tenant-safe
Use the orchestrated workflow path rather than direct tenant deletion.
retire-serviceshould remain visible in the tenant namespace for ordinary service removal.delete-tenant-safeshould run fromargo-workflows, retire all services, wait, clean shared fallout, then remove the tenant.- In this repo the fast path also eager-prunes Argo app CRs and waits explicitly for service app, tenant app, and namespace disappearance.
3. Clean shared fallout explicitly
Assume some tenant-owned resources live outside the tenant namespace.
In this repo the critical shared path is:
platform-gitops/infra-components/data/cnpg/shared
Look for tenant-owned leftovers such as:
DatabaseCRsExternalSecretDB credentials- managed roles
pg_hbaentries
Also check platform-gitops/argo-workflows/sso-team-<tenant>.yaml — the
per-tenant Argo Workflows SSO ServiceAccount + rbac-rule created bywft-create-tenant.yaml. As of 2026-07-26 wft-delete-tenant-safe.yaml'sdelete-tenant-from-git step checked the wrong path
(platform-gitops/tenants/<tenant>/sso.yaml, which never existed) and
silently skipped removing it, so every prior tenant deletion may have
left one of these orphaned. An orphaned SSO ServiceAccount is not just
inert clutter: if a user is later a member of two tenants whose SSO groups
both resolve at the same rbac-rule-precedence (every tenant gets "5"
hardcoded), Argo Workflows SSO can non-deterministically pick the wrong
ServiceAccount and reject deploy-service with a forbidden error scoped
to the stale tenant's namespace — this is exactly what happened with
tenant nfc2026 (a never-deleted duplicate of nfc, same owner). The
path bug is fixed going forward (mctl-gitops#633), but when investigating
an unexplained "forbidden ... in namespace X" from Argo Workflows for a
user who has ever belonged to more than one tenant, check for leftoversso-team-<old-tenant>.yaml files as a likely root cause, not just
missing RBAC in the target namespace.
4. Verify after deletion
At the end verify:
- tenant namespace is gone if deletion was intended
- no tenant-owned shared DB artifacts remain
shared-pgis not degraded by the cleanuproot-appis not degraded by the cleanup
High-Value Rules
- Block unsafe tenant deletion if services still exist and orchestration is unavailable.
- Prefer fail-closed behavior over "wait and hope".
- If stale live resources remain after Git cleanup, delete only the confirmed leftovers.
- Distinguish tenant-fallout from unrelated platform incidents before broad remediation.
- Verify deletion with all four markers, not just API
404:- service app CR gone
- tenant app CR gone
- namespace gone
- tenant API returns
404
- Treat
kubectl get ...failures as success only when they are realNotFoundresults. Do not let generic command failures masquerade as cleanup success. - If delete speed matters, remember the two platform levers that materially affect it:
- eager prune inside
delete-tenant-safe - short ApplicationSet git poll interval (the repo now uses
requeueAfterSeconds: 30forappsandtenants)
- eager prune inside
When To Use Live Cleanup
Use live cleanup only for:
- stale DB artifacts already removed from GitOps
- broken workflows or pods left after an incident
- corrupted CRs that Argo should recreate cleanly
Keep the durable fix in GitOps or workflow logic whenever the issue can recur.
Read references/cleanup.md for the exact patterns that were fixed in this repo.