From cb226eec46b59372c684c3946e0ba0910066573d Mon Sep 17 00:00:00 2001 From: Artem Chernyshev Date: Mon, 10 Jul 2023 17:16:16 +0300 Subject: [PATCH] fix: rewrite encryption system information flow Pass getter to the key handler instead of already fetched node uuid. Signed-off-by: Artem Chernyshev --- .../pkg/runtime/v1alpha1/v1alpha1_runtime.go | 8 +----- .../v1alpha1/v1alpha1_sequencer_tasks.go | 2 +- internal/pkg/encryption/encryption.go | 27 +++++++++--------- internal/pkg/encryption/helpers/helpers.go | 15 ++++++++++ internal/pkg/encryption/keys/keys.go | 14 +++++----- internal/pkg/encryption/keys/kms.go | 24 ++++++++++------ internal/pkg/encryption/keys/nodeid.go | 28 +++++++++++++------ internal/pkg/encryption/keys/options.go | 12 ++++---- internal/pkg/mount/options.go | 26 ++++++++--------- internal/pkg/mount/system.go | 23 ++++----------- 10 files changed, 98 insertions(+), 81 deletions(-) create mode 100644 internal/pkg/encryption/helpers/helpers.go diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_runtime.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_runtime.go index cdf542a523..737ab1490e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_runtime.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_runtime.go @@ -15,7 +15,6 @@ import ( "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/safe" - "github.com/cosi-project/runtime/pkg/state" "github.com/google/go-cmp/cmp" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" @@ -227,12 +226,7 @@ func (r *Runtime) IsBootstrapAllowed() bool { // GetSystemInformation returns system information resource if it exists. func (r *Runtime) GetSystemInformation(ctx context.Context) (*hardware.SystemInformation, error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*2) - defer cancel() - - return safe.StateWatchFor[*hardware.SystemInformation](ctx, r.State().V1Alpha2().Resources(), hardware.NewSystemInformation(hardware.SystemInformationID).Metadata(), - state.WithEventTypes(state.Created, state.Updated), - ) + return safe.StateGet[*hardware.SystemInformation](ctx, r.State().V1Alpha2().Resources(), hardware.NewSystemInformation(hardware.SystemInformationID).Metadata()) } // atomicInterface is a typed wrapper around atomic.Value. It's only useful for storing the interfaces, because diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index 5d26b8c2f8..9ac45be4f7 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -2115,7 +2115,7 @@ func MountStatePartition(seq runtime.Sequence, _ any) (runtime.TaskExecutionFunc } if encryption != nil { - opts = append(opts, mount.WithEncryptionConfig(encryption)) + opts = append(opts, mount.WithEncryptionConfig(encryption), mount.WithSystemInformationGetter(r.GetSystemInformation)) } return mount.SystemPartitionMount(ctx, r, logger, constants.StatePartitionLabel, opts...) diff --git a/internal/pkg/encryption/encryption.go b/internal/pkg/encryption/encryption.go index 5a51353728..4baf9eb1c7 100644 --- a/internal/pkg/encryption/encryption.go +++ b/internal/pkg/encryption/encryption.go @@ -23,6 +23,7 @@ import ( "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" "github.com/siderolabs/go-retry/retry" + "github.com/siderolabs/talos/internal/pkg/encryption/helpers" "github.com/siderolabs/talos/internal/pkg/encryption/keys" "github.com/siderolabs/talos/pkg/machinery/config/config" ) @@ -33,7 +34,7 @@ const ( ) // NewHandler creates new Handler. -func NewHandler(device *blockdevice.BlockDevice, partition *gpt.Partition, encryptionConfig config.Encryption, nodeParams NodeParams) (*Handler, error) { +func NewHandler(device *blockdevice.BlockDevice, partition *gpt.Partition, encryptionConfig config.Encryption, getSystemInformation helpers.SystemInformationGetter) (*Handler, error) { var provider encryption.Provider switch encryptionConfig.Kind() { @@ -71,23 +72,23 @@ func NewHandler(device *blockdevice.BlockDevice, partition *gpt.Partition, encry } return &Handler{ - device: device, - partition: partition, - encryptionConfig: encryptionConfig, - encryptionProvider: provider, - nodeParams: nodeParams, + device: device, + partition: partition, + encryptionConfig: encryptionConfig, + encryptionProvider: provider, + getSystemInformation: getSystemInformation, }, nil } // Handler reads encryption config, creates appropriate // encryption provider, handles encrypted partition open and close. type Handler struct { - device *blockdevice.BlockDevice - partition *gpt.Partition - encryptionConfig config.Encryption - encryptionProvider encryption.Provider - nodeParams NodeParams - encryptedPath string + device *blockdevice.BlockDevice + partition *gpt.Partition + encryptionConfig config.Encryption + encryptionProvider encryption.Provider + getSystemInformation helpers.SystemInformationGetter + encryptedPath string } // Open encrypted partition. @@ -337,7 +338,7 @@ func (h *Handler) initKeyHandlers(encryptionConfig config.Encryption, partition handlers := make([]keys.Handler, 0, len(encryptionConfig.Keys())) for _, cfg := range encryptionConfig.Keys() { - handler, err := keys.NewHandler(cfg, keys.WithPartitionLabel(partition.Name), keys.WithNodeUUID(h.nodeParams.UUID)) + handler, err := keys.NewHandler(cfg, keys.WithPartitionLabel(partition.Name), keys.WithSystemInformationGetter(h.getSystemInformation)) if err != nil { return nil, err } diff --git a/internal/pkg/encryption/helpers/helpers.go b/internal/pkg/encryption/helpers/helpers.go new file mode 100644 index 0000000000..9d2002da2c --- /dev/null +++ b/internal/pkg/encryption/helpers/helpers.go @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package helpers defines encryption handlers. +package helpers + +import ( + "context" + + "github.com/siderolabs/talos/pkg/machinery/resources/hardware" +) + +// SystemInformationGetter defines the closure which can be used in key handlers to get the node UUID. +type SystemInformationGetter func(context.Context) (*hardware.SystemInformation, error) diff --git a/internal/pkg/encryption/keys/keys.go b/internal/pkg/encryption/keys/keys.go index c09c928bbf..491124a921 100644 --- a/internal/pkg/encryption/keys/keys.go +++ b/internal/pkg/encryption/keys/keys.go @@ -15,7 +15,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/config/config" ) -var errNoNodeUUID = fmt.Errorf("the node UUID is not set") +var errNoSystemInfoGetter = fmt.Errorf("the UUID getter is not set") // NewHandler key using provided config. func NewHandler(cfg config.EncryptionKey, options ...KeyOption) (Handler, error) { @@ -35,17 +35,17 @@ func NewHandler(cfg config.EncryptionKey, options ...KeyOption) (Handler, error) return NewStaticKeyHandler(key, k), nil case cfg.NodeID() != nil: - if opts.NodeUUID == "" { - return nil, fmt.Errorf("failed to create nodeUUID key handler at slot %d: %w", cfg.Slot(), errNoNodeUUID) + if opts.GetSystemInformation == nil { + return nil, fmt.Errorf("failed to create nodeUUID key handler at slot %d: %w", cfg.Slot(), errNoSystemInfoGetter) } - return NewNodeIDKeyHandler(key, opts.PartitionLabel, opts.NodeUUID), nil + return NewNodeIDKeyHandler(key, opts.PartitionLabel, opts.GetSystemInformation), nil case cfg.KMS() != nil: - if opts.NodeUUID == "" { - return nil, fmt.Errorf("failed to create KMS key handler at slot %d: %w", cfg.Slot(), errNoNodeUUID) + if opts.GetSystemInformation == nil { + return nil, fmt.Errorf("failed to create KMS key handler at slot %d: %w", cfg.Slot(), errNoSystemInfoGetter) } - return NewKMSKeyHandler(key, cfg.KMS().Endpoint(), opts.NodeUUID) + return NewKMSKeyHandler(key, cfg.KMS().Endpoint(), opts.GetSystemInformation) } return nil, fmt.Errorf("malformed config: no key handler can be created") diff --git a/internal/pkg/encryption/keys/kms.go b/internal/pkg/encryption/keys/kms.go index bc3c2f9ad3..204a326d26 100644 --- a/internal/pkg/encryption/keys/kms.go +++ b/internal/pkg/encryption/keys/kms.go @@ -21,8 +21,8 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" + "github.com/siderolabs/talos/internal/pkg/encryption/helpers" "github.com/siderolabs/talos/internal/pkg/endpoint" - "github.com/siderolabs/talos/internal/pkg/smbios" ) // KMSToken is the userdata stored in the partition token metadata. @@ -33,15 +33,16 @@ type KMSToken struct { // KMSKeyHandler seals token using KMS service. type KMSKeyHandler struct { KeyHandler - kmsEndpoint string - nodeUUID string + kmsEndpoint string + getSystemInfo helpers.SystemInformationGetter } // NewKMSKeyHandler creates new KMSKeyHandler. -func NewKMSKeyHandler(key KeyHandler, kmsEndpoint, nodeUUID string) (*KMSKeyHandler, error) { +func NewKMSKeyHandler(key KeyHandler, kmsEndpoint string, getSystemInfo helpers.SystemInformationGetter) (*KMSKeyHandler, error) { return &KMSKeyHandler{ - KeyHandler: key, - kmsEndpoint: kmsEndpoint, + KeyHandler: key, + kmsEndpoint: kmsEndpoint, + getSystemInfo: getSystemInfo, }, nil } @@ -62,8 +63,13 @@ func (h *KMSKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Toke return nil, nil, err } + systemInformation, err := h.getSystemInfo(ctx) + if err != nil { + return nil, nil, err + } + resp, err := client.Seal(ctx, &kms.Request{ - NodeUuid: h.nodeUUID, + NodeUuid: systemInformation.TypedSpec().UUID, Data: key, }) if err != nil { @@ -97,13 +103,13 @@ func (h *KMSKeyHandler) GetKey(ctx context.Context, t token.Token) (*encryption. client := kms.NewKMSServiceClient(conn) - s, err := smbios.GetSMBIOSInfo() + systemInformation, err := h.getSystemInfo(ctx) if err != nil { return nil, err } resp, err := client.Unseal(ctx, &kms.Request{ - NodeUuid: s.SystemInformation.UUID, + NodeUuid: systemInformation.TypedSpec().UUID, Data: token.UserData.SealedData, }) if err != nil { diff --git a/internal/pkg/encryption/keys/nodeid.go b/internal/pkg/encryption/keys/nodeid.go index c457f5b1b1..6e85224fe4 100644 --- a/internal/pkg/encryption/keys/nodeid.go +++ b/internal/pkg/encryption/keys/nodeid.go @@ -10,6 +10,8 @@ import ( "github.com/siderolabs/go-blockdevice/blockdevice/encryption" "github.com/siderolabs/go-blockdevice/blockdevice/encryption/token" + + "github.com/siderolabs/talos/internal/pkg/encryption/helpers" ) // NodeIDKeyHandler generates the key based on current node information @@ -17,14 +19,15 @@ import ( type NodeIDKeyHandler struct { KeyHandler partitionLabel string - nodeUUID string + getSystemInfo helpers.SystemInformationGetter } // NewNodeIDKeyHandler creates new NodeIDKeyHandler. -func NewNodeIDKeyHandler(key KeyHandler, partitionLabel, nodeUUID string) *NodeIDKeyHandler { +func NewNodeIDKeyHandler(key KeyHandler, partitionLabel string, systemInfoGetter helpers.SystemInformationGetter) *NodeIDKeyHandler { return &NodeIDKeyHandler{ KeyHandler: key, partitionLabel: partitionLabel, + getSystemInfo: systemInfoGetter, } } @@ -36,19 +39,26 @@ func (h *NodeIDKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.T } // GetKey implements Handler interface. -func (h *NodeIDKeyHandler) GetKey(context.Context, token.Token) (*encryption.Key, error) { - if h.nodeUUID == "" { - return nil, fmt.Errorf("machine UUID is not populated %s", h.nodeUUID) +func (h *NodeIDKeyHandler) GetKey(ctx context.Context, _ token.Token) (*encryption.Key, error) { + systemInformation, err := h.getSystemInfo(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get UUID: %w", err) + } + + nodeUUID := systemInformation.TypedSpec().UUID + + if nodeUUID == "" { + return nil, fmt.Errorf("machine UUID is not populated %s", nodeUUID) } // primitive entropy check counts := map[rune]int{} - for _, s := range h.nodeUUID { + for _, s := range nodeUUID { counts[s]++ - if counts[s] > len(h.nodeUUID)/2 { - return nil, fmt.Errorf("machine UUID %s entropy check failed", h.nodeUUID) + if counts[s] > len(nodeUUID)/2 { + return nil, fmt.Errorf("machine UUID %s entropy check failed", nodeUUID) } } - return encryption.NewKey(h.slot, []byte(h.nodeUUID+h.partitionLabel)), nil + return encryption.NewKey(h.slot, []byte(nodeUUID+h.partitionLabel)), nil } diff --git a/internal/pkg/encryption/keys/options.go b/internal/pkg/encryption/keys/options.go index 7d75f52453..2f9a52f7f3 100644 --- a/internal/pkg/encryption/keys/options.go +++ b/internal/pkg/encryption/keys/options.go @@ -4,13 +4,15 @@ package keys +import "github.com/siderolabs/talos/internal/pkg/encryption/helpers" + // KeyOption represents key option callback used in KeyHandler.GetKey func. type KeyOption func(o *KeyOptions) error // KeyOptions set of options to be used in KeyHandler.GetKey func. type KeyOptions struct { - PartitionLabel string - NodeUUID string + PartitionLabel string + GetSystemInformation helpers.SystemInformationGetter } // WithPartitionLabel passes the partition label to the key handler. @@ -22,10 +24,10 @@ func WithPartitionLabel(label string) KeyOption { } } -// WithNodeUUID passes the node UUID to the key handler. -func WithNodeUUID(uuid string) KeyOption { +// WithSystemInformationGetter passes the node UUID to the key handler. +func WithSystemInformationGetter(getter helpers.SystemInformationGetter) KeyOption { return func(o *KeyOptions) error { - o.NodeUUID = uuid + o.GetSystemInformation = getter return nil } diff --git a/internal/pkg/mount/options.go b/internal/pkg/mount/options.go index 338604f22e..6a0202416c 100644 --- a/internal/pkg/mount/options.go +++ b/internal/pkg/mount/options.go @@ -7,7 +7,7 @@ package mount import ( "log" - "github.com/siderolabs/talos/internal/pkg/encryption" + "github.com/siderolabs/talos/internal/pkg/encryption/helpers" "github.com/siderolabs/talos/pkg/machinery/config/config" ) @@ -40,15 +40,15 @@ type Flags uint // Options is the functional options struct. type Options struct { - Loopback string - Prefix string - MountFlags Flags - PreMountHooks []Hook - PostUnmountHooks []Hook - Encryption config.Encryption - NodeParams encryption.NodeParams - Logger *log.Logger - ProjectQuota bool + Loopback string + Prefix string + MountFlags Flags + PreMountHooks []Hook + PostUnmountHooks []Hook + Encryption config.Encryption + SystemInformationGetter helpers.SystemInformationGetter + Logger *log.Logger + ProjectQuota bool } // Option is the functional option func. @@ -113,10 +113,10 @@ func WithProjectQuota(enable bool) Option { } } -// WithNodeParams node info used by the encryption handler. -func WithNodeParams(params encryption.NodeParams) Option { +// WithSystemInformationGetter the function to get system information on the node. +func WithSystemInformationGetter(getter helpers.SystemInformationGetter) Option { return func(args *Options) { - args.NodeParams = params + args.SystemInformationGetter = getter } } diff --git a/internal/pkg/mount/system.go b/internal/pkg/mount/system.go index abb50083db..36fdce2491 100644 --- a/internal/pkg/mount/system.go +++ b/internal/pkg/mount/system.go @@ -110,7 +110,7 @@ func SystemMountPointForLabel(ctx context.Context, device *blockdevice.BlockDevi device, part, o.Encryption, - o.NodeParams, + o.SystemInformationGetter, ) if err != nil { return nil, err @@ -123,7 +123,7 @@ func SystemMountPointForLabel(ctx context.Context, device *blockdevice.BlockDevi path string ) - if path, err = encryptionHandler.Open(context.TODO()); err != nil { + if path, err = encryptionHandler.Open(ctx); err != nil { return err } @@ -189,27 +189,13 @@ func SystemPartitionMount(ctx context.Context, r runtime.Runtime, logger *log.Lo return fmt.Errorf("failed to find device with partition labeled %s", label) } - systemInformation, err := r.GetSystemInformation(ctx) - if err != nil && !errors.Is(err, context.Canceled) && state.IsNotFoundError(err) { - return err - } - - if systemInformation != nil { - opts = append(opts, WithNodeParams(encryption.NodeParams{ - UUID: systemInformation.TypedSpec().UUID, - })) - } - - var encrypted bool - if r.Config() != nil && r.Config().Machine() != nil { encryptionConfig := r.Config().Machine().SystemDiskEncryption().Get(label) if encryptionConfig != nil { - encrypted = true - opts = append(opts, WithEncryptionConfig(encryptionConfig), + WithSystemInformationGetter(r.GetSystemInformation), ) } } @@ -239,6 +225,9 @@ func SystemPartitionMount(ctx context.Context, r runtime.Runtime, logger *log.Lo return } + o := NewDefaultOptions(opts...) + encrypted := o.Encryption != nil + // record mount as the resource mountStatus := runtimeres.NewMountStatus(v1alpha1.NamespaceName, label) mountStatus.TypedSpec().Source = mountpoint.Source()