feat: provide an option to enforce SecureBoot for TPM enrollment

Fixes #8995

There is no security impact, as the actual SecureBoot
state/configuration is measured into the PCR 7 and the disk encryption
key unsealing is tied to this value.

This is more to provide a way to avoid accidentally encrypting to the
TPM while SecureBoot is not enabled.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2024-07-11 18:16:56 +04:00
parent 736c1485e2
commit cf5effabb2
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
10 changed files with 76 additions and 8 deletions

View File

@ -563,7 +563,9 @@ func create(ctx context.Context) 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:

View File

@ -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")

View File

@ -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

View File

@ -396,6 +396,7 @@ type EncryptionKeyNodeID interface {
// EncryptionKeyTPM encryption key sealed by TPM.
type EncryptionKeyTPM interface {
CheckSecurebootOnEnroll() bool
String() string
}

View File

@ -1649,7 +1649,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"
},

View File

@ -1456,6 +1456,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

View File

@ -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{}

View File

@ -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

View File

@ -2397,6 +2397,10 @@ EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by
| Field | Type | Description | Value(s) |
|-------|------|-------------|----------|
|`checkSecurebootStatusOnEnroll` |bool |<details><summary>Check that Secureboot is enabled in the EFI firmware.</summary>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.</details> | |
@ -2516,6 +2520,10 @@ EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by
| Field | Type | Description | Value(s) |
|-------|------|-------------|----------|
|`checkSecurebootStatusOnEnroll` |bool |<details><summary>Check that Secureboot is enabled in the EFI firmware.</summary>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.</details> | |

View File

@ -1649,7 +1649,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"
},