ipn/{conffile,ipnlocal}: start booting tailscaled from a config file w/ auth key

Updates #1412

Change-Id: Icd880035a31df59797b8379f4af19da5c4c453e2
Co-authored-by: Maisem Ali <maisem@tailscale.com>
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2023-10-16 12:15:03 -07:00
committed by Brad Fitzpatrick
parent 6ca8650c7b
commit 1fc3573446
7 changed files with 126 additions and 10 deletions

View File

@@ -41,6 +41,8 @@ import (
"tailscale.com/tstest/integration/testcontrol"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/ptr"
"tailscale.com/util/must"
"tailscale.com/util/rands"
"tailscale.com/version"
)
@@ -312,6 +314,33 @@ func TestOneNodeUpAuth(t *testing.T) {
d1.MustCleanShutdown(t)
}
func TestConfigFileAuthKey(t *testing.T) {
tstest.SkipOnUnshardedCI(t)
tstest.Shard(t)
t.Parallel()
const authKey = "opensesame"
env := newTestEnv(t, configureControl(func(control *testcontrol.Server) {
control.RequireAuthKey = authKey
}))
n1 := newTestNode(t, env)
n1.configFile = filepath.Join(n1.dir, "config.json")
authKeyFile := filepath.Join(n1.dir, "my-auth-key")
must.Do(os.WriteFile(authKeyFile, fmt.Appendf(nil, "%s\n", authKey), 0666))
must.Do(os.WriteFile(n1.configFile, must.Get(json.Marshal(ipn.ConfigVAlpha{
Version: "alpha0",
AuthKey: ptr.To("file:" + authKeyFile),
ServerURL: ptr.To(n1.env.ControlServer.URL),
})), 0644))
d1 := n1.StartDaemon()
n1.AwaitListening()
t.Logf("Got IP: %v", n1.AwaitIP4())
n1.AwaitRunning()
d1.MustCleanShutdown(t)
}
func TestTwoNodes(t *testing.T) {
tstest.Shard(t)
flakytest.Mark(t, "https://github.com/tailscale/tailscale/issues/3598")
@@ -920,6 +949,7 @@ type testNode struct {
env *testEnv
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
@@ -1113,6 +1143,9 @@ func (n *testNode) StartDaemonAsIPNGOOS(ipnGOOS string) *Daemon {
"--tun=userspace-networking",
)
}
if n.configFile != "" {
cmd.Args = append(cmd.Args, "--config="+n.configFile)
}
cmd.Env = append(os.Environ(),
"TS_DEBUG_PERMIT_HTTP_C2N=1",
"TS_LOG_TARGET="+n.env.LogCatcherServer.URL,

View File

@@ -33,6 +33,7 @@ import (
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/ptr"
"tailscale.com/util/must"
"tailscale.com/util/rands"
"tailscale.com/util/set"
)
@@ -45,6 +46,7 @@ type Server struct {
Logf logger.Logf // nil means to use the log package
DERPMap *tailcfg.DERPMap // nil means to use prod DERP map
RequireAuth bool
RequireAuthKey string // required authkey for all nodes
Verbose bool
DNSConfig *tailcfg.DNSConfig // nil means no DNS config
MagicDNSDomain string
@@ -538,6 +540,14 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
j, _ := json.MarshalIndent(req, "", "\t")
log.Printf("Got %T: %s", req, j)
}
if s.RequireAuthKey != "" && req.Auth.AuthKey != s.RequireAuthKey {
res := must.Get(s.encode(mkey, false, tailcfg.RegisterResponse{
Error: "invalid authkey",
}))
w.WriteHeader(200)
w.Write(res)
return
}
// If this is a followup request, wait until interactive followup URL visit complete.
if req.Followup != "" {