mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-05 22:27:11 +02:00
feat: implement encryption locking to STATE
Fixes #10676 Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
parent
c1e65a3425
commit
a5f3000f2e
@ -88,6 +88,7 @@ message EncryptionKey {
|
||||
bytes static_passphrase = 3;
|
||||
string kms_endpoint = 4;
|
||||
bool tpm_check_secureboot_status_on_enroll = 5;
|
||||
bool lock_to_state = 6;
|
||||
}
|
||||
|
||||
// EncryptionSpec is the spec for volume encryption.
|
||||
|
@ -21,6 +21,11 @@ message CertSANSpec {
|
||||
string fqdn = 3;
|
||||
}
|
||||
|
||||
// EncryptionSaltSpec describes the salt.
|
||||
message EncryptionSaltSpec {
|
||||
bytes disk_salt = 1;
|
||||
}
|
||||
|
||||
// EtcdCertsSpec describes etcd certs secrets.
|
||||
message EtcdCertsSpec {
|
||||
common.PEMEncodedCertificateAndKey etcd = 1;
|
||||
|
@ -582,6 +582,12 @@ func create(ctx context.Context, ops createOps) error {
|
||||
EncryptionKeys: convertEncryptionKeys(keys),
|
||||
}
|
||||
|
||||
if spec.label != constants.StatePartitionLabel {
|
||||
for idx := range blockCfg.EncryptionSpec.EncryptionKeys {
|
||||
blockCfg.EncryptionSpec.EncryptionKeys[idx].KeyLockToSTATE = pointer.To(true)
|
||||
}
|
||||
}
|
||||
|
||||
ctr, err := container.New(blockCfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating container for %q volume: %w", spec.label, err)
|
||||
|
@ -132,6 +132,9 @@ Talos increases the boot partition size to 2 GiB to accommodate larger images (w
|
||||
description = """\
|
||||
Disk encryption for system volumes is now managed by the `VolumeConfig` machine configuration document.
|
||||
Legacy configuration in `valpha1` machine configuration is still supported.
|
||||
|
||||
New per-key option `lockToSTATE` is added to the `VolumeConfig` document, which allows to lock the volume encryption key to the secret salt in the `STATE` volume.
|
||||
So, if the `STATE` volume is wiped or replaced, the volume encryption key will not be usable anymore.
|
||||
"""
|
||||
|
||||
[make_deps]
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
)
|
||||
|
||||
func TestIdentityGenerate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var spec1, spec2 cluster.IdentitySpec
|
||||
|
||||
require.NoError(t, clusteradapter.IdentitySpec(&spec1).Generate())
|
||||
@ -29,6 +31,8 @@ func TestIdentityGenerate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIdentityConvertMachineID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
spec := cluster.IdentitySpec{
|
||||
NodeID: "sou7yy34ykX3n373Zw1DXKb8zD7UnyKT6HT3QDsGH6L",
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
// 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 secrets
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
// EncryptionSalt adapter provides encryption salt generation.
|
||||
//
|
||||
//nolint:revive,golint
|
||||
func EncryptionSalt(r *secrets.EncryptionSaltSpec) encryptionSalt {
|
||||
return encryptionSalt{
|
||||
EncryptionSaltSpec: r,
|
||||
}
|
||||
}
|
||||
|
||||
type encryptionSalt struct {
|
||||
*secrets.EncryptionSaltSpec
|
||||
}
|
||||
|
||||
// Generate new encryption salt.
|
||||
func (a encryptionSalt) Generate() error {
|
||||
buf := make([]byte, constants.DiskEncryptionSaltSize)
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.EncryptionSaltSpec.DiskSalt = buf
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
// 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 secrets_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
secretsadapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/secrets"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
func TestEncryptionSaltGenerate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var spec1, spec2 secrets.EncryptionSaltSpec
|
||||
|
||||
require.NoError(t, secretsadapter.EncryptionSalt(&spec1).Generate())
|
||||
require.NoError(t, secretsadapter.EncryptionSalt(&spec2).Generate())
|
||||
|
||||
assert.NotEqual(t, spec1, spec2)
|
||||
|
||||
assert.Len(t, spec1.DiskSalt, constants.DiskEncryptionSaltSize)
|
||||
}
|
6
internal/app/machined/pkg/adapters/secrets/secrets.go
Normal file
6
internal/app/machined/pkg/adapters/secrets/secrets.go
Normal file
@ -0,0 +1,6 @@
|
||||
// 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 secrets implements adapters wrapping resources to provide additional functionality.
|
||||
package secrets
|
@ -36,7 +36,7 @@ func Close(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext
|
||||
case block.EncryptionProviderLUKS2:
|
||||
encryptionConfig := volumeContext.Cfg.TypedSpec().Encryption
|
||||
|
||||
handler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.GetSystemInformation, volumeContext.TPMLocker)
|
||||
handler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.EncryptionHelpers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create encryption handler: %w", err)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func HandleEncryption(ctx context.Context, logger *zap.Logger, volumeContext Man
|
||||
case block.EncryptionProviderLUKS2:
|
||||
encryptionConfig := volumeContext.Cfg.TypedSpec().Encryption
|
||||
|
||||
handler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.GetSystemInformation, volumeContext.TPMLocker)
|
||||
handler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.EncryptionHelpers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create encryption handler: %w", err)
|
||||
}
|
||||
|
@ -7,14 +7,13 @@ package volumes
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"math"
|
||||
|
||||
"github.com/siderolabs/gen/optional"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption"
|
||||
blockpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/hardware"
|
||||
)
|
||||
|
||||
// CompareVolumeConfigs compares two volume configs in the proposed order of provisioning.
|
||||
@ -89,7 +88,6 @@ type ManagerContext struct {
|
||||
|
||||
DevicesReady bool
|
||||
PreviousWaveProvisioned bool
|
||||
GetSystemInformation func(context.Context) (*hardware.SystemInformation, error)
|
||||
TPMLocker func(context.Context, func() error) error
|
||||
EncryptionHelpers encryption.Helpers
|
||||
ShouldCloseVolume bool
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ func convertEncryptionConfiguration(in cfg.EncryptionConfig, out *block.VolumeCo
|
||||
|
||||
for i, key := range in.Keys() {
|
||||
out.Encryption.Keys[i].Slot = key.Slot()
|
||||
out.Encryption.Keys[i].LockToSTATE = key.LockToSTATE()
|
||||
|
||||
switch {
|
||||
case key.Static() != nil:
|
||||
|
@ -23,12 +23,15 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes"
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption"
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption/helpers"
|
||||
blockpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/proto"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/hardware"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/runtime"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
// VolumeManagerController manages volumes in the system, converting VolumeConfig resources to VolumeStatuses.
|
||||
@ -96,6 +99,12 @@ func (ctrl *VolumeManagerController) Inputs() []controller.Input {
|
||||
Type: hardware.PCRStatusType,
|
||||
Kind: controller.InputStrong,
|
||||
},
|
||||
{
|
||||
Namespace: secrets.NamespaceName,
|
||||
Type: secrets.EncryptionSaltType,
|
||||
ID: optional.Some(secrets.EncryptionSaltID),
|
||||
Kind: controller.InputWeak,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -374,19 +383,11 @@ func (ctrl *VolumeManagerController) Run(ctx context.Context, r controller.Runti
|
||||
Disks: diskSpecs,
|
||||
DevicesReady: devicesReady,
|
||||
PreviousWaveProvisioned: vc.TypedSpec().Provisioning.Wave <= fullyProvisionedWave,
|
||||
GetSystemInformation: func(ctx context.Context) (*hardware.SystemInformation, error) {
|
||||
systemInfo, err := safe.ReaderGetByID[*hardware.SystemInformation](ctx, r, hardware.SystemInformationID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return nil, fmt.Errorf("error fetching system information: %w", err)
|
||||
}
|
||||
|
||||
if systemInfo == nil {
|
||||
return nil, errors.New("system information not available")
|
||||
}
|
||||
|
||||
return systemInfo, nil
|
||||
EncryptionHelpers: encryption.Helpers{
|
||||
GetSystemInformation: ctrl.getSystemInformation(r),
|
||||
TPMLocker: hardware.LockPCRStatus(r, constants.UKIPCR, vc.Metadata().ID()),
|
||||
SaltGetter: ctrl.getSaltGetter(r),
|
||||
},
|
||||
TPMLocker: hardware.LockPCRStatus(r, constants.UKIPCR, vc.Metadata().ID()),
|
||||
ShouldCloseVolume: shouldCloseVolume,
|
||||
},
|
||||
); err != nil {
|
||||
@ -591,3 +592,33 @@ func (ctrl *VolumeManagerController) processVolumeConfig(ctx context.Context, lo
|
||||
prevPhase = volumeContext.Status.Phase
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *VolumeManagerController) getSystemInformation(r controller.Reader) helpers.SystemInformationGetter {
|
||||
return func(ctx context.Context) (*hardware.SystemInformation, error) {
|
||||
systemInfo, err := safe.ReaderGetByID[*hardware.SystemInformation](ctx, r, hardware.SystemInformationID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return nil, fmt.Errorf("error fetching system information: %w", err)
|
||||
}
|
||||
|
||||
if systemInfo == nil {
|
||||
return nil, errors.New("system information not available")
|
||||
}
|
||||
|
||||
return systemInfo, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *VolumeManagerController) getSaltGetter(r controller.Reader) helpers.SaltGetter {
|
||||
return func(ctx context.Context) ([]byte, error) {
|
||||
salt, err := safe.ReaderGetByID[*secrets.EncryptionSalt](ctx, r, secrets.EncryptionSaltID)
|
||||
if err != nil && !state.IsNotFoundError(err) {
|
||||
return nil, fmt.Errorf("error fetching encryption salt: %w", err)
|
||||
}
|
||||
|
||||
if salt == nil {
|
||||
return nil, errors.New("encryption salt not available")
|
||||
}
|
||||
|
||||
return salt.TypedSpec().DiskSalt, nil
|
||||
}
|
||||
}
|
||||
|
109
internal/app/machined/pkg/controllers/secrets/encryption_salt.go
Normal file
109
internal/app/machined/pkg/controllers/secrets/encryption_salt.go
Normal file
@ -0,0 +1,109 @@
|
||||
// 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 secrets
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/controller"
|
||||
"github.com/cosi-project/runtime/pkg/safe"
|
||||
"go.uber.org/zap"
|
||||
|
||||
secretsadapter "github.com/siderolabs/talos/internal/app/machined/pkg/adapters/secrets"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton"
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
// EncryptionSaltController manages secrets.EncryptionSalt in STATE.
|
||||
type EncryptionSaltController struct {
|
||||
stateMachine blockautomaton.VolumeMounterAutomaton
|
||||
}
|
||||
|
||||
// Name implements controller.Controller interface.
|
||||
func (ctrl *EncryptionSaltController) Name() string {
|
||||
return "secrets.EncryptionSaltController"
|
||||
}
|
||||
|
||||
// Inputs implements controller.Controller interface.
|
||||
func (ctrl *EncryptionSaltController) Inputs() []controller.Input {
|
||||
return []controller.Input{
|
||||
{
|
||||
Namespace: block.NamespaceName,
|
||||
Type: block.VolumeMountStatusType,
|
||||
Kind: controller.InputStrong,
|
||||
},
|
||||
{
|
||||
Namespace: block.NamespaceName,
|
||||
Type: block.VolumeMountRequestType,
|
||||
Kind: controller.InputDestroyReady,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs implements controller.Controller interface.
|
||||
func (ctrl *EncryptionSaltController) Outputs() []controller.Output {
|
||||
return []controller.Output{
|
||||
{
|
||||
Type: secrets.EncryptionSaltType,
|
||||
Kind: controller.OutputShared,
|
||||
},
|
||||
{
|
||||
Type: block.VolumeMountRequestType,
|
||||
Kind: controller.OutputShared,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run implements controller.Controller interface.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (ctrl *EncryptionSaltController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-r.EventCh():
|
||||
}
|
||||
|
||||
if ctrl.stateMachine == nil {
|
||||
ctrl.stateMachine = blockautomaton.NewVolumeMounter(ctrl.Name(), constants.StatePartitionLabel, ctrl.establishEncryptionSalt)
|
||||
}
|
||||
|
||||
if err := ctrl.stateMachine.Run(ctx, r, logger); err != nil {
|
||||
return fmt.Errorf("error running volume mounter machine: %w", err)
|
||||
}
|
||||
|
||||
r.ResetRestartBackoff()
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *EncryptionSaltController) establishEncryptionSalt(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {
|
||||
rootPath := mountStatus.TypedSpec().Target
|
||||
|
||||
var salt secrets.EncryptionSaltSpec
|
||||
|
||||
if err := controllers.LoadOrNewFromFile(filepath.Join(rootPath, constants.EncryptionSaltFilename), &salt, func(v *secrets.EncryptionSaltSpec) error {
|
||||
return secretsadapter.EncryptionSalt(v).Generate()
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error caching node identity: %w", err)
|
||||
}
|
||||
|
||||
if err := safe.WriterModify(ctx, r, secrets.NewEncryptionSalt(), func(r *secrets.EncryptionSalt) error {
|
||||
*r.TypedSpec() = salt
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("error modifying resource: %w", err)
|
||||
}
|
||||
|
||||
logger.Info("encryption salt established")
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
// 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 secrets_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest"
|
||||
secretsctrl "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/block"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/secrets"
|
||||
)
|
||||
|
||||
type EncryptionSaltSuite struct {
|
||||
ctest.DefaultSuite
|
||||
}
|
||||
|
||||
func (suite *EncryptionSaltSuite) TestDefault() {
|
||||
statePath := suite.T().TempDir()
|
||||
mountID := (&secretsctrl.EncryptionSaltController{}).Name() + "-" + constants.StatePartitionLabel
|
||||
|
||||
ctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {
|
||||
asrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)
|
||||
})
|
||||
|
||||
ctest.AssertNoResource[*secrets.EncryptionSalt](suite, secrets.EncryptionSaltID)
|
||||
|
||||
volumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)
|
||||
volumeMountStatus.TypedSpec().Target = statePath
|
||||
suite.Create(volumeMountStatus)
|
||||
|
||||
ctest.AssertResource(suite, secrets.EncryptionSaltID, func(*secrets.EncryptionSalt, *assert.Assertions) {})
|
||||
|
||||
ctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {
|
||||
asrt.True(vms.Metadata().Finalizers().Empty())
|
||||
})
|
||||
|
||||
suite.Destroy(volumeMountStatus)
|
||||
|
||||
ctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)
|
||||
|
||||
suite.Assert().FileExists(filepath.Join(statePath, constants.EncryptionSaltFilename), "encryption salt file should exist")
|
||||
|
||||
contents, err := os.ReadFile(filepath.Join(statePath, constants.EncryptionSaltFilename))
|
||||
suite.Require().NoError(err, "should be able to read encryption salt file")
|
||||
|
||||
log.Printf("contents: %q", contents)
|
||||
}
|
||||
|
||||
func (suite *EncryptionSaltSuite) TestLoad() {
|
||||
statePath := suite.T().TempDir()
|
||||
mountID := (&secretsctrl.EncryptionSaltController{}).Name() + "-" + constants.StatePartitionLabel
|
||||
|
||||
ctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {
|
||||
asrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)
|
||||
})
|
||||
|
||||
// using verbatim data here to make sure salt representation is supported in future version fo Talos
|
||||
suite.Require().NoError(os.WriteFile(filepath.Join(statePath, constants.EncryptionSaltFilename),
|
||||
[]byte("diskSalt:\n - 240\n - 180\n - 79\n - 128\n - 31\n - 0\n - 19\n - 124\n - 165\n - 74\n - 113\n - 220\n - 27\n - 83\n - 46\n - 74\n - 204\n - 190\n - 217\n - 96\n - 221\n - 2\n - 165\n - 98\n - 245\n - 36\n - 165\n - 151\n - 149\n - 66\n - 113\n - 16\n"), //nolint:lll
|
||||
0o600))
|
||||
|
||||
ctest.AssertNoResource[*secrets.EncryptionSalt](suite, secrets.EncryptionSaltID)
|
||||
|
||||
volumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)
|
||||
volumeMountStatus.TypedSpec().Target = statePath
|
||||
suite.Create(volumeMountStatus)
|
||||
|
||||
ctest.AssertResource(suite, secrets.EncryptionSaltID, func(encryptionSalt *secrets.EncryptionSalt, asrt *assert.Assertions) {
|
||||
asrt.Equal(
|
||||
[]byte{0xf0, 0xb4, 0x4f, 0x80, 0x1f, 0x0, 0x13, 0x7c, 0xa5, 0x4a, 0x71, 0xdc, 0x1b, 0x53, 0x2e, 0x4a, 0xcc, 0xbe, 0xd9, 0x60, 0xdd, 0x2, 0xa5, 0x62, 0xf5, 0x24, 0xa5, 0x97, 0x95, 0x42, 0x71, 0x10},
|
||||
encryptionSalt.TypedSpec().DiskSalt,
|
||||
)
|
||||
})
|
||||
|
||||
ctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {
|
||||
asrt.True(vms.Metadata().Finalizers().Empty())
|
||||
})
|
||||
|
||||
suite.Destroy(volumeMountStatus)
|
||||
|
||||
ctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)
|
||||
}
|
||||
|
||||
func TestEncryptionSaltSuite(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
suite.Run(t, &EncryptionSaltSuite{
|
||||
DefaultSuite: ctest.DefaultSuite{
|
||||
AfterSetup: func(suite *ctest.DefaultSuite) {
|
||||
suite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.EncryptionSaltController{}))
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
@ -378,6 +378,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error
|
||||
&runtimecontrollers.WatchdogTimerController{},
|
||||
&secrets.APICertSANsController{},
|
||||
&secrets.APIController{},
|
||||
&secrets.EncryptionSaltController{},
|
||||
&secrets.EtcdController{},
|
||||
secrets.NewKubeletController(),
|
||||
&secrets.KubernetesCertSANsController{},
|
||||
|
@ -232,6 +232,7 @@ func NewState() (*State, error) {
|
||||
&runtime.WatchdogTimerStatus{},
|
||||
&secrets.API{},
|
||||
&secrets.CertSAN{},
|
||||
&secrets.EncryptionSalt{},
|
||||
&secrets.Etcd{},
|
||||
&secrets.EtcdRoot{},
|
||||
&secrets.Kubelet{},
|
||||
|
@ -128,6 +128,8 @@ func (suite *ResetSuite) TestResetWithSpecEphemeral() {
|
||||
// TestResetWithSpecStateAndUserDisks resets state partition and user disks on the node.
|
||||
//
|
||||
// As ephemeral partition is not reset, so kubelet cert shouldn't change.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (suite *ResetSuite) TestResetWithSpecStateAndUserDisks() {
|
||||
if suite.Capabilities().SecureBooted {
|
||||
// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args
|
||||
@ -135,8 +137,25 @@ func (suite *ResetSuite) TestResetWithSpecStateAndUserDisks() {
|
||||
}
|
||||
|
||||
node := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)
|
||||
nodeCtx := client.WithNode(suite.ctx, node)
|
||||
|
||||
disks, err := suite.Client.Disks(client.WithNode(suite.ctx, node))
|
||||
suite.T().Logf("resetting STATE + user disk on node %s", node)
|
||||
|
||||
config, err := suite.ReadConfigFromNode(nodeCtx)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// check if EPHEMERAL is encrypted locked to STATE
|
||||
var lockedToState bool
|
||||
|
||||
if volume, ok := config.Volumes().ByName(constants.EphemeralPartitionLabel); ok && volume.Encryption() != nil {
|
||||
for _, key := range volume.Encryption().Keys() {
|
||||
if key.LockToSTATE() {
|
||||
lockedToState = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disks, err := suite.Client.Disks(nodeCtx)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NotEmpty(disks.Messages)
|
||||
|
||||
@ -160,6 +179,26 @@ func (suite *ResetSuite) TestResetWithSpecStateAndUserDisks() {
|
||||
},
|
||||
)
|
||||
|
||||
if !lockedToState {
|
||||
// if not locked to STATE, wipe will be successful
|
||||
suite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{
|
||||
Reboot: true,
|
||||
Graceful: true,
|
||||
SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{
|
||||
{
|
||||
Label: constants.StatePartitionLabel,
|
||||
Wipe: true,
|
||||
},
|
||||
},
|
||||
UserDisksToWipe: userDisksToWipe,
|
||||
}, true)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
suite.T().Logf("verifying that EPHEMERAL partition would fail to unlock after reset, as it is locked to STATE")
|
||||
|
||||
// if the EPHEMERAL partition is locked to STATE, it will fail to unlock after reset, so let's verify it
|
||||
suite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{
|
||||
Reboot: true,
|
||||
Graceful: true,
|
||||
@ -170,6 +209,27 @@ func (suite *ResetSuite) TestResetWithSpecStateAndUserDisks() {
|
||||
},
|
||||
},
|
||||
UserDisksToWipe: userDisksToWipe,
|
||||
}, false)
|
||||
|
||||
// wait for EPHEMERAL failure
|
||||
rtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,
|
||||
[]string{constants.EphemeralPartitionLabel},
|
||||
func(vs *block.VolumeStatus, asrt *assert.Assertions) {
|
||||
asrt.Equal(block.VolumePhaseFailed, vs.TypedSpec().Phase)
|
||||
asrt.Contains(vs.TypedSpec().ErrorMessage, "encryption key rejected")
|
||||
},
|
||||
)
|
||||
|
||||
// now reset EPHEMERAL
|
||||
suite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{
|
||||
Reboot: true,
|
||||
Graceful: false,
|
||||
SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{
|
||||
{
|
||||
Label: constants.EphemeralPartitionLabel,
|
||||
Wipe: true,
|
||||
},
|
||||
},
|
||||
}, true)
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,15 @@ import (
|
||||
|
||||
const keyHandlerTimeout = time.Second * 10
|
||||
|
||||
// Helpers provides helper methods for encryption handling.
|
||||
type Helpers struct {
|
||||
GetSystemInformation helpers.SystemInformationGetter
|
||||
TPMLocker helpers.TPMLockFunc
|
||||
SaltGetter helpers.SaltGetter
|
||||
}
|
||||
|
||||
// NewHandler creates new Handler.
|
||||
func NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, getSystemInformation helpers.SystemInformationGetter, tpmLocker helpers.TPMLockFunc) (*Handler, error) {
|
||||
func NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, helpers Helpers) (*Handler, error) {
|
||||
cipher, err := luks.ParseCipherKind(encryptionConfig.Cipher)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse cipher kind: %w", err)
|
||||
@ -60,8 +67,9 @@ func NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, getSyste
|
||||
for _, cfg := range encryptionConfig.Keys {
|
||||
handler, err := keys.NewHandler(cfg,
|
||||
keys.WithVolumeID(volumeID),
|
||||
keys.WithSystemInformationGetter(getSystemInformation),
|
||||
keys.WithTPMLocker(tpmLocker),
|
||||
keys.WithSystemInformationGetter(helpers.GetSystemInformation),
|
||||
keys.WithTPMLocker(helpers.TPMLocker),
|
||||
keys.WithSaltGetter(helpers.SaltGetter),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -81,6 +89,7 @@ func NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, getSyste
|
||||
return &Handler{
|
||||
encryptionProvider: provider,
|
||||
keyHandlers: keyHandlers,
|
||||
saltGetter: helpers.SaltGetter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -89,6 +98,7 @@ func NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, getSyste
|
||||
type Handler struct {
|
||||
encryptionProvider encryption.Provider
|
||||
keyHandlers []keys.Handler
|
||||
saltGetter helpers.SaltGetter
|
||||
}
|
||||
|
||||
// Open encrypted partition.
|
||||
|
@ -16,3 +16,6 @@ type SystemInformationGetter func(context.Context) (*hardware.SystemInformation,
|
||||
|
||||
// TPMLockFunc is a function that ensures that the TPM is locked and PCR state is as expected.
|
||||
type TPMLockFunc func(context.Context, func() error) error
|
||||
|
||||
// SaltGetter defines the closure which can be used in key handlers to get the encryption salt.
|
||||
type SaltGetter func(context.Context) ([]byte, error)
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
var errNoSystemInfoGetter = errors.New("the UUID getter is not set")
|
||||
|
||||
// NewHandler key using provided config.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func NewHandler(cfg block.EncryptionKey, options ...KeyOption) (Handler, error) {
|
||||
opts, err := NewDefaultOptions(options)
|
||||
if err != nil {
|
||||
@ -27,6 +29,8 @@ func NewHandler(cfg block.EncryptionKey, options ...KeyOption) (Handler, error)
|
||||
|
||||
key := KeyHandler{slot: cfg.Slot}
|
||||
|
||||
var handler Handler
|
||||
|
||||
switch cfg.Type {
|
||||
case block.EncryptionKeyStatic:
|
||||
k := cfg.StaticPassphrase
|
||||
@ -34,28 +38,44 @@ func NewHandler(cfg block.EncryptionKey, options ...KeyOption) (Handler, error)
|
||||
return nil, errors.New("static key must have key data defined")
|
||||
}
|
||||
|
||||
return NewStaticKeyHandler(key, k), nil
|
||||
handler = NewStaticKeyHandler(key, k)
|
||||
case block.EncryptionKeyNodeID:
|
||||
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.VolumeID, opts.GetSystemInformation), nil
|
||||
handler = NewNodeIDKeyHandler(key, opts.VolumeID, opts.GetSystemInformation)
|
||||
case block.EncryptionKeyKMS:
|
||||
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.KMSEndpoint, opts.GetSystemInformation)
|
||||
handler, err = NewKMSKeyHandler(key, cfg.KMSEndpoint, opts.GetSystemInformation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case block.EncryptionKeyTPM:
|
||||
if opts.TPMLocker == nil {
|
||||
return nil, fmt.Errorf("failed to create TPM key handler at slot %d: no TPM lock function", cfg.Slot)
|
||||
}
|
||||
|
||||
return NewTPMKeyHandler(key, cfg.TPMCheckSecurebootStatusOnEnroll, opts.TPMLocker)
|
||||
handler, err = NewTPMKeyHandler(key, cfg.TPMCheckSecurebootStatusOnEnroll, opts.TPMLocker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported key type: %s", cfg.Type)
|
||||
}
|
||||
|
||||
if cfg.LockToSTATE {
|
||||
if opts.SaltGetter == nil {
|
||||
return nil, fmt.Errorf("failed to create state-locked key handler at slot %d: no salt getter", cfg.Slot)
|
||||
}
|
||||
|
||||
handler = NewSaltedHandler(handler, opts.SaltGetter)
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
// Handler manages key lifecycle.
|
||||
|
52
internal/pkg/encryption/keys/nodeid_test.go
Normal file
52
internal/pkg/encryption/keys/nodeid_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption/keys"
|
||||
"github.com/siderolabs/talos/pkg/machinery/resources/hardware"
|
||||
)
|
||||
|
||||
func TestNodeID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := keys.NewNodeIDKeyHandler(keys.KeyHandler{}, "test", func(context.Context) (*hardware.SystemInformation, error) {
|
||||
res := hardware.NewSystemInformation(hardware.SystemInformationID)
|
||||
res.TypedSpec().UUID = "12345678-1234-5678-1234-567812345678"
|
||||
|
||||
return res, nil
|
||||
})
|
||||
|
||||
key, token, err := handler.NewKey(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, token)
|
||||
|
||||
assert.Equal(t, "12345678-1234-5678-1234-567812345678test", string(key.Value))
|
||||
|
||||
key, err = handler.GetKey(t.Context(), nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "12345678-1234-5678-1234-567812345678test", string(key.Value))
|
||||
}
|
||||
|
||||
func TestNodeIDBadEntropy(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
handler := keys.NewNodeIDKeyHandler(keys.KeyHandler{}, "test", func(context.Context) (*hardware.SystemInformation, error) {
|
||||
res := hardware.NewSystemInformation(hardware.SystemInformationID)
|
||||
res.TypedSpec().UUID = "11111111-0000-1111-1111-111111111111" // bad entropy
|
||||
|
||||
return res, nil
|
||||
})
|
||||
|
||||
_, _, err := handler.NewKey(t.Context())
|
||||
require.Error(t, err)
|
||||
assert.EqualError(t, err, "machine UUID 11111111-0000-1111-1111-111111111111 entropy check failed")
|
||||
}
|
@ -14,6 +14,7 @@ type KeyOptions struct {
|
||||
VolumeID string
|
||||
GetSystemInformation helpers.SystemInformationGetter
|
||||
TPMLocker helpers.TPMLockFunc
|
||||
SaltGetter helpers.SaltGetter
|
||||
}
|
||||
|
||||
// WithVolumeID passes the partition label to the key handler.
|
||||
@ -43,6 +44,15 @@ func WithTPMLocker(locker helpers.TPMLockFunc) KeyOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSaltGetter passes the salt getter to the key handler.
|
||||
func WithSaltGetter(getter helpers.SaltGetter) KeyOption {
|
||||
return func(o *KeyOptions) error {
|
||||
o.SaltGetter = getter
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultOptions creates new KeyOptions.
|
||||
func NewDefaultOptions(options []KeyOption) (*KeyOptions, error) {
|
||||
var opts KeyOptions
|
||||
|
69
internal/pkg/encryption/keys/salted.go
Normal file
69
internal/pkg/encryption/keys/salted.go
Normal file
@ -0,0 +1,69 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/siderolabs/go-blockdevice/v2/encryption"
|
||||
"github.com/siderolabs/go-blockdevice/v2/encryption/token"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption/helpers"
|
||||
)
|
||||
|
||||
// SaltedHandler is a key handler wrapper that salts the key with a provided random salt.
|
||||
type SaltedHandler struct {
|
||||
wrapped Handler
|
||||
saltGetter helpers.SaltGetter
|
||||
}
|
||||
|
||||
// NewSaltedHandler creates a new handler that wraps the provided key handler and uses the provided salt getter.
|
||||
func NewSaltedHandler(wrapped Handler, saltGetter helpers.SaltGetter) Handler {
|
||||
return &SaltedHandler{
|
||||
wrapped: wrapped,
|
||||
saltGetter: saltGetter,
|
||||
}
|
||||
}
|
||||
|
||||
// NewKey implements the keys.Handler interface.
|
||||
func (k *SaltedHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {
|
||||
key, token, err := k.wrapped.NewKey(ctx)
|
||||
if err != nil {
|
||||
return key, token, err
|
||||
}
|
||||
|
||||
salt, err := k.saltGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get disk encryption key salt: %w", err)
|
||||
}
|
||||
|
||||
key.Value = slices.Concat(key.Value, salt)
|
||||
|
||||
return key, token, nil
|
||||
}
|
||||
|
||||
// GetKey implements the keys.Handler interface.
|
||||
func (k *SaltedHandler) GetKey(ctx context.Context, token token.Token) (*encryption.Key, error) {
|
||||
key, err := k.wrapped.GetKey(ctx, token)
|
||||
if err != nil {
|
||||
return key, err
|
||||
}
|
||||
|
||||
salt, err := k.saltGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get disk encryption key salt: %w", err)
|
||||
}
|
||||
|
||||
key.Value = slices.Concat(key.Value, salt)
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// Slot implements the keys.Handler interface.
|
||||
func (k *SaltedHandler) Slot() int {
|
||||
return k.wrapped.Slot()
|
||||
}
|
40
internal/pkg/encryption/keys/salted_test.go
Normal file
40
internal/pkg/encryption/keys/salted_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption/keys"
|
||||
)
|
||||
|
||||
func TestSalted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
secret = "topsecret"
|
||||
salt = "salted"
|
||||
)
|
||||
|
||||
inner := keys.NewStaticKeyHandler(keys.KeyHandler{}, []byte(secret))
|
||||
|
||||
handler := keys.NewSaltedHandler(inner, func(context.Context) ([]byte, error) {
|
||||
return []byte(salt), nil
|
||||
})
|
||||
|
||||
key, token, err := handler.NewKey(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, token)
|
||||
|
||||
assert.Equal(t, secret+salt, string(key.Value))
|
||||
|
||||
key, err = handler.GetKey(t.Context(), nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, secret+salt, string(key.Value))
|
||||
}
|
32
internal/pkg/encryption/keys/static_test.go
Normal file
32
internal/pkg/encryption/keys/static_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/encryption/keys"
|
||||
)
|
||||
|
||||
func TestStatic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const secret = "topsecret"
|
||||
|
||||
handler := keys.NewStaticKeyHandler(keys.KeyHandler{}, []byte(secret))
|
||||
|
||||
key, token, err := handler.NewKey(t.Context())
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, token)
|
||||
|
||||
assert.Equal(t, secret, string(key.Value))
|
||||
|
||||
key1, err := handler.GetKey(t.Context(), nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, key, key1)
|
||||
}
|
@ -647,6 +647,7 @@ type EncryptionKey struct {
|
||||
StaticPassphrase []byte `protobuf:"bytes,3,opt,name=static_passphrase,json=staticPassphrase,proto3" json:"static_passphrase,omitempty"`
|
||||
KmsEndpoint string `protobuf:"bytes,4,opt,name=kms_endpoint,json=kmsEndpoint,proto3" json:"kms_endpoint,omitempty"`
|
||||
TpmCheckSecurebootStatusOnEnroll bool `protobuf:"varint,5,opt,name=tpm_check_secureboot_status_on_enroll,json=tpmCheckSecurebootStatusOnEnroll,proto3" json:"tpm_check_secureboot_status_on_enroll,omitempty"`
|
||||
LockToState bool `protobuf:"varint,6,opt,name=lock_to_state,json=lockToState,proto3" json:"lock_to_state,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -716,6 +717,13 @@ func (x *EncryptionKey) GetTpmCheckSecurebootStatusOnEnroll() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *EncryptionKey) GetLockToState() bool {
|
||||
if x != nil {
|
||||
return x.LockToState
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// EncryptionSpec is the spec for volume encryption.
|
||||
type EncryptionSpec struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -2217,13 +2225,14 @@ const file_resource_definitions_block_block_proto_rawDesc = "" +
|
||||
"prettySize\x12'\n" +
|
||||
"\x0fsecondary_disks\x18\x10 \x03(\tR\x0esecondaryDisks\x12\x12\n" +
|
||||
"\x04uuid\x18\x11 \x01(\tR\x04uuid\x12\x1a\n" +
|
||||
"\bsymlinks\x18\x12 \x03(\tR\bsymlinks\"\x92\x02\n" +
|
||||
"\bsymlinks\x18\x12 \x03(\tR\bsymlinks\"\xb6\x02\n" +
|
||||
"\rEncryptionKey\x12\x12\n" +
|
||||
"\x04slot\x18\x01 \x01(\x03R\x04slot\x12L\n" +
|
||||
"\x04type\x18\x02 \x01(\x0e28.talos.resource.definitions.enums.BlockEncryptionKeyTypeR\x04type\x12+\n" +
|
||||
"\x11static_passphrase\x18\x03 \x01(\fR\x10staticPassphrase\x12!\n" +
|
||||
"\fkms_endpoint\x18\x04 \x01(\tR\vkmsEndpoint\x12O\n" +
|
||||
"%tpm_check_secureboot_status_on_enroll\x18\x05 \x01(\bR tpmCheckSecurebootStatusOnEnroll\"\xa5\x02\n" +
|
||||
"%tpm_check_secureboot_status_on_enroll\x18\x05 \x01(\bR tpmCheckSecurebootStatusOnEnroll\x12\"\n" +
|
||||
"\rlock_to_state\x18\x06 \x01(\bR\vlockToState\"\xa5\x02\n" +
|
||||
"\x0eEncryptionSpec\x12Y\n" +
|
||||
"\bprovider\x18\x01 \x01(\x0e2=.talos.resource.definitions.enums.BlockEncryptionProviderTypeR\bprovider\x12C\n" +
|
||||
"\x04keys\x18\x02 \x03(\v2/.talos.resource.definitions.block.EncryptionKeyR\x04keys\x12\x16\n" +
|
||||
|
@ -606,6 +606,16 @@ func (m *EncryptionKey) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if m.LockToState {
|
||||
i--
|
||||
if m.LockToState {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x30
|
||||
}
|
||||
if m.TpmCheckSecurebootStatusOnEnroll {
|
||||
i--
|
||||
if m.TpmCheckSecurebootStatusOnEnroll {
|
||||
@ -2216,6 +2226,9 @@ func (m *EncryptionKey) SizeVT() (n int) {
|
||||
if m.TpmCheckSecurebootStatusOnEnroll {
|
||||
n += 2
|
||||
}
|
||||
if m.LockToState {
|
||||
n += 2
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
@ -4552,6 +4565,26 @@ func (m *EncryptionKey) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.TpmCheckSecurebootStatusOnEnroll = bool(v != 0)
|
||||
case 6:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LockToState", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.LockToState = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
|
@ -146,6 +146,51 @@ func (x *CertSANSpec) GetFqdn() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// EncryptionSaltSpec describes the salt.
|
||||
type EncryptionSaltSpec struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
DiskSalt []byte `protobuf:"bytes,1,opt,name=disk_salt,json=diskSalt,proto3" json:"disk_salt,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EncryptionSaltSpec) Reset() {
|
||||
*x = EncryptionSaltSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EncryptionSaltSpec) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*EncryptionSaltSpec) ProtoMessage() {}
|
||||
|
||||
func (x *EncryptionSaltSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EncryptionSaltSpec.ProtoReflect.Descriptor instead.
|
||||
func (*EncryptionSaltSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *EncryptionSaltSpec) GetDiskSalt() []byte {
|
||||
if x != nil {
|
||||
return x.DiskSalt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EtcdCertsSpec describes etcd certs secrets.
|
||||
type EtcdCertsSpec struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -159,7 +204,7 @@ type EtcdCertsSpec struct {
|
||||
|
||||
func (x *EtcdCertsSpec) Reset() {
|
||||
*x = EtcdCertsSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -171,7 +216,7 @@ func (x *EtcdCertsSpec) String() string {
|
||||
func (*EtcdCertsSpec) ProtoMessage() {}
|
||||
|
||||
func (x *EtcdCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -184,7 +229,7 @@ func (x *EtcdCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use EtcdCertsSpec.ProtoReflect.Descriptor instead.
|
||||
func (*EtcdCertsSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{2}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *EtcdCertsSpec) GetEtcd() *common.PEMEncodedCertificateAndKey {
|
||||
@ -225,7 +270,7 @@ type EtcdRootSpec struct {
|
||||
|
||||
func (x *EtcdRootSpec) Reset() {
|
||||
*x = EtcdRootSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -237,7 +282,7 @@ func (x *EtcdRootSpec) String() string {
|
||||
func (*EtcdRootSpec) ProtoMessage() {}
|
||||
|
||||
func (x *EtcdRootSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -250,7 +295,7 @@ func (x *EtcdRootSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use EtcdRootSpec.ProtoReflect.Descriptor instead.
|
||||
func (*EtcdRootSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{3}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *EtcdRootSpec) GetEtcdCa() *common.PEMEncodedCertificateAndKey {
|
||||
@ -273,7 +318,7 @@ type KubeletSpec struct {
|
||||
|
||||
func (x *KubeletSpec) Reset() {
|
||||
*x = KubeletSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -285,7 +330,7 @@ func (x *KubeletSpec) String() string {
|
||||
func (*KubeletSpec) ProtoMessage() {}
|
||||
|
||||
func (x *KubeletSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -298,7 +343,7 @@ func (x *KubeletSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use KubeletSpec.ProtoReflect.Descriptor instead.
|
||||
func (*KubeletSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{4}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *KubeletSpec) GetEndpoint() *common.URL {
|
||||
@ -342,7 +387,7 @@ type KubernetesCertsSpec struct {
|
||||
|
||||
func (x *KubernetesCertsSpec) Reset() {
|
||||
*x = KubernetesCertsSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -354,7 +399,7 @@ func (x *KubernetesCertsSpec) String() string {
|
||||
func (*KubernetesCertsSpec) ProtoMessage() {}
|
||||
|
||||
func (x *KubernetesCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -367,7 +412,7 @@ func (x *KubernetesCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use KubernetesCertsSpec.ProtoReflect.Descriptor instead.
|
||||
func (*KubernetesCertsSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{5}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *KubernetesCertsSpec) GetSchedulerKubeconfig() string {
|
||||
@ -410,7 +455,7 @@ type KubernetesDynamicCertsSpec struct {
|
||||
|
||||
func (x *KubernetesDynamicCertsSpec) Reset() {
|
||||
*x = KubernetesDynamicCertsSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -422,7 +467,7 @@ func (x *KubernetesDynamicCertsSpec) String() string {
|
||||
func (*KubernetesDynamicCertsSpec) ProtoMessage() {}
|
||||
|
||||
func (x *KubernetesDynamicCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -435,7 +480,7 @@ func (x *KubernetesDynamicCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use KubernetesDynamicCertsSpec.ProtoReflect.Descriptor instead.
|
||||
func (*KubernetesDynamicCertsSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{6}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *KubernetesDynamicCertsSpec) GetApiServer() *common.PEMEncodedCertificateAndKey {
|
||||
@ -482,7 +527,7 @@ type KubernetesRootSpec struct {
|
||||
|
||||
func (x *KubernetesRootSpec) Reset() {
|
||||
*x = KubernetesRootSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -494,7 +539,7 @@ func (x *KubernetesRootSpec) String() string {
|
||||
func (*KubernetesRootSpec) ProtoMessage() {}
|
||||
|
||||
func (x *KubernetesRootSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -507,7 +552,7 @@ func (x *KubernetesRootSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use KubernetesRootSpec.ProtoReflect.Descriptor instead.
|
||||
func (*KubernetesRootSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{7}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *KubernetesRootSpec) GetName() string {
|
||||
@ -618,7 +663,7 @@ type MaintenanceRootSpec struct {
|
||||
|
||||
func (x *MaintenanceRootSpec) Reset() {
|
||||
*x = MaintenanceRootSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -630,7 +675,7 @@ func (x *MaintenanceRootSpec) String() string {
|
||||
func (*MaintenanceRootSpec) ProtoMessage() {}
|
||||
|
||||
func (x *MaintenanceRootSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -643,7 +688,7 @@ func (x *MaintenanceRootSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use MaintenanceRootSpec.ProtoReflect.Descriptor instead.
|
||||
func (*MaintenanceRootSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{8}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *MaintenanceRootSpec) GetCa() *common.PEMEncodedCertificateAndKey {
|
||||
@ -664,7 +709,7 @@ type MaintenanceServiceCertsSpec struct {
|
||||
|
||||
func (x *MaintenanceServiceCertsSpec) Reset() {
|
||||
*x = MaintenanceServiceCertsSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -676,7 +721,7 @@ func (x *MaintenanceServiceCertsSpec) String() string {
|
||||
func (*MaintenanceServiceCertsSpec) ProtoMessage() {}
|
||||
|
||||
func (x *MaintenanceServiceCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -689,7 +734,7 @@ func (x *MaintenanceServiceCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use MaintenanceServiceCertsSpec.ProtoReflect.Descriptor instead.
|
||||
func (*MaintenanceServiceCertsSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{9}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *MaintenanceServiceCertsSpec) GetCa() *common.PEMEncodedCertificateAndKey {
|
||||
@ -720,7 +765,7 @@ type OSRootSpec struct {
|
||||
|
||||
func (x *OSRootSpec) Reset() {
|
||||
*x = OSRootSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -732,7 +777,7 @@ func (x *OSRootSpec) String() string {
|
||||
func (*OSRootSpec) ProtoMessage() {}
|
||||
|
||||
func (x *OSRootSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -745,7 +790,7 @@ func (x *OSRootSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use OSRootSpec.ProtoReflect.Descriptor instead.
|
||||
func (*OSRootSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{10}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *OSRootSpec) GetIssuingCa() *common.PEMEncodedCertificateAndKey {
|
||||
@ -794,7 +839,7 @@ type TrustdCertsSpec struct {
|
||||
|
||||
func (x *TrustdCertsSpec) Reset() {
|
||||
*x = TrustdCertsSpec{}
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -806,7 +851,7 @@ func (x *TrustdCertsSpec) String() string {
|
||||
func (*TrustdCertsSpec) ProtoMessage() {}
|
||||
|
||||
func (x *TrustdCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]
|
||||
mi := &file_resource_definitions_secrets_secrets_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -819,7 +864,7 @@ func (x *TrustdCertsSpec) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use TrustdCertsSpec.ProtoReflect.Descriptor instead.
|
||||
func (*TrustdCertsSpec) Descriptor() ([]byte, []int) {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{11}
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *TrustdCertsSpec) GetServer() *common.PEMEncodedCertificateAndKey {
|
||||
@ -848,7 +893,9 @@ const file_resource_definitions_secrets_secrets_proto_rawDesc = "" +
|
||||
"\vCertSANSpec\x12 \n" +
|
||||
"\x04i_ps\x18\x01 \x03(\v2\r.common.NetIPR\x03iPs\x12\x1b\n" +
|
||||
"\tdns_names\x18\x02 \x03(\tR\bdnsNames\x12\x12\n" +
|
||||
"\x04fqdn\x18\x03 \x01(\tR\x04fqdn\"\x9b\x02\n" +
|
||||
"\x04fqdn\x18\x03 \x01(\tR\x04fqdn\"1\n" +
|
||||
"\x12EncryptionSaltSpec\x12\x1b\n" +
|
||||
"\tdisk_salt\x18\x01 \x01(\fR\bdiskSalt\"\x9b\x02\n" +
|
||||
"\rEtcdCertsSpec\x127\n" +
|
||||
"\x04etcd\x18\x01 \x01(\v2#.common.PEMEncodedCertificateAndKeyR\x04etcd\x12@\n" +
|
||||
"\tetcd_peer\x18\x02 \x01(\v2#.common.PEMEncodedCertificateAndKeyR\betcdPeer\x12B\n" +
|
||||
@ -923,56 +970,57 @@ func file_resource_definitions_secrets_secrets_proto_rawDescGZIP() []byte {
|
||||
return file_resource_definitions_secrets_secrets_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_resource_definitions_secrets_secrets_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_resource_definitions_secrets_secrets_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
|
||||
var file_resource_definitions_secrets_secrets_proto_goTypes = []any{
|
||||
(*APICertsSpec)(nil), // 0: talos.resource.definitions.secrets.APICertsSpec
|
||||
(*CertSANSpec)(nil), // 1: talos.resource.definitions.secrets.CertSANSpec
|
||||
(*EtcdCertsSpec)(nil), // 2: talos.resource.definitions.secrets.EtcdCertsSpec
|
||||
(*EtcdRootSpec)(nil), // 3: talos.resource.definitions.secrets.EtcdRootSpec
|
||||
(*KubeletSpec)(nil), // 4: talos.resource.definitions.secrets.KubeletSpec
|
||||
(*KubernetesCertsSpec)(nil), // 5: talos.resource.definitions.secrets.KubernetesCertsSpec
|
||||
(*KubernetesDynamicCertsSpec)(nil), // 6: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec
|
||||
(*KubernetesRootSpec)(nil), // 7: talos.resource.definitions.secrets.KubernetesRootSpec
|
||||
(*MaintenanceRootSpec)(nil), // 8: talos.resource.definitions.secrets.MaintenanceRootSpec
|
||||
(*MaintenanceServiceCertsSpec)(nil), // 9: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec
|
||||
(*OSRootSpec)(nil), // 10: talos.resource.definitions.secrets.OSRootSpec
|
||||
(*TrustdCertsSpec)(nil), // 11: talos.resource.definitions.secrets.TrustdCertsSpec
|
||||
(*common.PEMEncodedCertificateAndKey)(nil), // 12: common.PEMEncodedCertificateAndKey
|
||||
(*common.PEMEncodedCertificate)(nil), // 13: common.PEMEncodedCertificate
|
||||
(*common.NetIP)(nil), // 14: common.NetIP
|
||||
(*common.URL)(nil), // 15: common.URL
|
||||
(*common.PEMEncodedKey)(nil), // 16: common.PEMEncodedKey
|
||||
(*EncryptionSaltSpec)(nil), // 2: talos.resource.definitions.secrets.EncryptionSaltSpec
|
||||
(*EtcdCertsSpec)(nil), // 3: talos.resource.definitions.secrets.EtcdCertsSpec
|
||||
(*EtcdRootSpec)(nil), // 4: talos.resource.definitions.secrets.EtcdRootSpec
|
||||
(*KubeletSpec)(nil), // 5: talos.resource.definitions.secrets.KubeletSpec
|
||||
(*KubernetesCertsSpec)(nil), // 6: talos.resource.definitions.secrets.KubernetesCertsSpec
|
||||
(*KubernetesDynamicCertsSpec)(nil), // 7: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec
|
||||
(*KubernetesRootSpec)(nil), // 8: talos.resource.definitions.secrets.KubernetesRootSpec
|
||||
(*MaintenanceRootSpec)(nil), // 9: talos.resource.definitions.secrets.MaintenanceRootSpec
|
||||
(*MaintenanceServiceCertsSpec)(nil), // 10: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec
|
||||
(*OSRootSpec)(nil), // 11: talos.resource.definitions.secrets.OSRootSpec
|
||||
(*TrustdCertsSpec)(nil), // 12: talos.resource.definitions.secrets.TrustdCertsSpec
|
||||
(*common.PEMEncodedCertificateAndKey)(nil), // 13: common.PEMEncodedCertificateAndKey
|
||||
(*common.PEMEncodedCertificate)(nil), // 14: common.PEMEncodedCertificate
|
||||
(*common.NetIP)(nil), // 15: common.NetIP
|
||||
(*common.URL)(nil), // 16: common.URL
|
||||
(*common.PEMEncodedKey)(nil), // 17: common.PEMEncodedKey
|
||||
}
|
||||
var file_resource_definitions_secrets_secrets_proto_depIdxs = []int32{
|
||||
12, // 0: talos.resource.definitions.secrets.APICertsSpec.client:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 1: talos.resource.definitions.secrets.APICertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 2: talos.resource.definitions.secrets.APICertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
14, // 3: talos.resource.definitions.secrets.CertSANSpec.i_ps:type_name -> common.NetIP
|
||||
12, // 4: talos.resource.definitions.secrets.EtcdCertsSpec.etcd:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 5: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_peer:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 6: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_admin:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 7: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_api_server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 8: talos.resource.definitions.secrets.EtcdRootSpec.etcd_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
15, // 9: talos.resource.definitions.secrets.KubeletSpec.endpoint:type_name -> common.URL
|
||||
13, // 10: talos.resource.definitions.secrets.KubeletSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
12, // 11: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 12: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server_kubelet_client:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 13: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.front_proxy:type_name -> common.PEMEncodedCertificateAndKey
|
||||
15, // 14: talos.resource.definitions.secrets.KubernetesRootSpec.endpoint:type_name -> common.URL
|
||||
15, // 15: talos.resource.definitions.secrets.KubernetesRootSpec.local_endpoint:type_name -> common.URL
|
||||
12, // 16: talos.resource.definitions.secrets.KubernetesRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
16, // 17: talos.resource.definitions.secrets.KubernetesRootSpec.service_account:type_name -> common.PEMEncodedKey
|
||||
12, // 18: talos.resource.definitions.secrets.KubernetesRootSpec.aggregator_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
14, // 19: talos.resource.definitions.secrets.KubernetesRootSpec.api_server_ips:type_name -> common.NetIP
|
||||
13, // 20: talos.resource.definitions.secrets.KubernetesRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
12, // 21: talos.resource.definitions.secrets.MaintenanceRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 22: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 23: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
12, // 24: talos.resource.definitions.secrets.OSRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
14, // 25: talos.resource.definitions.secrets.OSRootSpec.cert_sani_ps:type_name -> common.NetIP
|
||||
13, // 26: talos.resource.definitions.secrets.OSRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
12, // 27: talos.resource.definitions.secrets.TrustdCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 28: talos.resource.definitions.secrets.TrustdCertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
13, // 0: talos.resource.definitions.secrets.APICertsSpec.client:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 1: talos.resource.definitions.secrets.APICertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
14, // 2: talos.resource.definitions.secrets.APICertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
15, // 3: talos.resource.definitions.secrets.CertSANSpec.i_ps:type_name -> common.NetIP
|
||||
13, // 4: talos.resource.definitions.secrets.EtcdCertsSpec.etcd:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 5: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_peer:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 6: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_admin:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 7: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_api_server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 8: talos.resource.definitions.secrets.EtcdRootSpec.etcd_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
16, // 9: talos.resource.definitions.secrets.KubeletSpec.endpoint:type_name -> common.URL
|
||||
14, // 10: talos.resource.definitions.secrets.KubeletSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
13, // 11: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 12: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server_kubelet_client:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 13: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.front_proxy:type_name -> common.PEMEncodedCertificateAndKey
|
||||
16, // 14: talos.resource.definitions.secrets.KubernetesRootSpec.endpoint:type_name -> common.URL
|
||||
16, // 15: talos.resource.definitions.secrets.KubernetesRootSpec.local_endpoint:type_name -> common.URL
|
||||
13, // 16: talos.resource.definitions.secrets.KubernetesRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
17, // 17: talos.resource.definitions.secrets.KubernetesRootSpec.service_account:type_name -> common.PEMEncodedKey
|
||||
13, // 18: talos.resource.definitions.secrets.KubernetesRootSpec.aggregator_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
15, // 19: talos.resource.definitions.secrets.KubernetesRootSpec.api_server_ips:type_name -> common.NetIP
|
||||
14, // 20: talos.resource.definitions.secrets.KubernetesRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
13, // 21: talos.resource.definitions.secrets.MaintenanceRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 22: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 23: talos.resource.definitions.secrets.MaintenanceServiceCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
13, // 24: talos.resource.definitions.secrets.OSRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey
|
||||
15, // 25: talos.resource.definitions.secrets.OSRootSpec.cert_sani_ps:type_name -> common.NetIP
|
||||
14, // 26: talos.resource.definitions.secrets.OSRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
13, // 27: talos.resource.definitions.secrets.TrustdCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey
|
||||
14, // 28: talos.resource.definitions.secrets.TrustdCertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate
|
||||
29, // [29:29] is the sub-list for method output_type
|
||||
29, // [29:29] is the sub-list for method input_type
|
||||
29, // [29:29] is the sub-list for extension type_name
|
||||
@ -991,7 +1039,7 @@ func file_resource_definitions_secrets_secrets_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_secrets_secrets_proto_rawDesc), len(file_resource_definitions_secrets_secrets_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 12,
|
||||
NumMessages: 13,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
@ -196,6 +196,46 @@ func (m *CertSANSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *EncryptionSaltSpec) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
size := m.SizeVT()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *EncryptionSaltSpec) MarshalToVT(dAtA []byte) (int, error) {
|
||||
size := m.SizeVT()
|
||||
return m.MarshalToSizedBufferVT(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *EncryptionSaltSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
|
||||
if m == nil {
|
||||
return 0, nil
|
||||
}
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.unknownFields != nil {
|
||||
i -= len(m.unknownFields)
|
||||
copy(dAtA[i:], m.unknownFields)
|
||||
}
|
||||
if len(m.DiskSalt) > 0 {
|
||||
i -= len(m.DiskSalt)
|
||||
copy(dAtA[i:], m.DiskSalt)
|
||||
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskSalt)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *EtcdCertsSpec) MarshalVT() (dAtA []byte, err error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
@ -1271,6 +1311,20 @@ func (m *CertSANSpec) SizeVT() (n int) {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *EncryptionSaltSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.DiskSalt)
|
||||
if l > 0 {
|
||||
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
|
||||
}
|
||||
n += len(m.unknownFields)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *EtcdCertsSpec) SizeVT() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@ -2035,6 +2089,91 @@ func (m *CertSANSpec) UnmarshalVT(dAtA []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *EncryptionSaltSpec) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: EncryptionSaltSpec: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: EncryptionSaltSpec: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field DiskSalt", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return protohelpers.ErrIntOverflow
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.DiskSalt = append(m.DiskSalt[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.DiskSalt == nil {
|
||||
m.DiskSalt = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return protohelpers.ErrInvalidLength
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *EtcdCertsSpec) UnmarshalVT(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
@ -407,6 +407,7 @@ type EncryptionKey interface {
|
||||
KMS() EncryptionKeyKMS
|
||||
Slot() int
|
||||
TPM() EncryptionKeyTPM
|
||||
LockToSTATE() bool
|
||||
}
|
||||
|
||||
// EncryptionKeyStatic ephemeral encryption key.
|
||||
|
@ -52,6 +52,13 @@
|
||||
"description": "Enable TPM based disk encryption.\n",
|
||||
"markdownDescription": "Enable TPM based disk encryption.",
|
||||
"x-intellij-html-description": "\u003cp\u003eEnable TPM based disk encryption.\u003c/p\u003e\n"
|
||||
},
|
||||
"lockToState": {
|
||||
"type": "boolean",
|
||||
"title": "lockToState",
|
||||
"description": "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\n",
|
||||
"markdownDescription": "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.",
|
||||
"x-intellij-html-description": "\u003cp\u003eLock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\u003c/p\u003e\n"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
@ -148,6 +148,13 @@ func (EncryptionKey) Doc() *encoder.Doc {
|
||||
Description: "Enable TPM based disk encryption.",
|
||||
Comments: [3]string{"" /* encoder.HeadComment */, "Enable TPM based disk encryption." /* encoder.LineComment */, "" /* encoder.FootComment */},
|
||||
},
|
||||
{
|
||||
Name: "lockToState",
|
||||
Type: "bool",
|
||||
Note: "",
|
||||
Description: "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.",
|
||||
Comments: [3]string{"" /* encoder.HeadComment */, "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes." /* encoder.LineComment */, "" /* encoder.FootComment */},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,10 @@ func (o *RawVolumeConfigV1Alpha1) DeepCopy() *RawVolumeConfigV1Alpha1 {
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {
|
||||
cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionPerfOptions != nil {
|
||||
@ -119,6 +123,10 @@ func (o *SwapVolumeConfigV1Alpha1) DeepCopy() *SwapVolumeConfigV1Alpha1 {
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {
|
||||
cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionPerfOptions != nil {
|
||||
@ -179,6 +187,10 @@ func (o *UserVolumeConfigV1Alpha1) DeepCopy() *UserVolumeConfigV1Alpha1 {
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {
|
||||
cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionPerfOptions != nil {
|
||||
@ -235,6 +247,10 @@ func (o *VolumeConfigV1Alpha1) DeepCopy() *VolumeConfigV1Alpha1 {
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {
|
||||
cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)
|
||||
*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.EncryptionSpec.EncryptionPerfOptions != nil {
|
||||
|
@ -99,6 +99,12 @@ type EncryptionKey struct {
|
||||
// description: >
|
||||
// Enable TPM based disk encryption.
|
||||
KeyTPM *EncryptionKeyTPM `yaml:"tpm,omitempty"`
|
||||
// description: >
|
||||
// Lock the disk encryption key to the random salt stored in the STATE partition.
|
||||
// This is useful to prevent the volume from being unlocked if STATE partition is compromised
|
||||
// or replaced. It is recommended to use this option with TPM disk encryption for
|
||||
// non-STATE volumes.
|
||||
KeyLockToSTATE *bool `yaml:"lockToState,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptionKeyStatic represents throw away key type.
|
||||
@ -213,6 +219,11 @@ func (k EncryptionKey) Slot() int {
|
||||
return k.KeySlot
|
||||
}
|
||||
|
||||
// LockToSTATE implements the config.Provider interface.
|
||||
func (k EncryptionKey) LockToSTATE() bool {
|
||||
return pointer.SafeDeref(k.KeyLockToSTATE)
|
||||
}
|
||||
|
||||
// Static implements the config.Provider interface.
|
||||
func (k EncryptionKey) Static() config.EncryptionKeyStatic {
|
||||
if k.KeyStatic == nil {
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"github.com/siderolabs/gen/optional"
|
||||
"github.com/siderolabs/go-pointer"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/cel"
|
||||
"github.com/siderolabs/talos/pkg/machinery/cel/celenv"
|
||||
@ -177,6 +178,13 @@ func (s *VolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Op
|
||||
if !s.ProvisioningSpec.IsZero() {
|
||||
validationErrors = errors.Join(validationErrors, fmt.Errorf("provisioning config is not allowed for the %q volume", s.MetaName))
|
||||
}
|
||||
|
||||
for _, key := range s.EncryptionSpec.EncryptionKeys {
|
||||
if pointer.SafeDeref(key.KeyLockToSTATE) {
|
||||
// state-locked keys are not allowed
|
||||
validationErrors = errors.Join(validationErrors, fmt.Errorf("state-locked key is not allowed for the %q volume", s.MetaName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extraWarnings, extraErrors := s.ProvisioningSpec.Validate(false)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/siderolabs/go-pointer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -185,6 +186,37 @@ func TestVolumeConfigValidate(t *testing.T) {
|
||||
|
||||
expectedErrors: "provisioning config is not allowed for the \"STATE\" volume",
|
||||
},
|
||||
{
|
||||
name: "state encryption lock to state",
|
||||
|
||||
cfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {
|
||||
c := block.NewVolumeConfigV1Alpha1()
|
||||
c.MetaName = constants.StatePartitionLabel
|
||||
|
||||
c.EncryptionSpec = block.EncryptionSpec{
|
||||
EncryptionProvider: blockres.EncryptionProviderLUKS2,
|
||||
EncryptionKeys: []block.EncryptionKey{
|
||||
{
|
||||
KeySlot: 0,
|
||||
KeyStatic: &block.EncryptionKeyStatic{
|
||||
KeyData: "topsecret",
|
||||
},
|
||||
},
|
||||
{
|
||||
KeySlot: 1,
|
||||
KeyStatic: &block.EncryptionKeyStatic{
|
||||
KeyData: "topsecret2",
|
||||
},
|
||||
KeyLockToSTATE: pointer.To(true),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return c
|
||||
},
|
||||
|
||||
expectedErrors: "state-locked key is not allowed for the \"STATE\" volume",
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
|
||||
|
@ -1604,6 +1604,12 @@ func (e *EncryptionKey) TPM() config.EncryptionKeyTPM {
|
||||
return e.KeyTPM
|
||||
}
|
||||
|
||||
// LockToSTATE implements the config.Provider interface.
|
||||
func (e *EncryptionKey) LockToSTATE() bool {
|
||||
// not supported in v1alpha1
|
||||
return false
|
||||
}
|
||||
|
||||
// String implements the config.Provider interface.
|
||||
func (e *EncryptionKeyNodeID) String() string {
|
||||
return "nodeid"
|
||||
|
@ -1270,6 +1270,12 @@ const (
|
||||
|
||||
// ExtensionSPDXPath is the path to the SBOM file(s) provided by system extensions.
|
||||
ExtensionSPDXPath = "/usr/local/share/spdx"
|
||||
|
||||
// EncryptionSaltFilename is the filename for the encryption salt file.
|
||||
EncryptionSaltFilename = "encryption-salt.yaml"
|
||||
|
||||
// DiskEncryptionSaltSize is the size of the disk encryption salt in bytes.
|
||||
DiskEncryptionSaltSize = 32
|
||||
)
|
||||
|
||||
// See https://linux.die.net/man/3/klogctl
|
||||
|
@ -135,8 +135,9 @@ type EncryptionSpec struct {
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type EncryptionKey struct {
|
||||
Slot int `yaml:"slot" protobuf:"1"`
|
||||
Type EncryptionKeyType `yaml:"type" protobuf:"2"`
|
||||
Slot int `yaml:"slot" protobuf:"1"`
|
||||
Type EncryptionKeyType `yaml:"type" protobuf:"2"`
|
||||
LockToSTATE bool `yaml:"lockToState,omitempty" protobuf:"6"`
|
||||
|
||||
// Only for Type == "static":
|
||||
StaticPassphrase yamlutils.StringBytes `yaml:"staticPassphrase,omitempty" protobuf:"3"`
|
||||
|
@ -2,7 +2,7 @@
|
||||
// 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/.
|
||||
|
||||
// Code generated by "deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
// Code generated by "deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type EncryptionSaltSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT.
|
||||
|
||||
package secrets
|
||||
|
||||
@ -75,6 +75,16 @@ func (o EtcdRootSpec) DeepCopy() EtcdRootSpec {
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of EncryptionSaltSpec.
|
||||
func (o EncryptionSaltSpec) DeepCopy() EncryptionSaltSpec {
|
||||
var cp EncryptionSaltSpec = o
|
||||
if o.DiskSalt != nil {
|
||||
cp.DiskSalt = make([]byte, len(o.DiskSalt))
|
||||
copy(cp.DiskSalt, o.DiskSalt)
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// DeepCopy generates a deep copy of KubeletSpec.
|
||||
func (o KubeletSpec) DeepCopy() KubeletSpec {
|
||||
var cp KubeletSpec = o
|
||||
|
59
pkg/machinery/resources/secrets/encryption_salt.go
Normal file
59
pkg/machinery/resources/secrets/encryption_salt.go
Normal file
@ -0,0 +1,59 @@
|
||||
// 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 secrets
|
||||
|
||||
import (
|
||||
"github.com/cosi-project/runtime/pkg/resource"
|
||||
"github.com/cosi-project/runtime/pkg/resource/meta"
|
||||
"github.com/cosi-project/runtime/pkg/resource/protobuf"
|
||||
"github.com/cosi-project/runtime/pkg/resource/typed"
|
||||
|
||||
"github.com/siderolabs/talos/pkg/machinery/proto"
|
||||
)
|
||||
|
||||
// EncryptionSaltType is type of EncryptionSalt resource.
|
||||
const EncryptionSaltType = resource.Type("EncryptionSalts.secrets.talos.dev")
|
||||
|
||||
// EncryptionSaltID is a resource ID of singleton instance.
|
||||
const EncryptionSaltID = resource.ID("salt")
|
||||
|
||||
// EncryptionSalt contains salt data used to mix in into disk encryption keys.
|
||||
type EncryptionSalt = typed.Resource[EncryptionSaltSpec, EncryptionSaltExtension]
|
||||
|
||||
// EncryptionSaltSpec describes the salt.
|
||||
//
|
||||
//gotagsrewrite:gen
|
||||
type EncryptionSaltSpec struct {
|
||||
DiskSalt []byte `yaml:"diskSalt" protobuf:"1"`
|
||||
}
|
||||
|
||||
// NewEncryptionSalt initializes a EncryptionSalt resource.
|
||||
func NewEncryptionSalt() *EncryptionSalt {
|
||||
return typed.NewResource[EncryptionSaltSpec, EncryptionSaltExtension](
|
||||
resource.NewMetadata(NamespaceName, EncryptionSaltType, EncryptionSaltID, resource.VersionUndefined),
|
||||
EncryptionSaltSpec{},
|
||||
)
|
||||
}
|
||||
|
||||
// EncryptionSaltExtension provides auxiliary methods for EncryptionSalt.
|
||||
type EncryptionSaltExtension struct{}
|
||||
|
||||
// ResourceDefinition implements meta.ResourceDefinitionProvider interface.
|
||||
func (EncryptionSaltExtension) ResourceDefinition() meta.ResourceDefinitionSpec {
|
||||
return meta.ResourceDefinitionSpec{
|
||||
Type: EncryptionSaltType,
|
||||
Aliases: []resource.Type{},
|
||||
DefaultNamespace: NamespaceName,
|
||||
Sensitivity: meta.Sensitive,
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterDefaultTypes()
|
||||
|
||||
if err := protobuf.RegisterDynamic[EncryptionSaltSpec](EncryptionSaltType, &EncryptionSalt{}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -10,4 +10,4 @@ import "github.com/cosi-project/runtime/pkg/resource"
|
||||
// NamespaceName contains resources containing secret material.
|
||||
const NamespaceName resource.Namespace = "secrets"
|
||||
|
||||
//go:generate deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
//go:generate deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type EncryptionSaltSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceServiceCertsSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .
|
||||
|
@ -26,6 +26,7 @@ func TestRegisterResource(t *testing.T) {
|
||||
for _, resource := range []meta.ResourceWithRD{
|
||||
&secrets.API{},
|
||||
&secrets.CertSAN{},
|
||||
&secrets.EncryptionSalt{},
|
||||
&secrets.Etcd{},
|
||||
&secrets.EtcdRoot{},
|
||||
&secrets.Kubelet{},
|
||||
|
@ -302,6 +302,7 @@ description: Talos gRPC API reference.
|
||||
- [resource/definitions/secrets/secrets.proto](#resource/definitions/secrets/secrets.proto)
|
||||
- [APICertsSpec](#talos.resource.definitions.secrets.APICertsSpec)
|
||||
- [CertSANSpec](#talos.resource.definitions.secrets.CertSANSpec)
|
||||
- [EncryptionSaltSpec](#talos.resource.definitions.secrets.EncryptionSaltSpec)
|
||||
- [EtcdCertsSpec](#talos.resource.definitions.secrets.EtcdCertsSpec)
|
||||
- [EtcdRootSpec](#talos.resource.definitions.secrets.EtcdRootSpec)
|
||||
- [KubeletSpec](#talos.resource.definitions.secrets.KubeletSpec)
|
||||
@ -989,6 +990,7 @@ EncryptionKey is the spec for volume encryption key.
|
||||
| static_passphrase | [bytes](#bytes) | | |
|
||||
| kms_endpoint | [string](#string) | | |
|
||||
| tpm_check_secureboot_status_on_enroll | [bool](#bool) | | |
|
||||
| lock_to_state | [bool](#bool) | | |
|
||||
|
||||
|
||||
|
||||
@ -5546,6 +5548,21 @@ CertSANSpec describes fields of the cert SANs.
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.secrets.EncryptionSaltSpec"></a>
|
||||
|
||||
### EncryptionSaltSpec
|
||||
EncryptionSaltSpec describes the salt.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| disk_salt | [bytes](#bytes) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="talos.resource.definitions.secrets.EtcdCertsSpec"></a>
|
||||
|
||||
### EtcdCertsSpec
|
||||
|
@ -177,6 +177,7 @@ EncryptionKey represents configuration for disk encryption key.
|
||||
|`nodeID` |<a href="#RawVolumeConfig.encryption.keys..nodeID">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel. | |
|
||||
|`kms` |<a href="#RawVolumeConfig.encryption.keys..kms">EncryptionKeyKMS</a> |KMS managed encryption key. | |
|
||||
|`tpm` |<a href="#RawVolumeConfig.encryption.keys..tpm">EncryptionKeyTPM</a> |Enable TPM based disk encryption. | |
|
||||
|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes. | |
|
||||
|
||||
|
||||
|
||||
|
@ -174,6 +174,7 @@ EncryptionKey represents configuration for disk encryption key.
|
||||
|`nodeID` |<a href="#SwapVolumeConfig.encryption.keys..nodeID">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel. | |
|
||||
|`kms` |<a href="#SwapVolumeConfig.encryption.keys..kms">EncryptionKeyKMS</a> |KMS managed encryption key. | |
|
||||
|`tpm` |<a href="#SwapVolumeConfig.encryption.keys..tpm">EncryptionKeyTPM</a> |Enable TPM based disk encryption. | |
|
||||
|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes. | |
|
||||
|
||||
|
||||
|
||||
|
@ -204,6 +204,7 @@ EncryptionKey represents configuration for disk encryption key.
|
||||
|`nodeID` |<a href="#UserVolumeConfig.encryption.keys..nodeID">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel. | |
|
||||
|`kms` |<a href="#UserVolumeConfig.encryption.keys..kms">EncryptionKeyKMS</a> |KMS managed encryption key. | |
|
||||
|`tpm` |<a href="#UserVolumeConfig.encryption.keys..tpm">EncryptionKeyTPM</a> |Enable TPM based disk encryption. | |
|
||||
|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes. | |
|
||||
|
||||
|
||||
|
||||
|
@ -174,6 +174,7 @@ EncryptionKey represents configuration for disk encryption key.
|
||||
|`nodeID` |<a href="#VolumeConfig.encryption.keys..nodeID">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel. | |
|
||||
|`kms` |<a href="#VolumeConfig.encryption.keys..kms">EncryptionKeyKMS</a> |KMS managed encryption key. | |
|
||||
|`tpm` |<a href="#VolumeConfig.encryption.keys..tpm">EncryptionKeyTPM</a> |Enable TPM based disk encryption. | |
|
||||
|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes. | |
|
||||
|
||||
|
||||
|
||||
|
@ -52,6 +52,13 @@
|
||||
"description": "Enable TPM based disk encryption.\n",
|
||||
"markdownDescription": "Enable TPM based disk encryption.",
|
||||
"x-intellij-html-description": "\u003cp\u003eEnable TPM based disk encryption.\u003c/p\u003e\n"
|
||||
},
|
||||
"lockToState": {
|
||||
"type": "boolean",
|
||||
"title": "lockToState",
|
||||
"description": "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\n",
|
||||
"markdownDescription": "Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.",
|
||||
"x-intellij-html-description": "\u003cp\u003eLock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\u003c/p\u003e\n"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
@ -112,6 +112,7 @@ encryption:
|
||||
- static:
|
||||
passphrase: supersecret
|
||||
slot: 0
|
||||
lockToSTATE: true
|
||||
```
|
||||
|
||||
Take a note that key order does not play any role on which key slot is used.
|
||||
@ -126,8 +127,17 @@ Talos supports two kinds of keys:
|
||||
- `kms` which is sealed with the network KMS.
|
||||
- `tpm` which is sealed using the TPM and protected with SecureBoot.
|
||||
|
||||
> Note: Use static keys only if your STATE partition is encrypted and only for the EPHEMERAL partition.
|
||||
> For the STATE partition it will be stored in the META partition, which is not encrypted.
|
||||
> Note: The `STATE` volume encryption configuration will be stored cleartext in `META` volume, so
|
||||
> it is not secure to use `static` keys for `STATE` volume.
|
||||
> Other volumes can use `static` keys as long as `STATE` partition itself is encrypted.
|
||||
|
||||
Every key kind also supports `lockToSTATE` option, which means that the key will be locked to the contents of the `STATE` partition:
|
||||
|
||||
- if the `STATE` partition is wiped/replaced with new contents, locked to `STATE` volumes will not be unlockable anymore.
|
||||
- Talos Linux generates a random salt, and stores in the `STATE` partition, which will be mixed into the key derivation function.
|
||||
|
||||
It is recommended to use `lockToSTATE` for the `EPHEMERAL` partition and user volumes, so that the data on these partitions is not accessible if the `STATE` partition is wiped or replaced.
|
||||
If you would like non-`STATE` volumes to survive `STATE` partition wipe, do not enable `lockToSTATE` option.
|
||||
|
||||
### Key Rotation
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user