mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-26 22:11:38 +01:00
Dynamically map Kubernetes and Talos API ports to an available port on the host, so every cluster gets its own unique set of parts. As part of the changes, refactor the provision library and interfaces, dropping old weird interfaces replacing with (hopefully) much more descriprive names. Signed-off-by: Dmitry Sharshakov <dmitry.sharshakov@siderolabs.com> 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.Dial(
|
|
endpoint.Host,
|
|
grpc.WithTransportCredentials(transportCredentials),
|
|
grpc.WithSharedWriteBuffer(true),
|
|
)
|
|
}
|