wgengine/netstack: add an SSH server experiment

Disabled by default.

To use, run tailscaled with:

    TS_SSH_ALLOW_LOGIN=you@bar.com

And enable with:

    $ TAILSCALE_USE_WIP_CODE=true tailscale up --ssh=true

Then ssh [any-user]@[your-tailscale-ip] for a root bash shell.
(both the "root" and "bash" part are temporary)

Updates #3802

Change-Id: I268f8c3c95c8eed5f3231d712a5dc89615a406f0
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-08-26 14:50:55 -07:00
committed by Brad Fitzpatrick
parent 41fd4eab5c
commit f3c0023add
11 changed files with 233 additions and 14 deletions

View File

@@ -39,6 +39,7 @@ import (
"tailscale.com/net/tsdial"
"tailscale.com/paths"
"tailscale.com/portlist"
"tailscale.com/syncs"
"tailscale.com/tailcfg"
"tailscale.com/types/dnstype"
"tailscale.com/types/empty"
@@ -100,6 +101,7 @@ type LocalBackend struct {
serverURL string // tailcontrol URL
newDecompressor func() (controlclient.Decompressor, error)
varRoot string // or empty if SetVarRoot never called
sshAtomicBool syncs.AtomicBool
filterHash deephash.Sum
@@ -1536,6 +1538,9 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
}
b.logf("backend prefs for %q: %s", key, b.prefs.Pretty())
b.sshAtomicBool.Set(b.prefs != nil && b.prefs.RunSSH)
return nil
}
@@ -1709,6 +1714,8 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
netMap := b.netMap
stateKey := b.stateKey
b.sshAtomicBool.Set(newp.RunSSH)
oldp := b.prefs
newp.Persist = oldp.Persist // caller isn't allowed to override this
b.prefs = newp
@@ -2618,8 +2625,11 @@ func (b *LocalBackend) ResetForClientDisconnect() {
b.authURL = ""
b.authURLSticky = ""
b.activeLogin = ""
b.sshAtomicBool.Set(false)
}
func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Get() }
// Logout tells the controlclient that we want to log out, and
// transitions the local engine to the logged-out state without
// waiting for controlclient to be in that state.

View File

@@ -98,6 +98,11 @@ type Prefs struct {
// DNS configuration, if it exists.
CorpDNS bool
// RunSSH bool is whether this node should run an SSH
// server, permitting access to peers according to the
// policies as configured by the Tailnet's admin(s).
RunSSH bool
// WantRunning indicates whether networking should be active on
// this node.
WantRunning bool
@@ -193,6 +198,7 @@ type MaskedPrefs struct {
ExitNodeIPSet bool `json:",omitempty"`
ExitNodeAllowLANAccessSet bool `json:",omitempty"`
CorpDNSSet bool `json:",omitempty"`
RunSSHSet bool `json:",omitempty"`
WantRunningSet bool `json:",omitempty"`
LoggedOutSet bool `json:",omitempty"`
ShieldsUpSet bool `json:",omitempty"`
@@ -277,6 +283,9 @@ func (p *Prefs) pretty(goos string) string {
sb.WriteString("mesh=false ")
}
fmt.Fprintf(&sb, "dns=%v want=%v ", p.CorpDNS, p.WantRunning)
if p.RunSSH {
sb.WriteString("ssh=true ")
}
if p.LoggedOut {
sb.WriteString("loggedout=true ")
}
@@ -348,6 +357,7 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
p.ExitNodeIP == p2.ExitNodeIP &&
p.ExitNodeAllowLANAccess == p2.ExitNodeAllowLANAccess &&
p.CorpDNS == p2.CorpDNS &&
p.RunSSH == p2.RunSSH &&
p.WantRunning == p2.WantRunning &&
p.LoggedOut == p2.LoggedOut &&
p.NotepadURLs == p2.NotepadURLs &&

View File

@@ -40,6 +40,7 @@ var _PrefsCloneNeedsRegeneration = Prefs(struct {
ExitNodeIP netaddr.IP
ExitNodeAllowLANAccess bool
CorpDNS bool
RunSSH bool
WantRunning bool
LoggedOut bool
ShieldsUp bool

View File

@@ -42,6 +42,7 @@ func TestPrefsEqual(t *testing.T) {
"ExitNodeIP",
"ExitNodeAllowLANAccess",
"CorpDNS",
"RunSSH",
"WantRunning",
"LoggedOut",
"ShieldsUp",