mirror of
https://github.com/siderolabs/talos.git
synced 2026-05-05 12:26:21 +02:00
feat: seed the kernel random pool from the TPM
Use the TPM2 feature to provide high-quality random bytes. Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
parent
c81ce8cfb0
commit
d23d04de2a
1
go.mod
1
go.mod
@ -54,6 +54,7 @@ require (
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/google/go-tpm v0.9.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/google/nftables v0.1.0
|
||||
github.com/google/uuid v1.3.0
|
||||
|
||||
2
go.sum
2
go.sum
@ -687,6 +687,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
|
||||
github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk=
|
||||
github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/siderolabs/talos/internal/pkg/mount"
|
||||
"github.com/siderolabs/talos/internal/pkg/mount/switchroot"
|
||||
"github.com/siderolabs/talos/internal/pkg/rng"
|
||||
"github.com/siderolabs/talos/pkg/machinery/constants"
|
||||
"github.com/siderolabs/talos/pkg/machinery/extensions"
|
||||
"github.com/siderolabs/talos/pkg/version"
|
||||
@ -51,6 +52,12 @@ func run() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Seed RNG.
|
||||
if err = rng.TPMSeed(); err != nil {
|
||||
// not making this fatal error
|
||||
log.Printf("failed to seed from the TPM: %s", err)
|
||||
}
|
||||
|
||||
log.Printf("booting Talos %s", version.Tag)
|
||||
|
||||
// Mount the rootfs.
|
||||
|
||||
41
internal/pkg/rng/pool.go
Normal file
41
internal/pkg/rng/pool.go
Normal file
@ -0,0 +1,41 @@
|
||||
// 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 rng
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// GetPoolSize returns kernel random pool size.
|
||||
func GetPoolSize() (int, error) {
|
||||
contents, err := os.ReadFile("/proc/sys/kernel/random/poolsize")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return strconv.Atoi(string(bytes.TrimSpace(contents)))
|
||||
}
|
||||
|
||||
// WriteEntropy writes entropy data to the pool.
|
||||
func WriteEntropy(data []byte) error {
|
||||
fd, err := os.OpenFile("/dev/urandom", os.O_WRONLY|unix.O_CLOEXEC|unix.O_NOCTTY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fd.Close() //nolint:errcheck
|
||||
|
||||
_, err = fd.Write(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing entropy: %w", err)
|
||||
}
|
||||
|
||||
return fd.Close()
|
||||
}
|
||||
6
internal/pkg/rng/rng.go
Normal file
6
internal/pkg/rng/rng.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 rng handles interaction with kernel random number generator.
|
||||
package rng
|
||||
87
internal/pkg/rng/tpm.go
Normal file
87
internal/pkg/rng/tpm.go
Normal file
@ -0,0 +1,87 @@
|
||||
// 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 rng
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-tpm/tpm2"
|
||||
"github.com/google/go-tpm/tpm2/transport"
|
||||
)
|
||||
|
||||
// TPMSeed seeds the random entropy pool from the TPM.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func TPMSeed() error {
|
||||
t, err := transport.OpenTPM()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Printf("TPM device is not available")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("error opening TPM device: %w", err)
|
||||
}
|
||||
|
||||
defer t.Close() //nolint:errcheck
|
||||
|
||||
caps, err := tpm2.GetCapability{
|
||||
Capability: tpm2.TPMCapTPMProperties,
|
||||
Property: uint32(tpm2.TPMPTManufacturer),
|
||||
PropertyCount: 1,
|
||||
}.Execute(t)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting TPM capabilities: %w", err)
|
||||
}
|
||||
|
||||
props, err := caps.CapabilityData.Data.TPMProperties()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting properties: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("TPM manufacturer ID: %08x", props.TPMProperty[0].Value)
|
||||
|
||||
poolSize, err := GetPoolSize()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting pool size: %w", err)
|
||||
}
|
||||
|
||||
remaining := poolSize
|
||||
start := time.Now()
|
||||
|
||||
for remaining > 0 {
|
||||
chunk := 32 // default to small chunk (size of AES key)
|
||||
if remaining < chunk {
|
||||
chunk = remaining
|
||||
}
|
||||
|
||||
cmd := tpm2.GetRandom{
|
||||
BytesRequested: uint16(chunk),
|
||||
}
|
||||
|
||||
resp, err := cmd.Execute(t)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting random data from the TPM: %w", err)
|
||||
}
|
||||
|
||||
if len(resp.RandomBytes.Buffer) == 0 {
|
||||
return fmt.Errorf("received zero random bytes from the TPM: %w", err)
|
||||
}
|
||||
|
||||
if err = WriteEntropy(resp.RandomBytes.Buffer); err != nil {
|
||||
return fmt.Errorf("error writing random pool entropy: %w", err)
|
||||
}
|
||||
|
||||
remaining -= len(resp.RandomBytes.Buffer)
|
||||
}
|
||||
|
||||
log.Printf("seeded random pool with %d bytes from the TPM in %s", poolSize, time.Since(start))
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user