ipn/ipnlocal, feature/ssh: move SSH code out of LocalBackend to feature

This makes tsnet apps not depend on x/crypto/ssh and locks that in with a test.

It also paves the wave for tsnet apps to opt-in to SSH support via a
blank feature import in the future.

Updates #12614

Change-Id: Ica85628f89c8f015413b074f5001b82b27c953a9
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-03-10 21:33:12 +00:00
committed by Brad Fitzpatrick
parent 99e3e9af51
commit f905871fb1
23 changed files with 371 additions and 423 deletions
-23
View File
@@ -32,7 +32,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"tailscale.com/net/tsdial"
"tailscale.com/tailcfg"
@@ -631,28 +630,6 @@ type testBackend struct {
allowSendEnv bool
}
func (tb *testBackend) GetSSH_HostKeys() ([]gossh.Signer, error) {
var result []gossh.Signer
var priv any
var err error
const keySize = 2048
priv, err = rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
return nil, err
}
mk, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, err
}
hostKey := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: mk})
signer, err := gossh.ParsePrivateKey(hostKey)
if err != nil {
return nil, err
}
result = append(result, signer)
return result, nil
}
func (tb *testBackend) ShouldRunSSH() bool {
return true
}