mirror of
https://github.com/lingble/talos.git
synced 2025-11-02 13:38:12 +00:00
feat: implement ephemeral partition encryption
This PR introduces the first part of disk encryption support. New config section `systemDiskEncryption` was added into MachineConfig. For now it contains only Ephemeral partition encryption. Encryption itself supports two kinds of keys for now: - node id deterministic key. - static key which is hardcoded in the config and mainly used for test purposes. Talosctl cluster create can now be told to encrypt ephemeral partition by using `--encrypt-ephemeral` flag. Additionally: - updated pkgs library version. - changed Dockefile to copy cryptsetup deps from pkgs. Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
This commit is contained in:
committed by
talos-bot
parent
e5bd35ae3c
commit
58ff2c9808
@@ -358,16 +358,24 @@ local integration_cilium = Step("e2e-cilium-1.8.5", target="e2e-qemu", privilege
|
||||
"SHORT_INTEGRATION_TEST": "yes",
|
||||
"CUSTOM_CNI_URL": "https://raw.githubusercontent.com/cilium/cilium/v1.8.5/install/kubernetes/quick-install.yaml",
|
||||
"REGISTRY": local_registry,
|
||||
"CLUSTER_CIDR": 2,
|
||||
});
|
||||
local integration_uefi = Step("e2e-uefi", target="e2e-qemu", privileged=true, depends_on=[integration_cilium], environment={
|
||||
"SHORT_INTEGRATION_TEST": "yes",
|
||||
"WITH_UEFI": "true",
|
||||
"CLUSTER_CIDR": 3,
|
||||
"REGISTRY": local_registry,
|
||||
});
|
||||
local integration_disk_image = Step("e2e-disk-image", target="e2e-qemu", privileged=true, depends_on=[integration_uefi], environment={
|
||||
"SHORT_INTEGRATION_TEST": "yes",
|
||||
"USE_DISK_IMAGE": "true",
|
||||
"REGISTRY": local_registry,
|
||||
"CLUSTER_CIDR": 4,
|
||||
});
|
||||
local integration_disk_encryption = Step("e2e-encrypted", target="e2e-qemu", privileged=true, depends_on=[integration_disk_image], environment={
|
||||
"WITH_DISK_ENCRYPTION": "true",
|
||||
"REGISTRY": local_registry,
|
||||
"CLUSTER_CIDR": 5,
|
||||
});
|
||||
|
||||
local push_edge = {
|
||||
@@ -403,13 +411,13 @@ local integration_pipelines = [
|
||||
Pipeline('integration-qemu', default_pipeline_steps + [integration_qemu, push_edge]) + integration_trigger(['integration-qemu']),
|
||||
Pipeline('integration-provision-0', default_pipeline_steps + [integration_provision_tests_prepare, integration_provision_tests_track_0]) + integration_trigger(['integration-provision', 'integration-provision-0']),
|
||||
Pipeline('integration-provision-1', default_pipeline_steps + [integration_provision_tests_prepare, integration_provision_tests_track_1]) + integration_trigger(['integration-provision', 'integration-provision-1']),
|
||||
Pipeline('integration-misc', default_pipeline_steps + [integration_cilium, integration_uefi, integration_disk_image]) + integration_trigger(['integration-misc']),
|
||||
Pipeline('integration-misc', default_pipeline_steps + [integration_cilium, integration_uefi, integration_disk_image, integration_disk_encryption]) + integration_trigger(['integration-misc']),
|
||||
|
||||
// cron pipelines, triggered on schedule events
|
||||
Pipeline('cron-integration-qemu', default_pipeline_steps + [integration_qemu, push_edge]) + cron_trigger(['thrice-daily', 'nightly']),
|
||||
Pipeline('cron-integration-provision-0', default_pipeline_steps + [integration_provision_tests_prepare, integration_provision_tests_track_0]) + cron_trigger(['thrice-daily', 'nightly']),
|
||||
Pipeline('cron-integration-provision-1', default_pipeline_steps + [integration_provision_tests_prepare, integration_provision_tests_track_1]) + cron_trigger(['thrice-daily', 'nightly']),
|
||||
Pipeline('cron-integration-misc', default_pipeline_steps + [integration_cilium, integration_uefi, integration_disk_image]) + cron_trigger(['thrice-daily', 'nightly']),
|
||||
Pipeline('cron-integration-misc', default_pipeline_steps + [integration_cilium, integration_uefi, integration_disk_image, integration_disk_encryption]) + cron_trigger(['thrice-daily', 'nightly']),
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ FROM ghcr.io/talos-systems/dosfstools:${PKGS} AS pkg-dosfstools
|
||||
FROM ghcr.io/talos-systems/eudev:${PKGS} AS pkg-eudev
|
||||
FROM ghcr.io/talos-systems/grub:${PKGS} AS pkg-grub
|
||||
FROM ghcr.io/talos-systems/iptables:${PKGS} AS pkg-iptables
|
||||
FROM ghcr.io/talos-systems/libjson-c:${PKGS} AS pkg-libjson-c
|
||||
FROM ghcr.io/talos-systems/libpopt:${PKGS} AS pkg-libpopt
|
||||
FROM ghcr.io/talos-systems/libressl:${PKGS} AS pkg-libressl
|
||||
FROM ghcr.io/talos-systems/libseccomp:${PKGS} AS pkg-libseccomp
|
||||
FROM ghcr.io/talos-systems/linux-firmware:${PKGS} AS pkg-linux-firmware
|
||||
@@ -358,6 +360,8 @@ COPY --from=pkg-containerd / /rootfs
|
||||
COPY --from=pkg-dosfstools / /rootfs
|
||||
COPY --from=pkg-eudev / /rootfs
|
||||
COPY --from=pkg-iptables / /rootfs
|
||||
COPY --from=pkg-libjson-c / /rootfs
|
||||
COPY --from=pkg-libpopt / /rootfs
|
||||
COPY --from=pkg-libressl / /rootfs
|
||||
COPY --from=pkg-libseccomp / /rootfs
|
||||
COPY --from=pkg-linux-firmware /lib/firmware/bnx2 /rootfs/lib/firmware/bnx2
|
||||
|
||||
@@ -510,7 +510,6 @@ func (m *Manifest) zeroDevice(device Device) (err error) {
|
||||
func (t *Target) Partition(pt *gpt.GPT, pos int, bd *blockdevice.BlockDevice) (err error) {
|
||||
if t.Skip {
|
||||
part := pt.Partitions().FindByName(t.Label)
|
||||
|
||||
if part != nil {
|
||||
log.Printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/encryption"
|
||||
talosnet "github.com/talos-systems/net"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
@@ -42,51 +43,52 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
talosconfig string
|
||||
nodeImage string
|
||||
nodeInstallImage string
|
||||
registryMirrors []string
|
||||
registryInsecure []string
|
||||
kubernetesVersion string
|
||||
nodeVmlinuzPath string
|
||||
nodeInitramfsPath string
|
||||
nodeISOPath string
|
||||
nodeDiskImagePath string
|
||||
applyConfigEnabled bool
|
||||
bootloaderEnabled bool
|
||||
uefiEnabled bool
|
||||
configDebug bool
|
||||
networkCIDR string
|
||||
networkMTU int
|
||||
networkIPv4 bool
|
||||
networkIPv6 bool
|
||||
wireguardCIDR string
|
||||
nameservers []string
|
||||
dnsDomain string
|
||||
workers int
|
||||
masters int
|
||||
clusterCpus string
|
||||
clusterMemory int
|
||||
clusterDiskSize int
|
||||
clusterDisks []string
|
||||
targetArch string
|
||||
clusterWait bool
|
||||
clusterWaitTimeout time.Duration
|
||||
forceInitNodeAsEndpoint bool
|
||||
forceEndpoint string
|
||||
inputDir string
|
||||
cniBinPath []string
|
||||
cniConfDir string
|
||||
cniCacheDir string
|
||||
cniBundleURL string
|
||||
ports string
|
||||
dockerHostIP string
|
||||
withInitNode bool
|
||||
customCNIUrl string
|
||||
crashdumpOnFailure bool
|
||||
skipKubeconfig bool
|
||||
skipInjectingConfig bool
|
||||
talosVersion string
|
||||
talosconfig string
|
||||
nodeImage string
|
||||
nodeInstallImage string
|
||||
registryMirrors []string
|
||||
registryInsecure []string
|
||||
kubernetesVersion string
|
||||
nodeVmlinuzPath string
|
||||
nodeInitramfsPath string
|
||||
nodeISOPath string
|
||||
nodeDiskImagePath string
|
||||
applyConfigEnabled bool
|
||||
bootloaderEnabled bool
|
||||
uefiEnabled bool
|
||||
configDebug bool
|
||||
networkCIDR string
|
||||
networkMTU int
|
||||
networkIPv4 bool
|
||||
networkIPv6 bool
|
||||
wireguardCIDR string
|
||||
nameservers []string
|
||||
dnsDomain string
|
||||
workers int
|
||||
masters int
|
||||
clusterCpus string
|
||||
clusterMemory int
|
||||
clusterDiskSize int
|
||||
clusterDisks []string
|
||||
targetArch string
|
||||
clusterWait bool
|
||||
clusterWaitTimeout time.Duration
|
||||
forceInitNodeAsEndpoint bool
|
||||
forceEndpoint string
|
||||
inputDir string
|
||||
cniBinPath []string
|
||||
cniConfDir string
|
||||
cniCacheDir string
|
||||
cniBundleURL string
|
||||
ports string
|
||||
dockerHostIP string
|
||||
withInitNode bool
|
||||
customCNIUrl string
|
||||
crashdumpOnFailure bool
|
||||
skipKubeconfig bool
|
||||
skipInjectingConfig bool
|
||||
talosVersion string
|
||||
encryptEphemeralPartition bool
|
||||
)
|
||||
|
||||
// createCmd represents the cluster up command.
|
||||
@@ -304,6 +306,22 @@ func create(ctx context.Context) (err error) {
|
||||
genOptions = append(genOptions, generate.WithVersionContract(versionContract))
|
||||
}
|
||||
|
||||
if encryptEphemeralPartition {
|
||||
genOptions = append(genOptions, generate.WithSystemDiskEncryption(
|
||||
&v1alpha1.SystemDiskEncryptionConfig{
|
||||
EphemeralPartition: &v1alpha1.EncryptionConfig{
|
||||
EncryptionProvider: encryption.LUKS2,
|
||||
EncryptionKeys: []*v1alpha1.EncryptionKey{
|
||||
{
|
||||
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
|
||||
KeySlot: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
defaultInternalLB, defaultEndpoint := provisioner.GetLoadBalancers(request.Network)
|
||||
|
||||
if defaultInternalLB == "" {
|
||||
@@ -701,6 +719,7 @@ func init() {
|
||||
createCmd.Flags().BoolVar(&crashdumpOnFailure, "crashdump", false, "print debug crashdump to stderr when cluster startup fails")
|
||||
createCmd.Flags().BoolVar(&skipKubeconfig, "skip-kubeconfig", false, "skip merging kubeconfig from the created cluster")
|
||||
createCmd.Flags().BoolVar(&skipInjectingConfig, "skip-injecting-config", false, "skip injecting config from embedded metadata server, write config files to current directory")
|
||||
createCmd.Flags().BoolVar(&encryptEphemeralPartition, "encrypt-ephemeral", false, "enable ephemeral partition encryption")
|
||||
createCmd.Flags().StringVar(&talosVersion, "talos-version", "", "the desired Talos version to generate config for (if not set, defaults to image version)")
|
||||
Cmd.AddCommand(createCmd)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ source ./hack/test/e2e.sh
|
||||
|
||||
PROVISIONER=qemu
|
||||
CLUSTER_NAME=e2e-${PROVISIONER}
|
||||
CLUSTER_CIDR=${CLUSTER_CIDR:-1}
|
||||
|
||||
case "${CI:-false}" in
|
||||
true)
|
||||
@@ -45,6 +46,15 @@ case "${USE_DISK_IMAGE:-false}" in
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${WITH_DISK_ENCRYPTION:-false}" in
|
||||
false)
|
||||
DISK_ENCRYPTION_FLAG=""
|
||||
;;
|
||||
*)
|
||||
DISK_ENCRYPTION_FLAG="--encrypt-ephemeral"
|
||||
;;
|
||||
esac
|
||||
|
||||
function create_cluster {
|
||||
build_registry_mirrors
|
||||
|
||||
@@ -55,7 +65,7 @@ function create_cluster {
|
||||
--mtu 1450 \
|
||||
--memory 2048 \
|
||||
--cpus 2.0 \
|
||||
--cidr 172.20.1.0/24 \
|
||||
--cidr 172.20.${CLUSTER_CIDR}.0/24 \
|
||||
--user-disk /var/lib/extra:100MB \
|
||||
--user-disk /var/lib/p1:100MB:/var/lib/p2:100MB \
|
||||
--install-image ${REGISTRY:-ghcr.io}/talos-systems/installer:${INSTALLER_TAG} \
|
||||
@@ -63,11 +73,12 @@ function create_cluster {
|
||||
--cni-bundle-url ${ARTIFACTS}/talosctl-cni-bundle-'${ARCH}'.tar.gz \
|
||||
--crashdump \
|
||||
${DISK_IMAGE_FLAG} \
|
||||
${DISK_ENCRYPTION_FLAG} \
|
||||
${REGISTRY_MIRROR_FLAGS} \
|
||||
${QEMU_FLAGS} \
|
||||
${CUSTOM_CNI_FLAG}
|
||||
|
||||
"${TALOSCTL}" config node 172.20.1.2
|
||||
"${TALOSCTL}" config node 172.20.${CLUSTER_CIDR}.2
|
||||
}
|
||||
|
||||
function destroy_cluster() {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/talos-systems/talos/pkg/machinery/client"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
)
|
||||
@@ -179,6 +180,129 @@ func (suite *ApplyConfigSuite) TestApplyOnReboot() {
|
||||
suite.Require().NoError(err, "failed to apply deferred configuration (node %q): %w", node)
|
||||
}
|
||||
|
||||
// TestApplyConfigRotateEncryptionSecrets verify key rotation by sequential apply config calls.
|
||||
func (suite *ApplyConfigSuite) TestApplyConfigRotateEncryptionSecrets() {
|
||||
suite.T().Skip("skip: this test is not stable yet")
|
||||
|
||||
node := suite.RandomDiscoveredNode(machine.TypeJoin)
|
||||
suite.ClearConnectionRefused(suite.ctx, node)
|
||||
|
||||
nodeCtx := client.WithNodes(suite.ctx, node)
|
||||
provider, err := suite.readConfigFromNode(nodeCtx)
|
||||
|
||||
suite.Assert().NoError(err)
|
||||
|
||||
encryption := provider.Machine().SystemDiskEncryption().Get(constants.EphemeralPartitionLabel)
|
||||
|
||||
if encryption == nil {
|
||||
suite.T().Skip("skipped in not encrypted mode")
|
||||
}
|
||||
|
||||
suite.WaitForBootDone(suite.ctx)
|
||||
|
||||
cfg, ok := encryption.(*v1alpha1.EncryptionConfig)
|
||||
suite.Assert().True(ok)
|
||||
|
||||
keySets := [][]*v1alpha1.EncryptionKey{
|
||||
{
|
||||
{
|
||||
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
|
||||
KeySlot: 0,
|
||||
},
|
||||
{
|
||||
KeyStatic: &v1alpha1.EncryptionKeyStatic{
|
||||
KeyData: "AlO93jayutOpsDxDS=-",
|
||||
},
|
||||
KeySlot: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
KeyStatic: &v1alpha1.EncryptionKeyStatic{
|
||||
KeyData: "AlO93jayutOpsDxDS=-",
|
||||
},
|
||||
KeySlot: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
|
||||
KeySlot: 0,
|
||||
},
|
||||
{
|
||||
KeyStatic: &v1alpha1.EncryptionKeyStatic{
|
||||
KeyData: "AlO93jayutOpsDxDS=-",
|
||||
},
|
||||
KeySlot: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
|
||||
KeySlot: 0,
|
||||
},
|
||||
{
|
||||
KeyStatic: &v1alpha1.EncryptionKeyStatic{
|
||||
KeyData: "1js4nfhvneJJsak=GVN4Inf5gh",
|
||||
},
|
||||
KeySlot: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, keys := range keySets {
|
||||
cfg.EncryptionKeys = keys
|
||||
|
||||
data, err := provider.Bytes()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error {
|
||||
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
// It is expected that the connection will EOF here, so just log the error
|
||||
suite.Assert().Nilf("failed to apply configuration (node %q): %w", node, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, assertRebootedRebootTimeout)
|
||||
|
||||
// Verify configuration change
|
||||
var newProvider config.Provider
|
||||
|
||||
suite.Require().Nilf(retry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(func() error {
|
||||
newProvider, err = suite.readConfigFromNode(nodeCtx)
|
||||
if err != nil {
|
||||
return retry.ExpectedError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}), "failed to read updated configuration from node %q: %w", node, err)
|
||||
|
||||
e := newProvider.Machine().SystemDiskEncryption().Get(constants.EphemeralPartitionLabel)
|
||||
|
||||
for i, k := range e.Keys() {
|
||||
if keys[i].KeyStatic == nil {
|
||||
suite.Require().Nil(k.Static())
|
||||
} else {
|
||||
suite.Require().Equal(keys[i].Static().Key(), k.Static().Key())
|
||||
}
|
||||
|
||||
if keys[i].KeyNodeID == nil {
|
||||
suite.Require().Nil(k.NodeID())
|
||||
} else {
|
||||
suite.Require().NotNil(keys[i].NodeID())
|
||||
}
|
||||
|
||||
suite.Require().Equal(keys[i].Slot(), k.Slot())
|
||||
suite.Require().Equal(keys[i].Slot(), k.Slot())
|
||||
}
|
||||
|
||||
suite.WaitForBootDone(suite.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ApplyConfigSuite) readConfigFromNode(nodeCtx context.Context) (config.Provider, error) {
|
||||
// Load the current node machine config
|
||||
cfgData := new(bytes.Buffer)
|
||||
|
||||
254
internal/pkg/encryption/encryption.go
Normal file
254
internal/pkg/encryption/encryption.go
Normal file
@@ -0,0 +1,254 @@
|
||||
// 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 encryption provides modules for the partition encryption handling.
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/encryption"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/encryption/luks"
|
||||
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/encryption/keys"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||
)
|
||||
|
||||
// NewHandler creates new Handler.
|
||||
func NewHandler(device *blockdevice.BlockDevice, partition *gpt.Partition, encryptionConfig config.Encryption) (*Handler, error) {
|
||||
keys, err := getKeys(encryptionConfig, partition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var provider encryption.Provider
|
||||
|
||||
switch encryptionConfig.Kind() {
|
||||
case encryption.LUKS2:
|
||||
cipher, err := luks.ParseCipherKind(encryptionConfig.Cipher())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
provider = luks.New(
|
||||
cipher,
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown encryption kind %s", encryptionConfig.Kind())
|
||||
}
|
||||
|
||||
return &Handler{
|
||||
device: device,
|
||||
partition: partition,
|
||||
encryptionConfig: encryptionConfig,
|
||||
keys: keys,
|
||||
encryptionProvider: provider,
|
||||
}, 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
|
||||
keys []*encryption.Key
|
||||
encryptionProvider encryption.Provider
|
||||
encryptedPath string
|
||||
}
|
||||
|
||||
// Open encrypted partition.
|
||||
// nolint:gocyclo
|
||||
func (h *Handler) Open() (string, error) {
|
||||
partPath, err := h.partition.Path()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sb, err := h.partition.SuperBlock()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var path string
|
||||
|
||||
// encrypt if partition is not encrypted and empty
|
||||
if sb == nil {
|
||||
err = h.formatAndEncrypt(partPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if sb.Type() != h.encryptionConfig.Kind() {
|
||||
return "", fmt.Errorf("failed to encrypt the partition %s, because it is not empty", partPath)
|
||||
}
|
||||
|
||||
var k *encryption.Key
|
||||
|
||||
for _, k = range h.keys {
|
||||
path, err = h.encryptionProvider.Open(partPath, k)
|
||||
if err != nil {
|
||||
if err == encryption.ErrEncryptionKeyRejected {
|
||||
continue
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
return "", fmt.Errorf("failed to open encrypted device %s, no key matched", partPath)
|
||||
}
|
||||
|
||||
log.Printf("mapped encrypted partition %s -> %s", partPath, path)
|
||||
|
||||
if err = h.syncKeys(k, partPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
h.encryptedPath = path
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// Close encrypted partition.
|
||||
func (h *Handler) Close() error {
|
||||
if h.encryptedPath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := h.encryptionProvider.Close(h.encryptedPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("closed encrypted partition %s", h.encryptedPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) formatAndEncrypt(path string) error {
|
||||
log.Printf("encrypting the partition %s (%s)", path, h.partition.Name)
|
||||
|
||||
if len(h.keys) == 0 {
|
||||
return fmt.Errorf("no encryption keys found")
|
||||
}
|
||||
|
||||
key := h.keys[0]
|
||||
|
||||
err := h.encryptionProvider.Encrypt(path, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, extraKey := range h.keys[1:] {
|
||||
if err = h.encryptionProvider.AddKey(path, key, extraKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func (h *Handler) syncKeys(k *encryption.Key, path string) error {
|
||||
keyslots, err := h.encryptionProvider.ReadKeyslots(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
visited := map[string]bool{}
|
||||
|
||||
for _, key := range h.keys {
|
||||
slot := fmt.Sprintf("%d", key.Slot)
|
||||
visited[slot] = true
|
||||
// no need to update the key which we already detected as unchanged
|
||||
if k.Slot == key.Slot {
|
||||
continue
|
||||
}
|
||||
|
||||
// keyslot exists
|
||||
if _, ok := keyslots.Keyslots[slot]; ok {
|
||||
if err = h.updateKey(k, key, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("updated encryption key at slot %d", key.Slot)
|
||||
} else {
|
||||
// keyslot does not exist so just add the key
|
||||
if err = h.encryptionProvider.AddKey(path, k, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("added encryption key to slot %d", key.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup deleted key slots
|
||||
for slot := range keyslots.Keyslots {
|
||||
if !visited[slot] {
|
||||
s, err := strconv.ParseInt(slot, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = h.encryptionProvider.RemoveKey(path, int(s), k); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("removed key at slot %d", k.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) updateKey(existingKey, newKey *encryption.Key, path string) error {
|
||||
if valid, err := h.encryptionProvider.CheckKey(path, newKey); err != nil {
|
||||
return err
|
||||
} else if !valid {
|
||||
// re-add the key to the slot
|
||||
err = h.encryptionProvider.RemoveKey(path, newKey.Slot, existingKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to drop old key during key update %w", err)
|
||||
}
|
||||
|
||||
err = h.encryptionProvider.AddKey(path, existingKey, newKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add new key during key update %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getKeys(encryptionConfig config.Encryption, partition *gpt.Partition) ([]*encryption.Key, error) {
|
||||
encryptionKeys := make([]*encryption.Key, len(encryptionConfig.Keys()))
|
||||
|
||||
for i, cfg := range encryptionConfig.Keys() {
|
||||
handler, err := keys.NewHandler(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k, err := handler.GetKey(keys.WithPartitionLabel(partition.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encryptionKeys[i] = encryption.NewKey(cfg.Slot(), k)
|
||||
}
|
||||
|
||||
//nolint:scopelint
|
||||
sort.Slice(encryptionKeys, func(i, j int) bool { return encryptionKeys[i].Slot < encryptionKeys[j].Slot })
|
||||
|
||||
return encryptionKeys, nil
|
||||
}
|
||||
14
internal/pkg/encryption/encryption_test.go
Normal file
14
internal/pkg/encryption/encryption_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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 encryption_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
||||
34
internal/pkg/encryption/keys/keys.go
Normal file
34
internal/pkg/encryption/keys/keys.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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 contains various encryption KeyHandler implementations.
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||
)
|
||||
|
||||
// NewHandler creates a new key handler depending on key handler kind.
|
||||
func NewHandler(key config.EncryptionKey) (Handler, error) {
|
||||
switch {
|
||||
case key.Static() != nil:
|
||||
k := key.Static().Key()
|
||||
if k == nil {
|
||||
return nil, fmt.Errorf("static key must have key data defined")
|
||||
}
|
||||
|
||||
return NewStaticKeyHandler(k)
|
||||
case key.NodeID() != nil:
|
||||
return NewNodeIDKeyHandler()
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to create key handler: malformed config")
|
||||
}
|
||||
|
||||
// Handler represents an interface for fetching encryption keys.
|
||||
type Handler interface {
|
||||
GetKey(options ...KeyOption) ([]byte, error)
|
||||
}
|
||||
57
internal/pkg/encryption/keys/nodeid.go
Normal file
57
internal/pkg/encryption/keys/nodeid.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/talos-systems/go-smbios/smbios"
|
||||
)
|
||||
|
||||
// NodeIDKeyHandler generates the key based on current node information
|
||||
// and provided template string.
|
||||
type NodeIDKeyHandler struct {
|
||||
}
|
||||
|
||||
// NewNodeIDKeyHandler creates new NodeIDKeyHandler.
|
||||
func NewNodeIDKeyHandler() (*NodeIDKeyHandler, error) {
|
||||
return &NodeIDKeyHandler{}, nil
|
||||
}
|
||||
|
||||
// GetKey implements KeyHandler interface.
|
||||
func (h *NodeIDKeyHandler) GetKey(options ...KeyOption) ([]byte, error) {
|
||||
opts, err := NewDefaultOptions(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := smbios.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
machineUUID, err := s.SystemInformation().UUID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if machineUUID == uuid.Nil {
|
||||
return nil, fmt.Errorf("machine UUID is not populated %s", machineUUID)
|
||||
}
|
||||
|
||||
id := machineUUID.String()
|
||||
|
||||
// primitive entropy check
|
||||
counts := map[rune]int{}
|
||||
for _, s := range id {
|
||||
counts[s]++
|
||||
if counts[s] > len(id)/2 {
|
||||
return nil, fmt.Errorf("machine UUID %s entropy check failed", machineUUID)
|
||||
}
|
||||
}
|
||||
|
||||
return []byte(id + opts.PartitionLabel), nil
|
||||
}
|
||||
36
internal/pkg/encryption/keys/options.go
Normal file
36
internal/pkg/encryption/keys/options.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// WithPartitionLabel passes the partition label in to GetKey function.
|
||||
func WithPartitionLabel(label string) KeyOption {
|
||||
return func(o *KeyOptions) error {
|
||||
o.PartitionLabel = label
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultOptions creates new KeyOptions.
|
||||
func NewDefaultOptions(options []KeyOption) (*KeyOptions, error) {
|
||||
var opts KeyOptions
|
||||
|
||||
for _, o := range options {
|
||||
err := o(&opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &opts, nil
|
||||
}
|
||||
22
internal/pkg/encryption/keys/static.go
Normal file
22
internal/pkg/encryption/keys/static.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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
|
||||
|
||||
// StaticKeyHandler just handles the static key value all the time.
|
||||
type StaticKeyHandler struct {
|
||||
key []byte
|
||||
}
|
||||
|
||||
// NewStaticKeyHandler creates new EphemeralKeyHandler.
|
||||
func NewStaticKeyHandler(key []byte) (*StaticKeyHandler, error) {
|
||||
return &StaticKeyHandler{
|
||||
key: key,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetKey implements KeyHandler interface.
|
||||
func (h *StaticKeyHandler) GetKey(options ...KeyOption) ([]byte, error) {
|
||||
return h.key, nil
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
package mount
|
||||
|
||||
import "github.com/talos-systems/talos/pkg/machinery/config"
|
||||
|
||||
const (
|
||||
// ReadOnly is a flag for setting the mount point as readonly.
|
||||
ReadOnly Flags = 1 << iota
|
||||
@@ -29,6 +31,7 @@ type Options struct {
|
||||
MountFlags Flags
|
||||
PreMountHooks []Hook
|
||||
PostUnmountHooks []Hook
|
||||
Encryption config.Encryption
|
||||
}
|
||||
|
||||
// Option is the functional option func.
|
||||
@@ -72,6 +75,13 @@ func WithPostUnmountHooks(hooks ...Hook) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithEncryptionConfig partition encryption configuration.
|
||||
func WithEncryptionConfig(cfg config.Encryption) Option {
|
||||
return func(args *Options) {
|
||||
args.Encryption = cfg
|
||||
}
|
||||
}
|
||||
|
||||
// Hook represents pre/post mount hook.
|
||||
type Hook func(p *Point) error
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk"
|
||||
"github.com/talos-systems/talos/internal/pkg/encryption"
|
||||
"github.com/talos-systems/talos/internal/pkg/partition"
|
||||
"github.com/talos-systems/talos/pkg/machinery/config"
|
||||
"github.com/talos-systems/talos/pkg/machinery/constants"
|
||||
)
|
||||
|
||||
@@ -89,8 +91,46 @@ func SystemMountPointForLabel(device *blockdevice.BlockDevice, label string, opt
|
||||
return nil, err
|
||||
}
|
||||
|
||||
o := NewDefaultOptions(opts...)
|
||||
|
||||
preMountHooks := []Hook{}
|
||||
|
||||
if o.Encryption != nil {
|
||||
encryptionHandler, err := encryption.NewHandler(
|
||||
device,
|
||||
part,
|
||||
o.Encryption,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preMountHooks = append(preMountHooks,
|
||||
func(p *Point) error {
|
||||
var (
|
||||
err error
|
||||
path string
|
||||
)
|
||||
|
||||
if path, err = encryptionHandler.Open(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.source = path
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
opts = append(opts,
|
||||
WithPostUnmountHooks(
|
||||
func(p *Point) error {
|
||||
return encryptionHandler.Close()
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Format the partition if it does not have any filesystem
|
||||
preMountHooks = append(preMountHooks, func(p *Point) error {
|
||||
sb, err := filesystem.Probe(p.source)
|
||||
@@ -132,6 +172,16 @@ func SystemPartitionMount(r runtime.Runtime, label string, opts ...Option) (err
|
||||
return fmt.Errorf("failed to find device with partition labeled %s", label)
|
||||
}
|
||||
|
||||
var encryptionConfig config.Encryption
|
||||
|
||||
if r.Config() != nil && r.Config().Machine() != nil {
|
||||
encryptionConfig = r.Config().Machine().SystemDiskEncryption().Get(label)
|
||||
}
|
||||
|
||||
if encryptionConfig != nil {
|
||||
opts = append(opts, WithEncryptionConfig(encryptionConfig))
|
||||
}
|
||||
|
||||
mountpoint, err := SystemMountPointForLabel(device.BlockDevice, label, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -45,6 +45,7 @@ type MachineConfig interface {
|
||||
Kubelet() Kubelet
|
||||
Sysctls() map[string]string
|
||||
Registries() Registries
|
||||
SystemDiskEncryption() SystemDiskEncryption
|
||||
}
|
||||
|
||||
// Disk represents the options available for partitioning, formatting, and
|
||||
@@ -342,3 +343,31 @@ type CoreDNS interface {
|
||||
type AdminKubeconfig interface {
|
||||
CertLifetime() time.Duration
|
||||
}
|
||||
|
||||
// EncryptionKey defines settings for the partition encryption key handling.
|
||||
type EncryptionKey interface {
|
||||
Static() EncryptionKeyStatic
|
||||
NodeID() EncryptionKeyNodeID
|
||||
Slot() int
|
||||
}
|
||||
|
||||
// EncryptionKeyStatic ephemeral encryption key.
|
||||
type EncryptionKeyStatic interface {
|
||||
Key() []byte
|
||||
}
|
||||
|
||||
// EncryptionKeyNodeID deterministically generated encryption key.
|
||||
type EncryptionKeyNodeID interface {
|
||||
}
|
||||
|
||||
// Encryption defines settings for the partition encryption.
|
||||
type Encryption interface {
|
||||
Kind() string
|
||||
Cipher() string
|
||||
Keys() []EncryptionKey
|
||||
}
|
||||
|
||||
// SystemDiskEncryption accumulates settings for all system partitions encryption.
|
||||
type SystemDiskEncryption interface {
|
||||
Get(label string) Encryption
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
|
||||
)
|
||||
|
||||
// NewConfigBundle returns a new bundle
|
||||
// NewConfigBundle returns a new bundle.
|
||||
// nolint: gocyclo
|
||||
func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {
|
||||
options := DefaultOptions()
|
||||
|
||||
@@ -80,9 +80,10 @@ type Input struct {
|
||||
NetworkConfig *v1alpha1.NetworkConfig
|
||||
CNIConfig *v1alpha1.CNIConfig
|
||||
|
||||
RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig
|
||||
RegistryConfig map[string]*v1alpha1.RegistryConfig
|
||||
MachineDisks []*v1alpha1.MachineDisk
|
||||
RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig
|
||||
RegistryConfig map[string]*v1alpha1.RegistryConfig
|
||||
MachineDisks []*v1alpha1.MachineDisk
|
||||
SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig
|
||||
|
||||
Debug bool
|
||||
Persist bool
|
||||
@@ -454,28 +455,29 @@ func NewInput(clustername, endpoint, kubernetesVersion string, secrets *SecretsB
|
||||
}
|
||||
|
||||
input = &Input{
|
||||
Certs: secrets.Certs,
|
||||
ControlPlaneEndpoint: endpoint,
|
||||
PodNet: []string{podNet},
|
||||
ServiceNet: []string{serviceNet},
|
||||
ServiceDomain: options.DNSDomain,
|
||||
ClusterName: clustername,
|
||||
KubernetesVersion: kubernetesVersion,
|
||||
Secrets: secrets.Secrets,
|
||||
TrustdInfo: secrets.TrustdInfo,
|
||||
AdditionalSubjectAltNames: additionalSubjectAltNames,
|
||||
AdditionalMachineCertSANs: additionalMachineCertSANs,
|
||||
InstallDisk: options.InstallDisk,
|
||||
InstallImage: options.InstallImage,
|
||||
InstallExtraKernelArgs: options.InstallExtraKernelArgs,
|
||||
NetworkConfig: options.NetworkConfig,
|
||||
CNIConfig: options.CNIConfig,
|
||||
RegistryMirrors: options.RegistryMirrors,
|
||||
RegistryConfig: options.RegistryConfig,
|
||||
Debug: options.Debug,
|
||||
Persist: options.Persist,
|
||||
AllowSchedulingOnMasters: options.AllowSchedulingOnMasters,
|
||||
MachineDisks: options.MachineDisks,
|
||||
Certs: secrets.Certs,
|
||||
ControlPlaneEndpoint: endpoint,
|
||||
PodNet: []string{podNet},
|
||||
ServiceNet: []string{serviceNet},
|
||||
ServiceDomain: options.DNSDomain,
|
||||
ClusterName: clustername,
|
||||
KubernetesVersion: kubernetesVersion,
|
||||
Secrets: secrets.Secrets,
|
||||
TrustdInfo: secrets.TrustdInfo,
|
||||
AdditionalSubjectAltNames: additionalSubjectAltNames,
|
||||
AdditionalMachineCertSANs: additionalMachineCertSANs,
|
||||
InstallDisk: options.InstallDisk,
|
||||
InstallImage: options.InstallImage,
|
||||
InstallExtraKernelArgs: options.InstallExtraKernelArgs,
|
||||
NetworkConfig: options.NetworkConfig,
|
||||
CNIConfig: options.CNIConfig,
|
||||
RegistryMirrors: options.RegistryMirrors,
|
||||
RegistryConfig: options.RegistryConfig,
|
||||
Debug: options.Debug,
|
||||
Persist: options.Persist,
|
||||
AllowSchedulingOnMasters: options.AllowSchedulingOnMasters,
|
||||
MachineDisks: options.MachineDisks,
|
||||
SystemDiskEncryptionConfig: options.SystemDiskEncryptionConfig,
|
||||
}
|
||||
|
||||
return input, nil
|
||||
|
||||
@@ -38,7 +38,8 @@ func initUd(in *Input) (*v1alpha1.Config, error) {
|
||||
RegistryMirrors: in.RegistryMirrors,
|
||||
RegistryConfig: in.RegistryConfig,
|
||||
},
|
||||
MachineDisks: in.MachineDisks,
|
||||
MachineDisks: in.MachineDisks,
|
||||
MachineSystemDiskEncryption: in.SystemDiskEncryptionConfig,
|
||||
}
|
||||
|
||||
certSANs := in.GetAPIServerSANs()
|
||||
|
||||
@@ -39,7 +39,8 @@ func workerUd(in *Input) (*v1alpha1.Config, error) {
|
||||
RegistryMirrors: in.RegistryMirrors,
|
||||
RegistryConfig: in.RegistryConfig,
|
||||
},
|
||||
MachineDisks: in.MachineDisks,
|
||||
MachineDisks: in.MachineDisks,
|
||||
MachineSystemDiskEncryption: in.SystemDiskEncryptionConfig,
|
||||
}
|
||||
|
||||
controlPlaneURL, err := url.Parse(in.ControlPlaneEndpoint)
|
||||
|
||||
@@ -163,23 +163,33 @@ func WithVersionContract(versionContract *config.VersionContract) GenOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSystemDiskEncryption specifies encryption settings for the system disk partitions.
|
||||
func WithSystemDiskEncryption(cfg *v1alpha1.SystemDiskEncryptionConfig) GenOption {
|
||||
return func(o *GenOptions) error {
|
||||
o.SystemDiskEncryptionConfig = cfg
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GenOptions describes generate parameters.
|
||||
type GenOptions struct {
|
||||
EndpointList []string
|
||||
InstallDisk string
|
||||
InstallImage string
|
||||
InstallExtraKernelArgs []string
|
||||
AdditionalSubjectAltNames []string
|
||||
NetworkConfig *v1alpha1.NetworkConfig
|
||||
CNIConfig *v1alpha1.CNIConfig
|
||||
RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig
|
||||
RegistryConfig map[string]*v1alpha1.RegistryConfig
|
||||
DNSDomain string
|
||||
Debug bool
|
||||
Persist bool
|
||||
AllowSchedulingOnMasters bool
|
||||
MachineDisks []*v1alpha1.MachineDisk
|
||||
VersionContract *config.VersionContract
|
||||
EndpointList []string
|
||||
InstallDisk string
|
||||
InstallImage string
|
||||
InstallExtraKernelArgs []string
|
||||
AdditionalSubjectAltNames []string
|
||||
NetworkConfig *v1alpha1.NetworkConfig
|
||||
CNIConfig *v1alpha1.CNIConfig
|
||||
RegistryMirrors map[string]*v1alpha1.RegistryMirrorConfig
|
||||
RegistryConfig map[string]*v1alpha1.RegistryConfig
|
||||
DNSDomain string
|
||||
Debug bool
|
||||
Persist bool
|
||||
AllowSchedulingOnMasters bool
|
||||
MachineDisks []*v1alpha1.MachineDisk
|
||||
VersionContract *config.VersionContract
|
||||
SystemDiskEncryptionConfig *v1alpha1.SystemDiskEncryptionConfig
|
||||
}
|
||||
|
||||
// DefaultGenOptions returns default options.
|
||||
|
||||
@@ -233,6 +233,15 @@ func (m *MachineConfig) Registries() config.Registries {
|
||||
return &m.MachineRegistries
|
||||
}
|
||||
|
||||
// SystemDiskEncryption implements the config.Provider interface.
|
||||
func (m *MachineConfig) SystemDiskEncryption() config.SystemDiskEncryption {
|
||||
if m.MachineSystemDiskEncryption == nil {
|
||||
return &SystemDiskEncryptionConfig{}
|
||||
}
|
||||
|
||||
return m.MachineSystemDiskEncryption
|
||||
}
|
||||
|
||||
// Image implements the config.Provider interface.
|
||||
func (k *KubeletConfig) Image() string {
|
||||
image := k.KubeletImage
|
||||
@@ -1179,3 +1188,65 @@ func (p *DiskPartition) Size() uint64 {
|
||||
func (p *DiskPartition) MountPoint() string {
|
||||
return p.DiskMountPoint
|
||||
}
|
||||
|
||||
// Kind implements the config.Provider interface.
|
||||
func (e *EncryptionConfig) Kind() string {
|
||||
return e.EncryptionProvider
|
||||
}
|
||||
|
||||
// Cipher implements the config.Provider interface.
|
||||
func (e *EncryptionConfig) Cipher() string {
|
||||
return e.EncryptionCipher
|
||||
}
|
||||
|
||||
// Keys implements the config.Provider interface.
|
||||
func (e *EncryptionConfig) Keys() []config.EncryptionKey {
|
||||
keys := make([]config.EncryptionKey, len(e.EncryptionKeys))
|
||||
|
||||
for i, key := range e.EncryptionKeys {
|
||||
keys[i] = key
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// Static implements the config.Provider interface.
|
||||
func (e *EncryptionKey) Static() config.EncryptionKeyStatic {
|
||||
if e.KeyStatic == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e.KeyStatic
|
||||
}
|
||||
|
||||
// NodeID implements the config.Provider interface.
|
||||
func (e *EncryptionKey) NodeID() config.EncryptionKeyNodeID {
|
||||
if e.KeyNodeID == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e.KeyNodeID
|
||||
}
|
||||
|
||||
// Slot implements the config.Provider interface.
|
||||
func (e *EncryptionKey) Slot() int {
|
||||
return e.KeySlot
|
||||
}
|
||||
|
||||
// Key implements the config.Provider interface.
|
||||
func (e *EncryptionKeyStatic) Key() []byte {
|
||||
return []byte(e.KeyData)
|
||||
}
|
||||
|
||||
// Get implements the config.Provider interface.
|
||||
func (e *SystemDiskEncryptionConfig) Get(label string) config.Encryption {
|
||||
if label == constants.EphemeralPartitionLabel {
|
||||
if e.EphemeralPartition == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return e.EphemeralPartition
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -198,6 +198,18 @@ var (
|
||||
"net.ipv4.ip_forward": "0",
|
||||
}
|
||||
|
||||
machineSystemDiskEncryptionExample = &SystemDiskEncryptionConfig{
|
||||
EphemeralPartition: &EncryptionConfig{
|
||||
EncryptionProvider: "luks2",
|
||||
EncryptionKeys: []*EncryptionKey{
|
||||
{
|
||||
KeyNodeID: &EncryptionKeyNodeID{},
|
||||
KeySlot: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
clusterConfigExample = struct {
|
||||
ControlPlane *ControlPlaneConfig `yaml:"controlPlane"`
|
||||
ClusterName string `yaml:"clusterName"`
|
||||
@@ -533,6 +545,12 @@ type MachineConfig struct {
|
||||
// examples:
|
||||
// - value: machineConfigRegistriesExample
|
||||
MachineRegistries RegistriesConfig `yaml:"registries,omitempty"`
|
||||
// description: |
|
||||
// Machine system disk encryption configuration.
|
||||
// Defines each system partition encryption parameters.
|
||||
// examples:
|
||||
// - value: machineSystemDiskEncryptionExample
|
||||
MachineSystemDiskEncryption *SystemDiskEncryptionConfig `yaml:"systemDiskEncryption,omitempty"`
|
||||
}
|
||||
|
||||
// ClusterConfig represents the cluster-wide config values.
|
||||
@@ -1051,6 +1069,45 @@ type DiskPartition struct {
|
||||
DiskMountPoint string `yaml:"mountpoint,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptionConfig represents partition encryption settings.
|
||||
type EncryptionConfig struct {
|
||||
// description: >
|
||||
// Encryption provider to use for the encryption.
|
||||
// examples:
|
||||
// - value: '"luks2"'
|
||||
EncryptionProvider string `yaml:"provider"`
|
||||
// description: >
|
||||
// Defines the encryption keys generation and storage method.
|
||||
EncryptionKeys []*EncryptionKey `yaml:"keys"`
|
||||
// description: >
|
||||
// Cipher kind to use for the encryption.
|
||||
// Depends on the encryption provider.
|
||||
EncryptionCipher string `yaml:"cipher,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptionKey represents configuration for disk encryption key.
|
||||
type EncryptionKey struct {
|
||||
// description: >
|
||||
// Key which value is stored in the configuration file.
|
||||
KeyStatic *EncryptionKeyStatic `yaml:"static,omitempty"`
|
||||
// description: >
|
||||
// Deterministically generated key from the node UUID and PartitionLabel.
|
||||
KeyNodeID *EncryptionKeyNodeID `yaml:"nodeID,omitempty"`
|
||||
// description: >
|
||||
// Key slot number for luks2 encryption.
|
||||
KeySlot int `yaml:"slot"`
|
||||
}
|
||||
|
||||
// EncryptionKeyStatic represents throw away key type.
|
||||
type EncryptionKeyStatic struct {
|
||||
// description: >
|
||||
// Defines the static passphrase value.
|
||||
KeyData string `yaml:"passphrase,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.
|
||||
type EncryptionKeyNodeID struct{}
|
||||
|
||||
// Env represents a set of environment variables.
|
||||
type Env = map[string]string
|
||||
|
||||
@@ -1396,3 +1453,10 @@ type RegistryTLSConfig struct {
|
||||
// Skip TLS server certificate verification (not recommended).
|
||||
TLSInsecureSkipVerify bool `yaml:"insecureSkipVerify,omitempty"`
|
||||
}
|
||||
|
||||
// SystemDiskEncryptionConfig specifies system disk partitions encryption settings.
|
||||
type SystemDiskEncryptionConfig struct {
|
||||
// description: |
|
||||
// Ephemeral partition encryption.
|
||||
EphemeralPartition *EncryptionConfig `yaml:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
@@ -11,41 +11,46 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ConfigDoc encoder.Doc
|
||||
MachineConfigDoc encoder.Doc
|
||||
ClusterConfigDoc encoder.Doc
|
||||
KubeletConfigDoc encoder.Doc
|
||||
NetworkConfigDoc encoder.Doc
|
||||
InstallConfigDoc encoder.Doc
|
||||
TimeConfigDoc encoder.Doc
|
||||
RegistriesConfigDoc encoder.Doc
|
||||
PodCheckpointerDoc encoder.Doc
|
||||
CoreDNSDoc encoder.Doc
|
||||
EndpointDoc encoder.Doc
|
||||
ControlPlaneConfigDoc encoder.Doc
|
||||
APIServerConfigDoc encoder.Doc
|
||||
ControllerManagerConfigDoc encoder.Doc
|
||||
ProxyConfigDoc encoder.Doc
|
||||
SchedulerConfigDoc encoder.Doc
|
||||
EtcdConfigDoc encoder.Doc
|
||||
ClusterNetworkConfigDoc encoder.Doc
|
||||
CNIConfigDoc encoder.Doc
|
||||
AdminKubeconfigConfigDoc encoder.Doc
|
||||
MachineDiskDoc encoder.Doc
|
||||
DiskPartitionDoc encoder.Doc
|
||||
MachineFileDoc encoder.Doc
|
||||
ExtraHostDoc encoder.Doc
|
||||
DeviceDoc encoder.Doc
|
||||
DHCPOptionsDoc encoder.Doc
|
||||
DeviceWireguardConfigDoc encoder.Doc
|
||||
DeviceWireguardPeerDoc encoder.Doc
|
||||
BondDoc encoder.Doc
|
||||
VlanDoc encoder.Doc
|
||||
RouteDoc encoder.Doc
|
||||
RegistryMirrorConfigDoc encoder.Doc
|
||||
RegistryConfigDoc encoder.Doc
|
||||
RegistryAuthConfigDoc encoder.Doc
|
||||
RegistryTLSConfigDoc encoder.Doc
|
||||
ConfigDoc encoder.Doc
|
||||
MachineConfigDoc encoder.Doc
|
||||
ClusterConfigDoc encoder.Doc
|
||||
KubeletConfigDoc encoder.Doc
|
||||
NetworkConfigDoc encoder.Doc
|
||||
InstallConfigDoc encoder.Doc
|
||||
TimeConfigDoc encoder.Doc
|
||||
RegistriesConfigDoc encoder.Doc
|
||||
PodCheckpointerDoc encoder.Doc
|
||||
CoreDNSDoc encoder.Doc
|
||||
EndpointDoc encoder.Doc
|
||||
ControlPlaneConfigDoc encoder.Doc
|
||||
APIServerConfigDoc encoder.Doc
|
||||
ControllerManagerConfigDoc encoder.Doc
|
||||
ProxyConfigDoc encoder.Doc
|
||||
SchedulerConfigDoc encoder.Doc
|
||||
EtcdConfigDoc encoder.Doc
|
||||
ClusterNetworkConfigDoc encoder.Doc
|
||||
CNIConfigDoc encoder.Doc
|
||||
AdminKubeconfigConfigDoc encoder.Doc
|
||||
MachineDiskDoc encoder.Doc
|
||||
DiskPartitionDoc encoder.Doc
|
||||
EncryptionConfigDoc encoder.Doc
|
||||
EncryptionKeyDoc encoder.Doc
|
||||
EncryptionKeyStaticDoc encoder.Doc
|
||||
EncryptionKeyNodeIDDoc encoder.Doc
|
||||
MachineFileDoc encoder.Doc
|
||||
ExtraHostDoc encoder.Doc
|
||||
DeviceDoc encoder.Doc
|
||||
DHCPOptionsDoc encoder.Doc
|
||||
DeviceWireguardConfigDoc encoder.Doc
|
||||
DeviceWireguardPeerDoc encoder.Doc
|
||||
BondDoc encoder.Doc
|
||||
VlanDoc encoder.Doc
|
||||
RouteDoc encoder.Doc
|
||||
RegistryMirrorConfigDoc encoder.Doc
|
||||
RegistryConfigDoc encoder.Doc
|
||||
RegistryAuthConfigDoc encoder.Doc
|
||||
RegistryTLSConfigDoc encoder.Doc
|
||||
SystemDiskEncryptionConfigDoc encoder.Doc
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -107,7 +112,7 @@ func init() {
|
||||
FieldName: "machine",
|
||||
},
|
||||
}
|
||||
MachineConfigDoc.Fields = make([]encoder.Doc, 13)
|
||||
MachineConfigDoc.Fields = make([]encoder.Doc, 14)
|
||||
MachineConfigDoc.Fields[0].Name = "type"
|
||||
MachineConfigDoc.Fields[0].Type = "string"
|
||||
MachineConfigDoc.Fields[0].Note = ""
|
||||
@@ -213,6 +218,13 @@ func init() {
|
||||
MachineConfigDoc.Fields[12].Comments[encoder.LineComment] = "Used to configure the machine's container image registry mirrors."
|
||||
|
||||
MachineConfigDoc.Fields[12].AddExample("", machineConfigRegistriesExample)
|
||||
MachineConfigDoc.Fields[13].Name = "systemDiskEncryption"
|
||||
MachineConfigDoc.Fields[13].Type = "SystemDiskEncryptionConfig"
|
||||
MachineConfigDoc.Fields[13].Note = ""
|
||||
MachineConfigDoc.Fields[13].Description = "Machine system disk encryption configuration.\nDefines each system partition encryption parameters."
|
||||
MachineConfigDoc.Fields[13].Comments[encoder.LineComment] = "Machine system disk encryption configuration."
|
||||
|
||||
MachineConfigDoc.Fields[13].AddExample("", machineSystemDiskEncryptionExample)
|
||||
|
||||
ClusterConfigDoc.Type = "ClusterConfig"
|
||||
ClusterConfigDoc.Comments[encoder.LineComment] = "ClusterConfig represents the cluster-wide config values."
|
||||
@@ -912,6 +924,87 @@ func init() {
|
||||
DiskPartitionDoc.Fields[1].Description = "Where to mount the partition."
|
||||
DiskPartitionDoc.Fields[1].Comments[encoder.LineComment] = "Where to mount the partition."
|
||||
|
||||
EncryptionConfigDoc.Type = "EncryptionConfig"
|
||||
EncryptionConfigDoc.Comments[encoder.LineComment] = "EncryptionConfig represents partition encryption settings."
|
||||
EncryptionConfigDoc.Description = "EncryptionConfig represents partition encryption settings."
|
||||
EncryptionConfigDoc.AppearsIn = []encoder.Appearance{
|
||||
{
|
||||
TypeName: "SystemDiskEncryptionConfig",
|
||||
FieldName: "ephemeral",
|
||||
},
|
||||
}
|
||||
EncryptionConfigDoc.Fields = make([]encoder.Doc, 3)
|
||||
EncryptionConfigDoc.Fields[0].Name = "provider"
|
||||
EncryptionConfigDoc.Fields[0].Type = "string"
|
||||
EncryptionConfigDoc.Fields[0].Note = ""
|
||||
EncryptionConfigDoc.Fields[0].Description = "Encryption provider to use for the encryption."
|
||||
EncryptionConfigDoc.Fields[0].Comments[encoder.LineComment] = "Encryption provider to use for the encryption."
|
||||
|
||||
EncryptionConfigDoc.Fields[0].AddExample("", "luks2")
|
||||
EncryptionConfigDoc.Fields[1].Name = "keys"
|
||||
EncryptionConfigDoc.Fields[1].Type = "[]EncryptionKey"
|
||||
EncryptionConfigDoc.Fields[1].Note = ""
|
||||
EncryptionConfigDoc.Fields[1].Description = "Defines the encryption keys generation and storage method."
|
||||
EncryptionConfigDoc.Fields[1].Comments[encoder.LineComment] = "Defines the encryption keys generation and storage method."
|
||||
EncryptionConfigDoc.Fields[2].Name = "cipher"
|
||||
EncryptionConfigDoc.Fields[2].Type = "string"
|
||||
EncryptionConfigDoc.Fields[2].Note = ""
|
||||
EncryptionConfigDoc.Fields[2].Description = "Cipher kind to use for the encryption. Depends on the encryption provider."
|
||||
EncryptionConfigDoc.Fields[2].Comments[encoder.LineComment] = "Cipher kind to use for the encryption. Depends on the encryption provider."
|
||||
|
||||
EncryptionKeyDoc.Type = "EncryptionKey"
|
||||
EncryptionKeyDoc.Comments[encoder.LineComment] = "EncryptionKey represents configuration for disk encryption key."
|
||||
EncryptionKeyDoc.Description = "EncryptionKey represents configuration for disk encryption key."
|
||||
EncryptionKeyDoc.AppearsIn = []encoder.Appearance{
|
||||
{
|
||||
TypeName: "EncryptionConfig",
|
||||
FieldName: "keys",
|
||||
},
|
||||
}
|
||||
EncryptionKeyDoc.Fields = make([]encoder.Doc, 3)
|
||||
EncryptionKeyDoc.Fields[0].Name = "static"
|
||||
EncryptionKeyDoc.Fields[0].Type = "EncryptionKeyStatic"
|
||||
EncryptionKeyDoc.Fields[0].Note = ""
|
||||
EncryptionKeyDoc.Fields[0].Description = "Key which value is stored in the configuration file."
|
||||
EncryptionKeyDoc.Fields[0].Comments[encoder.LineComment] = "Key which value is stored in the configuration file."
|
||||
EncryptionKeyDoc.Fields[1].Name = "nodeID"
|
||||
EncryptionKeyDoc.Fields[1].Type = "EncryptionKeyNodeID"
|
||||
EncryptionKeyDoc.Fields[1].Note = ""
|
||||
EncryptionKeyDoc.Fields[1].Description = "Deterministically generated key from the node UUID and PartitionLabel."
|
||||
EncryptionKeyDoc.Fields[1].Comments[encoder.LineComment] = "Deterministically generated key from the node UUID and PartitionLabel."
|
||||
EncryptionKeyDoc.Fields[2].Name = "slot"
|
||||
EncryptionKeyDoc.Fields[2].Type = "int"
|
||||
EncryptionKeyDoc.Fields[2].Note = ""
|
||||
EncryptionKeyDoc.Fields[2].Description = "Key slot number for luks2 encryption."
|
||||
EncryptionKeyDoc.Fields[2].Comments[encoder.LineComment] = "Key slot number for luks2 encryption."
|
||||
|
||||
EncryptionKeyStaticDoc.Type = "EncryptionKeyStatic"
|
||||
EncryptionKeyStaticDoc.Comments[encoder.LineComment] = "EncryptionKeyStatic represents throw away key type."
|
||||
EncryptionKeyStaticDoc.Description = "EncryptionKeyStatic represents throw away key type."
|
||||
EncryptionKeyStaticDoc.AppearsIn = []encoder.Appearance{
|
||||
{
|
||||
TypeName: "EncryptionKey",
|
||||
FieldName: "static",
|
||||
},
|
||||
}
|
||||
EncryptionKeyStaticDoc.Fields = make([]encoder.Doc, 1)
|
||||
EncryptionKeyStaticDoc.Fields[0].Name = "passphrase"
|
||||
EncryptionKeyStaticDoc.Fields[0].Type = "string"
|
||||
EncryptionKeyStaticDoc.Fields[0].Note = ""
|
||||
EncryptionKeyStaticDoc.Fields[0].Description = "Defines the static passphrase value."
|
||||
EncryptionKeyStaticDoc.Fields[0].Comments[encoder.LineComment] = "Defines the static passphrase value."
|
||||
|
||||
EncryptionKeyNodeIDDoc.Type = "EncryptionKeyNodeID"
|
||||
EncryptionKeyNodeIDDoc.Comments[encoder.LineComment] = "EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel."
|
||||
EncryptionKeyNodeIDDoc.Description = "EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel."
|
||||
EncryptionKeyNodeIDDoc.AppearsIn = []encoder.Appearance{
|
||||
{
|
||||
TypeName: "EncryptionKey",
|
||||
FieldName: "nodeID",
|
||||
},
|
||||
}
|
||||
EncryptionKeyNodeIDDoc.Fields = make([]encoder.Doc, 0)
|
||||
|
||||
MachineFileDoc.Type = "MachineFile"
|
||||
MachineFileDoc.Comments[encoder.LineComment] = "MachineFile represents a file to write to disk."
|
||||
MachineFileDoc.Description = "MachineFile represents a file to write to disk."
|
||||
@@ -1473,6 +1566,24 @@ func init() {
|
||||
RegistryTLSConfigDoc.Fields[2].Note = ""
|
||||
RegistryTLSConfigDoc.Fields[2].Description = "Skip TLS server certificate verification (not recommended)."
|
||||
RegistryTLSConfigDoc.Fields[2].Comments[encoder.LineComment] = "Skip TLS server certificate verification (not recommended)."
|
||||
|
||||
SystemDiskEncryptionConfigDoc.Type = "SystemDiskEncryptionConfig"
|
||||
SystemDiskEncryptionConfigDoc.Comments[encoder.LineComment] = "SystemDiskEncryptionConfig specifies system disk partitions encryption settings."
|
||||
SystemDiskEncryptionConfigDoc.Description = "SystemDiskEncryptionConfig specifies system disk partitions encryption settings."
|
||||
|
||||
SystemDiskEncryptionConfigDoc.AddExample("", machineSystemDiskEncryptionExample)
|
||||
SystemDiskEncryptionConfigDoc.AppearsIn = []encoder.Appearance{
|
||||
{
|
||||
TypeName: "MachineConfig",
|
||||
FieldName: "systemDiskEncryption",
|
||||
},
|
||||
}
|
||||
SystemDiskEncryptionConfigDoc.Fields = make([]encoder.Doc, 1)
|
||||
SystemDiskEncryptionConfigDoc.Fields[0].Name = "ephemeral"
|
||||
SystemDiskEncryptionConfigDoc.Fields[0].Type = "EncryptionConfig"
|
||||
SystemDiskEncryptionConfigDoc.Fields[0].Note = ""
|
||||
SystemDiskEncryptionConfigDoc.Fields[0].Description = "Ephemeral partition encryption."
|
||||
SystemDiskEncryptionConfigDoc.Fields[0].Comments[encoder.LineComment] = "Ephemeral partition encryption."
|
||||
}
|
||||
|
||||
func (_ Config) Doc() *encoder.Doc {
|
||||
@@ -1563,6 +1674,22 @@ func (_ DiskPartition) Doc() *encoder.Doc {
|
||||
return &DiskPartitionDoc
|
||||
}
|
||||
|
||||
func (_ EncryptionConfig) Doc() *encoder.Doc {
|
||||
return &EncryptionConfigDoc
|
||||
}
|
||||
|
||||
func (_ EncryptionKey) Doc() *encoder.Doc {
|
||||
return &EncryptionKeyDoc
|
||||
}
|
||||
|
||||
func (_ EncryptionKeyStatic) Doc() *encoder.Doc {
|
||||
return &EncryptionKeyStaticDoc
|
||||
}
|
||||
|
||||
func (_ EncryptionKeyNodeID) Doc() *encoder.Doc {
|
||||
return &EncryptionKeyNodeIDDoc
|
||||
}
|
||||
|
||||
func (_ MachineFile) Doc() *encoder.Doc {
|
||||
return &MachineFileDoc
|
||||
}
|
||||
@@ -1615,6 +1742,10 @@ func (_ RegistryTLSConfig) Doc() *encoder.Doc {
|
||||
return &RegistryTLSConfigDoc
|
||||
}
|
||||
|
||||
func (_ SystemDiskEncryptionConfig) Doc() *encoder.Doc {
|
||||
return &SystemDiskEncryptionConfigDoc
|
||||
}
|
||||
|
||||
// GetConfigurationDoc returns documentation for the file ./v1alpha1_types_doc.go.
|
||||
func GetConfigurationDoc() *encoder.FileDoc {
|
||||
return &encoder.FileDoc{
|
||||
@@ -1643,6 +1774,10 @@ func GetConfigurationDoc() *encoder.FileDoc {
|
||||
&AdminKubeconfigConfigDoc,
|
||||
&MachineDiskDoc,
|
||||
&DiskPartitionDoc,
|
||||
&EncryptionConfigDoc,
|
||||
&EncryptionKeyDoc,
|
||||
&EncryptionKeyStaticDoc,
|
||||
&EncryptionKeyNodeIDDoc,
|
||||
&MachineFileDoc,
|
||||
&ExtraHostDoc,
|
||||
&DeviceDoc,
|
||||
@@ -1656,6 +1791,7 @@ func GetConfigurationDoc() *encoder.FileDoc {
|
||||
&RegistryConfigDoc,
|
||||
&RegistryAuthConfigDoc,
|
||||
&RegistryTLSConfigDoc,
|
||||
&SystemDiskEncryptionConfigDoc,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,28 @@ func (c *Config) Validate(mode config.RuntimeMode) error {
|
||||
result = multierror.Append(result, fmt.Errorf("%q is not a valid DNS name", c.ClusterConfig.ClusterNetwork.DNSDomain))
|
||||
}
|
||||
|
||||
for _, label := range []string{constants.EphemeralPartitionLabel} {
|
||||
encryptionConfig := c.MachineConfig.SystemDiskEncryption().Get(label)
|
||||
if encryptionConfig != nil {
|
||||
if len(encryptionConfig.Keys()) == 0 {
|
||||
result = multierror.Append(result, fmt.Errorf("no encryption keys provided for the ephemeral partition encryption"))
|
||||
}
|
||||
|
||||
slotsInUse := map[int]bool{}
|
||||
for _, key := range encryptionConfig.Keys() {
|
||||
if slotsInUse[key.Slot()] {
|
||||
result = multierror.Append(result, fmt.Errorf("encryption key slot %d is already in use", key.Slot()))
|
||||
}
|
||||
|
||||
slotsInUse[key.Slot()] = true
|
||||
|
||||
if key.NodeID() == nil && key.Static() == nil {
|
||||
result = multierror.Append(result, fmt.Errorf("encryption key at slot %d doesn't have any settings", key.Slot()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ talosctl cluster create [flags]
|
||||
--disk-image-path string disk image to use
|
||||
--dns-domain string the dns domain to use for cluster (default "cluster.local")
|
||||
--docker-host-ip string Host IP to forward exposed ports to (Docker provisioner only) (default "0.0.0.0")
|
||||
--encrypt-ephemeral enable ephemeral partition encryption
|
||||
--endpoint string use endpoint instead of provider defaults
|
||||
-p, --exposed-ports string Comma-separated list of ports/protocols to expose on init node. Ex -p <hostPort>:<containerPort>/<protocol (tcp or udp)> (Docker provisioner only)
|
||||
-h, --help help for create
|
||||
|
||||
@@ -658,6 +658,38 @@ registries:
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>systemDiskEncryption</code> <i><a href="#systemdiskencryptionconfig">SystemDiskEncryptionConfig</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Machine system disk encryption configuration.
|
||||
Defines each system partition encryption parameters.
|
||||
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
``` yaml
|
||||
systemDiskEncryption:
|
||||
# Ephemeral partition encryption.
|
||||
ephemeral:
|
||||
provider: luks2 # Encryption provider to use for the encryption.
|
||||
# Defines the encryption keys generation and storage method.
|
||||
keys:
|
||||
- # Deterministically generated key from the node UUID and PartitionLabel.
|
||||
nodeID: {}
|
||||
slot: 0 # Key slot number for luks2 encryption.
|
||||
```
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2693,6 +2725,167 @@ Where to mount the partition.
|
||||
|
||||
|
||||
|
||||
## EncryptionConfig
|
||||
EncryptionConfig represents partition encryption settings.
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#systemdiskencryptionconfig">SystemDiskEncryptionConfig</a>.ephemeral</code>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>provider</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Encryption provider to use for the encryption.
|
||||
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
``` yaml
|
||||
provider: luks2
|
||||
```
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>keys</code> <i>[]<a href="#encryptionkey">EncryptionKey</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Defines the encryption keys generation and storage method.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>cipher</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Cipher kind to use for the encryption. Depends on the encryption provider.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## EncryptionKey
|
||||
EncryptionKey represents configuration for disk encryption key.
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#encryptionconfig">EncryptionConfig</a>.keys</code>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>static</code> <i><a href="#encryptionkeystatic">EncryptionKeyStatic</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Key which value is stored in the configuration file.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>nodeID</code> <i><a href="#encryptionkeynodeid">EncryptionKeyNodeID</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Deterministically generated key from the node UUID and PartitionLabel.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>slot</code> <i>int</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Key slot number for luks2 encryption.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## EncryptionKeyStatic
|
||||
EncryptionKeyStatic represents throw away key type.
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#encryptionkey">EncryptionKey</a>.static</code>
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>passphrase</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Defines the static passphrase value.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## EncryptionKeyNodeID
|
||||
EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#encryptionkey">EncryptionKey</a>.nodeID</code>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## MachineFile
|
||||
MachineFile represents a file to write to disk.
|
||||
|
||||
@@ -4199,3 +4392,42 @@ Skip TLS server certificate verification (not recommended).
|
||||
|
||||
|
||||
|
||||
|
||||
## SystemDiskEncryptionConfig
|
||||
SystemDiskEncryptionConfig specifies system disk partitions encryption settings.
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#machineconfig">MachineConfig</a>.systemDiskEncryption</code>
|
||||
|
||||
|
||||
``` yaml
|
||||
# Ephemeral partition encryption.
|
||||
ephemeral:
|
||||
provider: luks2 # Encryption provider to use for the encryption.
|
||||
# Defines the encryption keys generation and storage method.
|
||||
keys:
|
||||
- # Deterministically generated key from the node UUID and PartitionLabel.
|
||||
nodeID: {}
|
||||
slot: 0 # Key slot number for luks2 encryption.
|
||||
```
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>ephemeral</code> <i><a href="#encryptionconfig">EncryptionConfig</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Ephemeral partition encryption.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user