Summary
When a Kubernetes TLS secret that has been synced to GCP Certificate Manager is deleted, the corresponding remote GCP certificate is not cleaned up. This leaves orphaned certificates in GCP that require manual deletion.
Current Behavior
- The informer in
cmd/cert-manager-sync/main.go only registers AddFunc and UpdateFunc — there is no DeleteFunc.
- The GCP store (
stores/gcpcm/gcpcm.go) only implements CreateCert and UpdateCert — there is no DeleteCert.
HandleSecret in pkg/certmanagersync/certmanagersync.go only reconciles existing watched secrets; it has no awareness of deletions.
- The operator writes the remote GCP certificate name back to the secret annotation (
cert-manager-sync.lestak.sh/gcp-certificate-name) for future updates, but there is no reverse cleanup path when the source secret disappears.
Expected Behavior
When a Kubernetes TLS secret with GCP sync annotations is deleted, the operator should delete the corresponding certificate from GCP Certificate Manager automatically.
Proposed Solution
Minimum viable change
- Add a
DeleteFunc to the informer.
- On secret delete, detect whether the secret had GCP sync enabled.
- Read the stored GCP certificate name from the annotation
cert-manager-sync.lestak.sh/gcp-certificate-name.
- Call GCP Certificate Manager delete for that certificate.
- Treat
NotFound as success so cleanup is idempotent.
Better long-term design
Use a finalizer on watched secrets. This would let the operator:
- See the delete intent before the secret is fully removed.
- Read annotations and any required config directly from the live object.
- Delete remote certificates reliably.
- Remove the finalizer only after cleanup succeeds (or after a clear failure policy).
Suggested GCP store change
Add DeleteCert(ctx context.Context) error to stores/gcpcm/gcpcm.go:
- Build a
DeleteCertificateRequest using s.CertificateName.
- Treat
NotFound as success.
Optionally extend the store contract with a delete-capable interface:
type DeletableRemoteStore interface {
RemoteStore
Delete(ctx context.Context) error
}
Design Questions for Maintainers
- Should delete reconciliation apply only to GCP, or to every remote store (AWS ACM, Vault, etc.)?
- What should happen if the remote delete fails — block finalizer removal and retry, or emit a warning and allow the delete to proceed?
- Should the operator delete only resources it created, or any resource referenced by annotation?
- If the same remote certificate is shared across multiple secrets, how should ownership be tracked?
Testing Considerations
- Unit test GCP delete request generation.
- Unit test delete reconciliation when annotation is present.
- Unit test idempotent delete when the remote cert is already gone.
- Unit test that non-GCP secrets are ignored during delete.
- If finalizers are added, test retry and finalizer removal behavior.
Context
We discovered this gap while running cert-manager-sync in production with the GCP Certificate Manager backend. Currently, manual cleanup in GCP is required whenever synced secrets are deleted from Kubernetes.
Happy to contribute a PR if the maintainers agree on the approach.
Summary
When a Kubernetes TLS secret that has been synced to GCP Certificate Manager is deleted, the corresponding remote GCP certificate is not cleaned up. This leaves orphaned certificates in GCP that require manual deletion.
Current Behavior
cmd/cert-manager-sync/main.goonly registersAddFuncandUpdateFunc— there is noDeleteFunc.stores/gcpcm/gcpcm.go) only implementsCreateCertandUpdateCert— there is noDeleteCert.HandleSecretinpkg/certmanagersync/certmanagersync.goonly reconciles existing watched secrets; it has no awareness of deletions.cert-manager-sync.lestak.sh/gcp-certificate-name) for future updates, but there is no reverse cleanup path when the source secret disappears.Expected Behavior
When a Kubernetes TLS secret with GCP sync annotations is deleted, the operator should delete the corresponding certificate from GCP Certificate Manager automatically.
Proposed Solution
Minimum viable change
DeleteFuncto the informer.cert-manager-sync.lestak.sh/gcp-certificate-name.NotFoundas success so cleanup is idempotent.Better long-term design
Use a finalizer on watched secrets. This would let the operator:
Suggested GCP store change
Add
DeleteCert(ctx context.Context) errortostores/gcpcm/gcpcm.go:DeleteCertificateRequestusings.CertificateName.NotFoundas success.Optionally extend the store contract with a delete-capable interface:
Design Questions for Maintainers
Testing Considerations
Context
We discovered this gap while running
cert-manager-syncin production with the GCP Certificate Manager backend. Currently, manual cleanup in GCP is required whenever synced secrets are deleted from Kubernetes.Happy to contribute a PR if the maintainers agree on the approach.