mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-14 06:57:31 +00:00
ipn/store: automatically migrate between plaintext and encrypted state (#16318)
Add a new `--encrypt-state` flag to `cmd/tailscaled`. Based on that flag, migrate the existing state file to/from encrypted format if needed. Updates #15830 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
@@ -569,11 +569,12 @@ type TestNode struct {
|
||||
env *TestEnv
|
||||
tailscaledParser *nodeOutputParser
|
||||
|
||||
dir string // temp dir for sock & state
|
||||
configFile string // or empty for none
|
||||
sockFile string
|
||||
stateFile string
|
||||
upFlagGOOS string // if non-empty, sets TS_DEBUG_UP_FLAG_GOOS for cmd/tailscale CLI
|
||||
dir string // temp dir for sock & state
|
||||
configFile string // or empty for none
|
||||
sockFile string
|
||||
stateFile string
|
||||
upFlagGOOS string // if non-empty, sets TS_DEBUG_UP_FLAG_GOOS for cmd/tailscale CLI
|
||||
encryptState bool
|
||||
|
||||
mu sync.Mutex
|
||||
onLogLine []func([]byte)
|
||||
@@ -640,7 +641,7 @@ func (n *TestNode) diskPrefs() *ipn.Prefs {
|
||||
if _, err := os.ReadFile(n.stateFile); err != nil {
|
||||
t.Fatalf("reading prefs: %v", err)
|
||||
}
|
||||
fs, err := store.NewFileStore(nil, n.stateFile)
|
||||
fs, err := store.New(nil, n.stateFile)
|
||||
if err != nil {
|
||||
t.Fatalf("reading prefs, NewFileStore: %v", err)
|
||||
}
|
||||
@@ -822,6 +823,9 @@ func (n *TestNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon {
|
||||
if n.configFile != "" {
|
||||
cmd.Args = append(cmd.Args, "--config="+n.configFile)
|
||||
}
|
||||
if n.encryptState {
|
||||
cmd.Args = append(cmd.Args, "--encrypt-state")
|
||||
}
|
||||
cmd.Env = append(os.Environ(),
|
||||
"TS_DEBUG_PERMIT_HTTP_C2N=1",
|
||||
"TS_LOG_TARGET="+n.env.LogCatcherServer.URL,
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"tailscale.com/client/tailscale"
|
||||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/cmd/testwrapper/flakytest"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tstun"
|
||||
@@ -1470,3 +1472,60 @@ func TestNetstackUDPLoopback(t *testing.T) {
|
||||
|
||||
d1.MustCleanShutdown(t)
|
||||
}
|
||||
|
||||
func TestEncryptStateMigration(t *testing.T) {
|
||||
if !hostinfo.New().TPM.Present() {
|
||||
t.Skip("TPM not available")
|
||||
}
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "windows" {
|
||||
t.Skip("--encrypt-state for tailscaled state not supported on this platform")
|
||||
}
|
||||
tstest.Shard(t)
|
||||
tstest.Parallel(t)
|
||||
env := NewTestEnv(t)
|
||||
n := NewTestNode(t, env)
|
||||
|
||||
runNode := func(t *testing.T, wantStateKeys []string) {
|
||||
t.Helper()
|
||||
|
||||
// Run the node.
|
||||
d := n.StartDaemon()
|
||||
n.AwaitResponding()
|
||||
n.MustUp()
|
||||
n.AwaitRunning()
|
||||
|
||||
// Check the contents of the state file.
|
||||
buf, err := os.ReadFile(n.stateFile)
|
||||
if err != nil {
|
||||
t.Fatalf("reading %q: %v", n.stateFile, err)
|
||||
}
|
||||
t.Logf("state file content:\n%s", buf)
|
||||
var content map[string]any
|
||||
if err := json.Unmarshal(buf, &content); err != nil {
|
||||
t.Fatalf("parsing %q: %v", n.stateFile, err)
|
||||
}
|
||||
for _, k := range wantStateKeys {
|
||||
if _, ok := content[k]; !ok {
|
||||
t.Errorf("state file is missing key %q", k)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the node.
|
||||
d.MustCleanShutdown(t)
|
||||
}
|
||||
|
||||
wantPlaintextStateKeys := []string{"_machinekey", "_current-profile", "_profiles"}
|
||||
wantEncryptedStateKeys := []string{"key", "nonce", "data"}
|
||||
t.Run("regular-state", func(t *testing.T) {
|
||||
n.encryptState = false
|
||||
runNode(t, wantPlaintextStateKeys)
|
||||
})
|
||||
t.Run("migrate-to-encrypted", func(t *testing.T) {
|
||||
n.encryptState = true
|
||||
runNode(t, wantEncryptedStateKeys)
|
||||
})
|
||||
t.Run("migrate-to-plaintext", func(t *testing.T) {
|
||||
n.encryptState = false
|
||||
runNode(t, wantPlaintextStateKeys)
|
||||
})
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
_ "tailscale.com/util/eventbus"
|
||||
_ "tailscale.com/util/multierr"
|
||||
_ "tailscale.com/util/osshare"
|
||||
_ "tailscale.com/util/syspolicy"
|
||||
_ "tailscale.com/version"
|
||||
_ "tailscale.com/version/distro"
|
||||
_ "tailscale.com/wgengine"
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
_ "tailscale.com/util/eventbus"
|
||||
_ "tailscale.com/util/multierr"
|
||||
_ "tailscale.com/util/osshare"
|
||||
_ "tailscale.com/util/syspolicy"
|
||||
_ "tailscale.com/version"
|
||||
_ "tailscale.com/version/distro"
|
||||
_ "tailscale.com/wgengine"
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
_ "tailscale.com/util/eventbus"
|
||||
_ "tailscale.com/util/multierr"
|
||||
_ "tailscale.com/util/osshare"
|
||||
_ "tailscale.com/util/syspolicy"
|
||||
_ "tailscale.com/version"
|
||||
_ "tailscale.com/version/distro"
|
||||
_ "tailscale.com/wgengine"
|
||||
|
@@ -51,6 +51,7 @@ import (
|
||||
_ "tailscale.com/util/eventbus"
|
||||
_ "tailscale.com/util/multierr"
|
||||
_ "tailscale.com/util/osshare"
|
||||
_ "tailscale.com/util/syspolicy"
|
||||
_ "tailscale.com/version"
|
||||
_ "tailscale.com/version/distro"
|
||||
_ "tailscale.com/wgengine"
|
||||
|
Reference in New Issue
Block a user