ipn/ipnlocal: don't fail profile unmarshal due to attestation keys (#18335)
Soft-fail on initial unmarshal and try again, ignoring the AttestationKey. This helps in cases where something about the attestation key storage (usually a TPM) is messed up. The old key will be lost, but at least the node can start again. Updates #18302 Updates #15830 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
package ipnlocal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/user"
|
||||
"strconv"
|
||||
@@ -1147,3 +1148,40 @@ func TestProfileStateChangeCallback(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProfileBadAttestationKey(t *testing.T) {
|
||||
store := new(mem.Store)
|
||||
pm, err := newProfileManagerWithGOOS(store, t.Logf, health.NewTracker(eventbustest.NewBus(t)), "linux")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fk := new(failingHardwareAttestationKey)
|
||||
pm.newEmptyHardwareAttestationKey = func() (key.HardwareAttestationKey, error) {
|
||||
return fk, nil
|
||||
}
|
||||
sk := ipn.StateKey(t.Name())
|
||||
if err := pm.store.WriteState(sk, []byte(`{"Config": {"AttestationKey": {}}}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prefs, err := pm.loadSavedPrefs(sk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ak := prefs.Persist().AsStruct().AttestationKey
|
||||
if _, ok := ak.(noopAttestationKey); !ok {
|
||||
t.Errorf("loaded attestation key of type %T, want noopAttestationKey", ak)
|
||||
}
|
||||
if !fk.unmarshalCalled {
|
||||
t.Error("UnmarshalJSON was not called on failingHardwareAttestationKey")
|
||||
}
|
||||
}
|
||||
|
||||
type failingHardwareAttestationKey struct {
|
||||
noopAttestationKey
|
||||
unmarshalCalled bool
|
||||
}
|
||||
|
||||
func (k *failingHardwareAttestationKey) UnmarshalJSON([]byte) error {
|
||||
k.unmarshalCalled = true
|
||||
return errors.New("failed to unmarshal attestation key!")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user