fix: rewrite encryption system information flow

Pass getter to the key handler instead of already fetched node uuid.

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
This commit is contained in:
Artem Chernyshev 2023-07-10 17:16:16 +03:00
parent 3206db5289
commit cb226eec46
No known key found for this signature in database
GPG Key ID: 9B9D0328B57B443F
10 changed files with 98 additions and 81 deletions

View File

@ -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

View File

@ -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...)

View File

@ -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
}

View File

@ -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)

View File

@ -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")

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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()