···33# To re-generate a bundle for another specific version without changing the standard setup, you can:
44# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
55# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
66-VERSION ?= 0.7.0
66+VERSION ?= 0.8.0
7788# CHANNELS define the bundle channels used in the bundle.
99# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
···6868 // DeleteSecret removes secret data from the specified HSM path
6969 DeleteSecret(ctx context.Context, path string) error
70707171+ // DeleteSecretKey removes a specific key from the secret at the given path
7272+ DeleteSecretKey(ctx context.Context, path, key string) error
7373+7174 // ListSecrets returns a list of secret paths
7275 ListSecrets(ctx context.Context, prefix string) ([]string, error)
7376
+23
internal/hsm/mock_client.go
···186186 return nil
187187}
188188189189+// DeleteSecretKey removes a specific key from the secret at the given path
190190+func (m *MockClient) DeleteSecretKey(ctx context.Context, path, key string) error {
191191+ m.mutex.Lock()
192192+ defer m.mutex.Unlock()
193193+194194+ if !m.connected {
195195+ return fmt.Errorf("HSM not connected")
196196+ }
197197+198198+ data, exists := m.secrets[path]
199199+ if !exists {
200200+ return fmt.Errorf("secret not found at path: %s", path)
201201+ }
202202+203203+ if _, keyExists := data[key]; !keyExists {
204204+ return fmt.Errorf("key %q not found in secret %q", key, path)
205205+ }
206206+207207+ delete(data, key)
208208+ m.logger.Info("Deleted key from mock HSM secret", "path", path, "key", key)
209209+ return nil
210210+}
211211+189212// ListSecrets returns a list of secret paths with the given prefix
190213func (m *MockClient) ListSecrets(ctx context.Context, prefix string) ([]string, error) {
191214 m.mutex.RLock()
+40
internal/hsm/pkcs11_cgo.go
···409409 return nil
410410}
411411412412+// deleteSecretKeyPKCS11 removes a single data object with the exact label
413413+func deleteSecretKeyPKCS11(session *Session, label string) error {
414414+ if session == nil {
415415+ return fmt.Errorf("session is nil")
416416+ }
417417+418418+ // Find data objects with exact label match
419419+ template := []*pkcs11.Attribute{
420420+ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_DATA),
421421+ pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
422422+ }
423423+424424+ if err := session.ctx.FindObjectsInit(session.session, template); err != nil {
425425+ return fmt.Errorf("failed to initialize object search: %w", err)
426426+ }
427427+428428+ // Find the object
429429+ objs, _, err := session.ctx.FindObjects(session.session, 1)
430430+ if err != nil {
431431+ _ = session.ctx.FindObjectsFinal(session.session)
432432+ return fmt.Errorf("failed to find object: %w", err)
433433+ }
434434+435435+ // Must finalize search before destroying objects
436436+ if err := session.ctx.FindObjectsFinal(session.session); err != nil {
437437+ return fmt.Errorf("failed to finalize object search: %w", err)
438438+ }
439439+440440+ if len(objs) == 0 {
441441+ return fmt.Errorf("key not found: %s", label)
442442+ }
443443+444444+ // Destroy the object
445445+ if err := session.ctx.DestroyObject(session.session, objs[0]); err != nil {
446446+ return fmt.Errorf("failed to destroy object: %w", err)
447447+ }
448448+449449+ return nil
450450+}
451451+412452// changePINPKCS11 changes the HSM PIN
413453func changePINPKCS11(session *Session, oldPIN, newPIN string) error {
414454 if session == nil {
+28
internal/hsm/pkcs11_client.go
···358358 return nil
359359}
360360361361+// DeleteSecretKey removes a specific key from the secret at the given path
362362+func (c *PKCS11Client) DeleteSecretKey(ctx context.Context, path, key string) error {
363363+ c.mutex.Lock()
364364+ defer c.mutex.Unlock()
365365+366366+ if !c.connected {
367367+ return fmt.Errorf("HSM not connected")
368368+ }
369369+370370+ // Build the exact label for this key
371371+ label := path
372372+ if key != "" && key != defaultKeyName {
373373+ label = path + "/" + key
374374+ }
375375+376376+ c.logger.Info("Deleting secret key from HSM", "path", path, "key", key, "label", label)
377377+378378+ if err := deleteSecretKeyPKCS11(c.session, label); err != nil {
379379+ return fmt.Errorf("failed to delete secret key: %w", err)
380380+ }
381381+382382+ // Remove from cache
383383+ delete(c.dataObjects, label)
384384+385385+ c.logger.Info("Successfully deleted secret key from HSM", "path", path, "key", key)
386386+ return nil
387387+}
388388+361389// ListSecrets returns a list of secret paths with the given prefix
362390func (c *PKCS11Client) ListSecrets(ctx context.Context, prefix string) ([]string, error) {
363391 c.mutex.RLock()
+5
internal/hsm/pkcs11_stub.go
···5656 return fmt.Errorf("PKCS#11 support requires CGO (set CGO_ENABLED=1 and rebuild)")
5757}
58585959+// deleteSecretKeyPKCS11 returns an error for non-CGO builds
6060+func deleteSecretKeyPKCS11(session *Session, label string) error {
6161+ return fmt.Errorf("PKCS#11 support requires CGO (set CGO_ENABLED=1 and rebuild)")
6262+}
6363+5964// changePINPKCS11 returns an error for non-CGO builds
6065func changePINPKCS11(session *Session, oldPIN, newPIN string) error {
6166 return fmt.Errorf("PKCS#11 support requires CGO (set CGO_ENABLED=1 and rebuild)")
+5
kubectl-hsm/pkg/client/client.go
···183183 return c.doRequest(ctx, "DELETE", fmt.Sprintf("/api/v1/hsm/secrets/%s", name), nil, nil)
184184}
185185186186+// DeleteSecretKey deletes a specific key from a secret in the HSM
187187+func (c *Client) DeleteSecretKey(ctx context.Context, name, key string) error {
188188+ return c.doRequest(ctx, "DELETE", fmt.Sprintf("/api/v1/hsm/secrets/%s/%s", name, key), nil, nil)
189189+}
190190+186191// GetHealth checks the health status of the HSM operator
187192func (c *Client) GetHealth(ctx context.Context) (*HealthStatus, error) {
188193 var result HealthStatus
+14-1
kubectl-hsm/pkg/commands/delete.go
···9191 }
92929393 if opts.Key != "" {
9494- return fmt.Errorf("deleting individual keys is not yet supported - please delete the entire secret and recreate it")
9494+ // Confirm deletion unless force is specified
9595+ if !opts.Force {
9696+ if err := opts.confirmDeletion(secretName); err != nil {
9797+ return err
9898+ }
9999+ }
100100+101101+ // Delete the specific key via native API
102102+ fmt.Printf("Deleting key '%s' from secret '%s'...\n", opts.Key, secretName)
103103+ if err := hsmClient.DeleteSecretKey(ctx, secretName, opts.Key); err != nil {
104104+ return fmt.Errorf("failed to delete key: %w", err)
105105+ }
106106+ fmt.Printf("Key '%s' deleted successfully from secret '%s'.\n", opts.Key, secretName)
107107+ return nil
95108 }
9610997110 // Confirm deletion unless force is specified