From 8db579b80162514344041ee0aacb17b99e0744c6 Mon Sep 17 00:00:00 2001 From: Piotr Kazmierczak <470696+pkazmierczak@users.noreply.github.com> Date: Tue, 31 Dec 2024 16:43:52 +0100 Subject: [PATCH] keyring: warn if removing a key that was used for encrypting variables --- api/keyring.go | 6 ++++-- command/operator_root_keyring_remove.go | 4 +++- nomad/keyring_endpoint.go | 9 +++++++++ nomad/structs/keyring.go | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/api/keyring.go b/api/keyring.go index 69e0c9c1073..f55d3e45970 100644 --- a/api/keyring.go +++ b/api/keyring.go @@ -6,6 +6,7 @@ package api import ( "fmt" "net/url" + "strconv" ) // Keyring is used to access the Variables keyring. @@ -60,14 +61,15 @@ func (k *Keyring) List(q *QueryOptions) ([]*RootKeyMeta, *QueryMeta, error) { // Delete deletes a specific inactive key from the keyring func (k *Keyring) Delete(opts *KeyringDeleteOptions, w *WriteOptions) (*WriteMeta, error) { - wm, err := k.client.delete(fmt.Sprintf("/v1/operator/keyring/key/%v", - url.PathEscape(opts.KeyID)), nil, nil, w) + wm, err := k.client.delete(fmt.Sprintf("/v1/operator/keyring/key/%v?force=%v", + url.PathEscape(opts.KeyID), strconv.FormatBool(opts.Force)), nil, nil, w) return wm, err } // KeyringDeleteOptions are parameters for the Delete API type KeyringDeleteOptions struct { KeyID string // UUID + Force bool } // Rotate requests a key rotation diff --git a/command/operator_root_keyring_remove.go b/command/operator_root_keyring_remove.go index 942c351b0d7..f550d683b67 100644 --- a/command/operator_root_keyring_remove.go +++ b/command/operator_root_keyring_remove.go @@ -51,11 +51,12 @@ func (c *OperatorRootKeyringRemoveCommand) Name() string { } func (c *OperatorRootKeyringRemoveCommand) Run(args []string) int { - var verbose bool + var force, verbose bool flags := c.Meta.FlagSet("root keyring remove", FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } flags.BoolVar(&verbose, "verbose", false, "") + flags.BoolVar(&force, "force", false, "Forces deletion of the root keyring even if it's in use.") if err := flags.Parse(args); err != nil { return 1 @@ -76,6 +77,7 @@ func (c *OperatorRootKeyringRemoveCommand) Run(args []string) int { } _, err = client.Keyring().Delete(&api.KeyringDeleteOptions{ KeyID: removeKey, + Force: force, }, nil) if err != nil { c.Ui.Error(fmt.Sprintf("error: %s", err)) diff --git a/nomad/keyring_endpoint.go b/nomad/keyring_endpoint.go index 692cb84ed37..1c022395388 100644 --- a/nomad/keyring_endpoint.go +++ b/nomad/keyring_endpoint.go @@ -348,6 +348,15 @@ func (k *Keyring) Delete(args *structs.KeyringDeleteRootKeyRequest, reply *struc return fmt.Errorf("active root key cannot be deleted - call rotate first") } + // make sure the key was used to encrypt an existing variable + rootKeyInUse, err := snap.IsRootKeyInUse(args.KeyID) + if err != nil { + return err + } + if rootKeyInUse && !args.Force { + return fmt.Errorf("root key in use, cannot delete") + } + _, index, err = k.srv.raftApply(structs.WrappedRootKeysDeleteRequestType, args) if err != nil { return err diff --git a/nomad/structs/keyring.go b/nomad/structs/keyring.go index a858a771ab5..5dc85a05a80 100644 --- a/nomad/structs/keyring.go +++ b/nomad/structs/keyring.go @@ -500,6 +500,7 @@ type KeyringUpdateRootKeyMetaResponse struct { type KeyringDeleteRootKeyRequest struct { KeyID string + Force bool WriteRequest }