diff --git a/cmd/talosctl/cmd/mgmt/cluster/create.go b/cmd/talosctl/cmd/mgmt/cluster/create.go index 30f53aaa99..0dab02427b 100644 --- a/cmd/talosctl/cmd/mgmt/cluster/create.go +++ b/cmd/talosctl/cmd/mgmt/cluster/create.go @@ -551,7 +551,9 @@ func create(ctx context.Context, flags *pflag.FlagSet) error { provisionOptions = append(provisionOptions, provision.WithKMS(nethelpers.JoinHostPort("0.0.0.0", port))) case "tpm": keys = append(keys, &v1alpha1.EncryptionKey{ - KeyTPM: &v1alpha1.EncryptionKeyTPM{}, + KeyTPM: &v1alpha1.EncryptionKeyTPM{ + TPMCheckSecurebootStatusOnEnroll: pointer.To(true), + }, KeySlot: i, }) default: diff --git a/internal/pkg/encryption/keys/keys.go b/internal/pkg/encryption/keys/keys.go index 0e38169f4c..d53ca2cf19 100644 --- a/internal/pkg/encryption/keys/keys.go +++ b/internal/pkg/encryption/keys/keys.go @@ -48,7 +48,7 @@ func NewHandler(cfg config.EncryptionKey, options ...KeyOption) (Handler, error) return NewKMSKeyHandler(key, cfg.KMS().Endpoint(), opts.GetSystemInformation) case cfg.TPM() != nil: - return NewTPMKeyHandler(key) + return NewTPMKeyHandler(key, cfg.TPM().CheckSecurebootOnEnroll()) } return nil, errors.New("malformed config: no key handler can be created") diff --git a/internal/pkg/encryption/keys/tpm2.go b/internal/pkg/encryption/keys/tpm2.go index ca21e49a7a..601c9d1fb5 100644 --- a/internal/pkg/encryption/keys/tpm2.go +++ b/internal/pkg/encryption/keys/tpm2.go @@ -8,8 +8,10 @@ import ( "context" "crypto/rand" "encoding/base64" + "fmt" "io" + "github.com/foxboron/go-uefi/efi" "github.com/siderolabs/go-blockdevice/blockdevice/encryption" "github.com/siderolabs/go-blockdevice/blockdevice/encryption/luks" "github.com/siderolabs/go-blockdevice/blockdevice/encryption/token" @@ -32,17 +34,30 @@ type TPMToken struct { // TPMKeyHandler seals token using TPM. type TPMKeyHandler struct { KeyHandler + + checkSecurebootOnEnroll bool } // NewTPMKeyHandler creates new TPMKeyHandler. -func NewTPMKeyHandler(key KeyHandler) (*TPMKeyHandler, error) { +func NewTPMKeyHandler(key KeyHandler, checkSecurebootOnEnroll bool) (*TPMKeyHandler, error) { return &TPMKeyHandler{ - KeyHandler: key, + KeyHandler: key, + checkSecurebootOnEnroll: checkSecurebootOnEnroll, }, nil } // NewKey implements Handler interface. func (h *TPMKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) { + if h.checkSecurebootOnEnroll { + if !efi.GetSecureBoot() { + return nil, nil, fmt.Errorf("failed to enroll the TPM2 key, as SecureBoot is disabled (and checkSecurebootOnEnroll is enabled)") + } + + if efi.GetSetupMode() { + return nil, nil, fmt.Errorf("failed to enroll the TPM2 key, as the system is in SecureBoot setup mode (and checkSecurebootOnEnroll is enabled)") + } + } + key := make([]byte, 32) if _, err := io.ReadFull(rand.Reader, key); err != nil { return nil, nil, err diff --git a/pkg/machinery/config/config/machine.go b/pkg/machinery/config/config/machine.go index 0849640b5a..212eb806fc 100644 --- a/pkg/machinery/config/config/machine.go +++ b/pkg/machinery/config/config/machine.go @@ -390,6 +390,7 @@ type EncryptionKeyNodeID interface { // EncryptionKeyTPM encryption key sealed by TPM. type EncryptionKeyTPM interface { + CheckSecurebootOnEnroll() bool String() string } diff --git a/pkg/machinery/config/schemas/config.schema.json b/pkg/machinery/config/schemas/config.schema.json index 83b1b3e020..011674a83b 100644 --- a/pkg/machinery/config/schemas/config.schema.json +++ b/pkg/machinery/config/schemas/config.schema.json @@ -1629,7 +1629,15 @@ "type": "object" }, "v1alpha1.EncryptionKeyTPM": { - "properties": {}, + "properties": { + "checkSecurebootStatusOnEnroll": { + "type": "boolean", + "title": "checkSecurebootStatusOnEnroll", + "description": "Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.\n", + "markdownDescription": "Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.", + "x-intellij-html-description": "\u003cp\u003eCheck that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.\u003c/p\u003e\n" + } + }, "additionalProperties": false, "type": "object" }, diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go index 5d17e101ae..21d9a0cf4e 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go @@ -1438,6 +1438,15 @@ func (e *EncryptionKeyTPM) String() string { return "tpm" } +// CheckSecurebootOnEnroll implements the config.Provider interface. +func (e *EncryptionKeyTPM) CheckSecurebootOnEnroll() bool { + if e == nil { + return false + } + + return pointer.SafeDeref(e.TPMCheckSecurebootStatusOnEnroll) +} + // Slot implements the config.Provider interface. func (e *EncryptionKey) Slot() int { return e.KeySlot diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go index 53604a9f9f..1293b82749 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go @@ -1621,7 +1621,16 @@ type EncryptionKeyKMS struct { } // EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM. -type EncryptionKeyTPM struct{} +type EncryptionKeyTPM struct { + // description: > + // Check that Secureboot is enabled in the EFI firmware. + // + // If Secureboot is not enabled, the enrollment of the key will fail. + // As the TPM key is anyways bound to the value of PCR 7, + // changing Secureboot status or configuration + // after the initial enrollment will make the key unusable. + TPMCheckSecurebootStatusOnEnroll *bool `yaml:"checkSecurebootStatusOnEnroll,omitempty"` +} // EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel. type EncryptionKeyNodeID struct{} diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go index 7f3709291d..3120e7c27b 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go @@ -2183,7 +2183,15 @@ func (EncryptionKeyTPM) Doc() *encoder.Doc { FieldName: "tpm", }, }, - Fields: []encoder.Doc{}, + Fields: []encoder.Doc{ + { + Name: "checkSecurebootStatusOnEnroll", + Type: "bool", + Note: "", + Description: "Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.", + Comments: [3]string{"" /* encoder.HeadComment */, "Check that Secureboot is enabled in the EFI firmware." /* encoder.LineComment */, "" /* encoder.FootComment */}, + }, + }, } return doc diff --git a/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go b/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go index 027e512def..9eb898179b 100644 --- a/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go @@ -845,7 +845,7 @@ func (in *EncryptionKey) DeepCopyInto(out *EncryptionKey) { if in.KeyTPM != nil { in, out := &in.KeyTPM, &out.KeyTPM *out = new(EncryptionKeyTPM) - **out = **in + (*in).DeepCopyInto(*out) } return } @@ -911,6 +911,11 @@ func (in *EncryptionKeyStatic) DeepCopy() *EncryptionKeyStatic { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EncryptionKeyTPM) DeepCopyInto(out *EncryptionKeyTPM) { *out = *in + if in.TPMCheckSecurebootStatusOnEnroll != nil { + in, out := &in.TPMCheckSecurebootStatusOnEnroll, &out.TPMCheckSecurebootStatusOnEnroll + *out = new(bool) + **out = **in + } return } diff --git a/website/content/v1.7/reference/cli.md b/website/content/v1.7/reference/cli.md index 5ad0c53867..45b1605b95 100644 --- a/website/content/v1.7/reference/cli.md +++ b/website/content/v1.7/reference/cli.md @@ -96,7 +96,7 @@ talosctl cluster create [flags] --bad-rtc launch VM with bad RTC state (QEMU only) --cidr string CIDR of the cluster network (IPv4, ULA network for IPv6 is derived in automated way) (default "10.5.0.0/24") --cni-bin-path strings search path for CNI binaries (VM only) (default [/home/user/.talos/cni/bin]) - --cni-bundle-url string URL to download CNI bundle from (VM only) (default "https://github.com/siderolabs/talos/releases/download/v1.7.5-dirty/talosctl-cni-bundle-${ARCH}.tar.gz") + --cni-bundle-url string URL to download CNI bundle from (VM only) (default "https://github.com/siderolabs/talos/releases/download/v1.7.5/talosctl-cni-bundle-${ARCH}.tar.gz") --cni-cache-dir string CNI cache directory path (VM only) (default "/home/user/.talos/cni/cache") --cni-conf-dir string CNI config directory path (VM only) (default "/home/user/.talos/cni/conf.d") --config-patch stringArray patch generated machineconfigs (applied to all node types), use @file to read a patch from file @@ -2898,7 +2898,7 @@ talosctl upgrade [flags] --debug debug operation from kernel logs. --wait is set to true when this flag is set -f, --force force the upgrade (skip checks on etcd health and members, might lead to data loss) -h, --help help for upgrade - -i, --image string the container image to use for performing the install (default "ghcr.io/siderolabs/installer:v1.7.5-dirty") + -i, --image string the container image to use for performing the install (default "ghcr.io/siderolabs/installer:v1.7.5") --insecure upgrade using the insecure (encrypted with no auth) maintenance service -p, --preserve preserve data -m, --reboot-mode string select the reboot mode during upgrade. Mode "powercycle" bypasses kexec. Valid values are: ["default" "powercycle"]. (default "default") diff --git a/website/content/v1.7/reference/configuration/v1alpha1/config.md b/website/content/v1.7/reference/configuration/v1alpha1/config.md index 1ca926aca7..e9e2cd1208 100644 --- a/website/content/v1.7/reference/configuration/v1alpha1/config.md +++ b/website/content/v1.7/reference/configuration/v1alpha1/config.md @@ -2380,6 +2380,10 @@ EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by +| Field | Type | Description | Value(s) | +|-------|------|-------------|----------| +|`checkSecurebootStatusOnEnroll` |bool |
Check that Secureboot is enabled in the EFI firmware.If Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.
| | + @@ -2499,6 +2503,10 @@ EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by +| Field | Type | Description | Value(s) | +|-------|------|-------------|----------| +|`checkSecurebootStatusOnEnroll` |bool |
Check that Secureboot is enabled in the EFI firmware.If Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.
| | + diff --git a/website/content/v1.7/schemas/config.schema.json b/website/content/v1.7/schemas/config.schema.json index 83b1b3e020..011674a83b 100644 --- a/website/content/v1.7/schemas/config.schema.json +++ b/website/content/v1.7/schemas/config.schema.json @@ -1629,7 +1629,15 @@ "type": "object" }, "v1alpha1.EncryptionKeyTPM": { - "properties": {}, + "properties": { + "checkSecurebootStatusOnEnroll": { + "type": "boolean", + "title": "checkSecurebootStatusOnEnroll", + "description": "Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.\n", + "markdownDescription": "Check that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.", + "x-intellij-html-description": "\u003cp\u003eCheck that Secureboot is enabled in the EFI firmware.\nIf Secureboot is not enabled, the enrollment of the key will fail. As the TPM key is anyways bound to the value of PCR 7, changing Secureboot status or configuration after the initial enrollment will make the key unusable.\u003c/p\u003e\n" + } + }, "additionalProperties": false, "type": "object" },