Skip to content

Commit

Permalink
fix: rewrite encryption system information flow
Browse files Browse the repository at this point in the history
Pass getter to the key handler instead of already fetched node uuid.

Signed-off-by: Artem Chernyshev <[email protected]>
  • Loading branch information
Unix4ever committed Jul 10, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 3206db5 commit cb226ee
Showing 10 changed files with 98 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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...)
27 changes: 14 additions & 13 deletions internal/pkg/encryption/encryption.go
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions internal/pkg/encryption/helpers/helpers.go
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 7 additions & 7 deletions internal/pkg/encryption/keys/keys.go
Original file line number Diff line number Diff line change
@@ -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")
24 changes: 15 additions & 9 deletions internal/pkg/encryption/keys/kms.go
Original file line number Diff line number Diff line change
@@ -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 {
28 changes: 19 additions & 9 deletions internal/pkg/encryption/keys/nodeid.go
Original file line number Diff line number Diff line change
@@ -10,21 +10,24 @@ 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
// and provided template string.
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
}
12 changes: 7 additions & 5 deletions internal/pkg/encryption/keys/options.go
Original file line number Diff line number Diff line change
@@ -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
}
26 changes: 13 additions & 13 deletions internal/pkg/mount/options.go
Original file line number Diff line number Diff line change
@@ -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
}
}

Loading

0 comments on commit cb226ee

Please sign in to comment.