Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Goroutine to Cleanup Orphaned Shadow Secrets #980

Open
wants to merge 32 commits into
base: main
Choose a base branch
from

Conversation

jaireddjawed
Copy link

@jaireddjawed jaireddjawed commented Dec 2, 2024

Description

When an HCPVaultSecretsApp is deleted, the handleDeletion() method is called to remove the app's shadow secrets from k8s. However, if handleDeletion() fails to remove the secrets for some reason, the orphaned shadow secrets remain in k8s indefinitely because we don't have a mechanism that attempts to remove these shadow secrets again later.

This PR addresses this issue by creating a goroutine that periodically checks for deleted HVS apps and removes the app's shadow secrets.

Local Testing

  • Commented the initial deletion attempt of a HCPVaultSecretsApp in Reconcile() This is to mock the scenario where the first handleDeletion() call fails (mentioned here).
Screenshot 2024-12-17 at 6 00 03 AM
  • Created an HCPVaultSecretsApp that includes a dynamic secret (yaml config below)
Screenshot 2024-12-17 at 9 41 35 AM
apiVersion: v1
data:
  clientID: redacted
  clientSecret: redacted
kind: Secret
metadata:
  name: vso-demo-sp
  namespace: default
type: Opaque

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: HCPAuth
metadata:
  name: default
  namespace: vault-secrets-operator-system
spec:
  organizationID: redacted
  projectID: redacted
  servicePrincipal:
    secretRef: vso-demo-sp

---
apiVersion: secrets.hashicorp.com/v1beta1
kind: HCPVaultSecretsApp
metadata:
  name: web-application
  namespace: default
spec:
  appName: sample-app
  destination:
    create: true
    labels:
      hvs: "true"
    name: web-application
  refreshAfter: 15m
Screenshot 2024-12-17 at 6 14 27 AM
  • Confirmed that secret exists in k8s (kubectl get secrets -o yaml)
  • Deleted HCPVaultSecretsApp from k8s (kubectl delete hcpvaultsecretsapps.secrets.hashicorp.com web-application)
  • Confirmed that the secret no longer exists in k8s (kubectl get secrets -o yaml)
Screenshot 2024-12-17 at 6 15 28 AM

Jira Ticket

https://hashicorp.atlassian.net/browse/VAULT-31820

@jaireddjawed jaireddjawed self-assigned this Dec 2, 2024
@jaireddjawed jaireddjawed marked this pull request as ready for review December 17, 2024 17:38
@jaireddjawed jaireddjawed requested a review from a team as a code owner December 17, 2024 17:38
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
@jaireddjawed jaireddjawed enabled auto-merge (squash) January 9, 2025 21:05
Copy link
Member

@tvoran tvoran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor comments, this is looking pretty good.

controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller_test.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@benashz benashz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting there. I think we need to probably implement a few interfaces to avoid extra code duplication. We also want to to delegate running the cache pruner to the controller-runtime Manager. Happy to sync up with you on that.

controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
Copy link
Collaborator

@benashz benashz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting there! I added some more feedback for your consideration.

internal/options/env.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
main.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Outdated Show resolved Hide resolved
}

// if the HCPVaultSecretsApp has been deleted, and the shadow secret belongs to it, delete both
if o.GetDeletionTimestamp() != nil && o.GetUID() == types.UID(secret.Labels[helpers.LabelOwnerRefUID]) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if secret labels is missing the UID key?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assumed that it always would be included. Will update the if statement to protect from a nil pointer error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that would cause a nil pointer panic, I think it would just be like comparing something to an empty string

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked and the definition of labelOwnerRefID states that it cannot be blank on a secret. I think we are good to leave this as is?

labelOwnerRefUID is used as the primary key when listing the Secrets owned by a specific VSO object. It should be included in every Secret that is created by VSO.

controllers/hcpvaultsecretsapp_controller.go Show resolved Hide resolved
@jaireddjawed jaireddjawed requested a review from benashz January 30, 2025 00:28
@jaireddjawed jaireddjawed requested a review from tvoran January 31, 2025 23:13
controllers/hcpvaultsecretsapp_controller_test.go Outdated Show resolved Hide resolved
main.go Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Show resolved Hide resolved
controllers/hcpvaultsecretsapp_controller.go Show resolved Hide resolved
internal/options/env_test.go Show resolved Hide resolved
logger.Info("Deleted orphaned resources associated with HCPVaultSecretsApp", "app", o.Name)
} else if apierrors.IsNotFound(err) || secret.GetDeletionTimestamp() != nil {
// otherwise, delete the single shadow secret if it has a deletion timestamp
if err := helpers.DeleteSecret(ctx, r.Client, objKey); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think objKey is going to be the HCPVaultSecretsApp here; should be the secret instead?

Labels: map[string]string{
"app.kubernetes.io/component": "hvs-dynamic-secret-cache",
},
DeletionTimestamp: &deletionTimestamp,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add a similar test case where DeletionTimestamp is not set.


if tt.isShadowSecretDeletionExpected {
deletedSecret := &corev1.Secret{}
err := r.Get(ctx, makeShadowObjKey(tt.secret), deletedSecret)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this should be ctrlclient.ObjectKeyFromObject(tt.secret)? Otherwise it's not going to fetch the secret in the test case. And could probably just do this Get() once then do the if/else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants