From fbff1555fcf6a52fb7dec3144d252090c415a031 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 17 Feb 2022 13:28:14 -0800 Subject: [PATCH] ipnlocal, tailssh: start moving host key stuff into the right spot Make tailssh ask LocalBackend for the SSH hostkeys, as we'll need to distribute them to peers. For now only the hacky use-same-as-actual-host mode is implemented. Updates #3802 Change-Id: I819dcb25c14e42e6692c441186c1dc744441592b Signed-off-by: Brad Fitzpatrick --- ipn/ipnlocal/ssh.go | 48 ++++++++++++++++++++++++++++++++++++++++++ ssh/tailssh/tailssh.go | 18 ++++++---------- 2 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 ipn/ipnlocal/ssh.go diff --git a/ipn/ipnlocal/ssh.go b/ipn/ipnlocal/ssh.go new file mode 100644 index 000000000..ff81e6f1b --- /dev/null +++ b/ipn/ipnlocal/ssh.go @@ -0,0 +1,48 @@ +// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux +// +build linux + +package ipnlocal + +import ( + "errors" + "io/ioutil" + "os" + + "golang.org/x/crypto/ssh" + "tailscale.com/envknob" +) + +var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS") + +func (b *LocalBackend) GetSSHHostKeys() ([]ssh.Signer, error) { + // TODO(bradfitz): generate host keys, at least as needed if + // an existing SSH server didn't put them on disk. But also + // because people may want tailscale-specific ones. For now be + // lazy and reuse the host ones. + return b.getSystemSSHHostKeys() +} + +func (b *LocalBackend) getSystemSSHHostKeys() (ret []ssh.Signer, err error) { + for _, typ := range []string{"rsa", "ecdsa", "ed25519"} { + hostKey, err := ioutil.ReadFile("/etc/ssh/ssh_host_" + typ + "_key") + if os.IsNotExist(err) { + continue + } + if err != nil { + return nil, err + } + signer, err := ssh.ParsePrivateKey(hostKey) + if err != nil { + return nil, err + } + ret = append(ret, signer) + } + if len(ret) == 0 { + return nil, errors.New("no system SSH host keys found") + } + return ret, nil +} diff --git a/ssh/tailssh/tailssh.go b/ssh/tailssh/tailssh.go index de1dcce5e..28c0f9f6b 100644 --- a/ssh/tailssh/tailssh.go +++ b/ssh/tailssh/tailssh.go @@ -12,7 +12,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net" "os" "os/exec" @@ -21,7 +20,6 @@ import ( "github.com/creack/pty" "github.com/gliderlabs/ssh" - gossh "golang.org/x/crypto/ssh" "inet.af/netaddr" "tailscale.com/envknob" "tailscale.com/ipn/ipnlocal" @@ -35,14 +33,6 @@ import ( // Handle handles an SSH connection from c. func Handle(logf logger.Logf, lb *ipnlocal.LocalBackend, c net.Conn) error { - hostKey, err := ioutil.ReadFile("/etc/ssh/ssh_host_ed25519_key") - if err != nil { - return err - } - signer, err := gossh.ParsePrivateKey(hostKey) - if err != nil { - return err - } sshd := &server{lb, logf} srv := &ssh.Server{ Handler: sshd.handleSSH, @@ -59,7 +49,13 @@ func Handle(logf logger.Logf, lb *ipnlocal.LocalBackend, c net.Conn) error { for k, v := range ssh.DefaultSubsystemHandlers { srv.SubsystemHandlers[k] = v } - srv.AddHostKey(signer) + keys, err := lb.GetSSHHostKeys() + if err != nil { + return err + } + for _, signer := range keys { + srv.AddHostKey(signer) + } srv.HandleConn(c) return nil