mirror of
				https://github.com/siderolabs/talos.git
				synced 2025-10-31 16:31:13 +01:00 
			
		
		
		
	Bump go modules, adjust the code. New linter warnings. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
		
			
				
	
	
		
			142 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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 keys
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/tls"
 | |
| 	"encoding/base64"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/siderolabs/go-blockdevice/blockdevice/encryption"
 | |
| 	"github.com/siderolabs/go-blockdevice/blockdevice/encryption/luks"
 | |
| 	"github.com/siderolabs/go-blockdevice/blockdevice/encryption/token"
 | |
| 	"github.com/siderolabs/kms-client/api/kms"
 | |
| 	"google.golang.org/grpc"
 | |
| 	"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"
 | |
| )
 | |
| 
 | |
| // KMSToken is the userdata stored in the partition token metadata.
 | |
| type KMSToken struct {
 | |
| 	SealedData []byte `json:"sealedData"`
 | |
| }
 | |
| 
 | |
| // KMSKeyHandler seals token using KMS service.
 | |
| type KMSKeyHandler struct {
 | |
| 	KeyHandler
 | |
| 	kmsEndpoint   string
 | |
| 	getSystemInfo helpers.SystemInformationGetter
 | |
| }
 | |
| 
 | |
| // NewKMSKeyHandler creates new KMSKeyHandler.
 | |
| func NewKMSKeyHandler(key KeyHandler, kmsEndpoint string, getSystemInfo helpers.SystemInformationGetter) (*KMSKeyHandler, error) {
 | |
| 	return &KMSKeyHandler{
 | |
| 		KeyHandler:    key,
 | |
| 		kmsEndpoint:   kmsEndpoint,
 | |
| 		getSystemInfo: getSystemInfo,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // NewKey implements Handler interface.
 | |
| func (h *KMSKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {
 | |
| 	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
 | |
| 	defer cancel()
 | |
| 
 | |
| 	conn, err := h.getConn()
 | |
| 	if err != nil {
 | |
| 		return nil, nil, fmt.Errorf("error dialing KMS endpoint %q: %w", h.kmsEndpoint, err)
 | |
| 	}
 | |
| 
 | |
| 	client := kms.NewKMSServiceClient(conn)
 | |
| 
 | |
| 	key := make([]byte, 32)
 | |
| 	if _, err = io.ReadFull(rand.Reader, key); err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	systemInformation, err := h.getSystemInfo(ctx)
 | |
| 	if err != nil {
 | |
| 		return nil, nil, err
 | |
| 	}
 | |
| 
 | |
| 	resp, err := client.Seal(ctx, &kms.Request{
 | |
| 		NodeUuid: systemInformation.TypedSpec().UUID,
 | |
| 		Data:     key,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, nil, fmt.Errorf("failed to seal KMS passphrase, slot %d: %w", h.Slot(), err)
 | |
| 	}
 | |
| 
 | |
| 	token := &luks.Token[*KMSToken]{
 | |
| 		Type: TokenTypeKMS,
 | |
| 		UserData: &KMSToken{
 | |
| 			SealedData: resp.Data,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	return encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(key))), token, nil
 | |
| }
 | |
| 
 | |
| // GetKey implements Handler interface.
 | |
| func (h *KMSKeyHandler) GetKey(ctx context.Context, t token.Token) (*encryption.Key, error) {
 | |
| 	token, ok := t.(*luks.Token[*KMSToken])
 | |
| 	if !ok {
 | |
| 		return nil, ErrTokenInvalid
 | |
| 	}
 | |
| 
 | |
| 	ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
 | |
| 	defer cancel()
 | |
| 
 | |
| 	conn, err := h.getConn()
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error dialing KMS endpoint %q: %w", h.kmsEndpoint, err)
 | |
| 	}
 | |
| 
 | |
| 	client := kms.NewKMSServiceClient(conn)
 | |
| 
 | |
| 	systemInformation, err := h.getSystemInfo(ctx)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	resp, err := client.Unseal(ctx, &kms.Request{
 | |
| 		NodeUuid: systemInformation.TypedSpec().UUID,
 | |
| 		Data:     token.UserData.SealedData,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("failed to unseal KMS passphrase, slot %d: %w", h.Slot(), err)
 | |
| 	}
 | |
| 
 | |
| 	return encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(resp.Data))), nil
 | |
| }
 | |
| 
 | |
| func (h *KMSKeyHandler) getConn() (*grpc.ClientConn, error) {
 | |
| 	var transportCredentials credentials.TransportCredentials
 | |
| 
 | |
| 	endpoint, err := endpoint.Parse(h.kmsEndpoint)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if endpoint.Insecure {
 | |
| 		transportCredentials = insecure.NewCredentials()
 | |
| 	} else {
 | |
| 		transportCredentials = credentials.NewTLS(&tls.Config{})
 | |
| 	}
 | |
| 
 | |
| 	return grpc.NewClient(
 | |
| 		endpoint.Host,
 | |
| 		grpc.WithTransportCredentials(transportCredentials),
 | |
| 		grpc.WithSharedWriteBuffer(true),
 | |
| 	)
 | |
| }
 |