mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 11:41:39 +00:00
ipn/ipnlocal: blend existing host SSH keys + newly-generated types as needed
If the host only has RSA, use its RSA + generate ecdsa + ed25519, etc. Perhaps fixes https://twitter.com/colek42c/status/1550554439299244032 and something else that was reported. Change-Id: I88dc475c8e3d95b6f25288ff7664b8e72655fd16 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
e5176f572e
commit
eae003e56f
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tailscale/golang-x-crypto/ssh"
|
"github.com/tailscale/golang-x-crypto/ssh"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
|
"tailscale.com/util/mak"
|
||||||
)
|
)
|
||||||
|
|
||||||
var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS")
|
var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS")
|
||||||
@ -36,34 +37,39 @@ var useHostKeys = envknob.Bool("TS_USE_SYSTEM_SSH_HOST_KEYS")
|
|||||||
var keyTypes = []string{"rsa", "ecdsa", "ed25519"}
|
var keyTypes = []string{"rsa", "ecdsa", "ed25519"}
|
||||||
|
|
||||||
func (b *LocalBackend) GetSSH_HostKeys() (keys []ssh.Signer, err error) {
|
func (b *LocalBackend) GetSSH_HostKeys() (keys []ssh.Signer, err error) {
|
||||||
|
var existing map[string]ssh.Signer
|
||||||
if os.Geteuid() == 0 {
|
if os.Geteuid() == 0 {
|
||||||
keys, err = b.getSystemSSH_HostKeys()
|
existing = b.getSystemSSH_HostKeys()
|
||||||
if err != nil || len(keys) > 0 {
|
|
||||||
return keys, err
|
|
||||||
}
|
}
|
||||||
// Otherwise, perhaps they don't have OpenSSH etc installed.
|
return b.getTailscaleSSH_HostKeys(existing)
|
||||||
// Generate our own keys...
|
|
||||||
}
|
|
||||||
return b.getTailscaleSSH_HostKeys()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) getTailscaleSSH_HostKeys() (keys []ssh.Signer, err error) {
|
// getTailscaleSSH_HostKeys returns the three (rsa, ecdsa, ed25519) SSH host
|
||||||
|
// keys, reusing the provided ones in existing if present in the map.
|
||||||
|
func (b *LocalBackend) getTailscaleSSH_HostKeys(existing map[string]ssh.Signer) (keys []ssh.Signer, err error) {
|
||||||
|
var keyDir string // lazily initialized $TAILSCALE_VAR/ssh dir.
|
||||||
|
for _, typ := range keyTypes {
|
||||||
|
if s, ok := existing[typ]; ok {
|
||||||
|
keys = append(keys, s)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if keyDir == "" {
|
||||||
root := b.TailscaleVarRoot()
|
root := b.TailscaleVarRoot()
|
||||||
if root == "" {
|
if root == "" {
|
||||||
return nil, errors.New("no var root for ssh keys")
|
return nil, errors.New("no var root for ssh keys")
|
||||||
}
|
}
|
||||||
keyDir := filepath.Join(root, "ssh")
|
keyDir = filepath.Join(root, "ssh")
|
||||||
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
if err := os.MkdirAll(keyDir, 0700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, typ := range keyTypes {
|
}
|
||||||
hostKey, err := b.hostKeyFileOrCreate(keyDir, typ)
|
hostKey, err := b.hostKeyFileOrCreate(keyDir, typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error creating SSH host key type %q in %q: %w", typ, keyDir, err)
|
||||||
}
|
}
|
||||||
signer, err := ssh.ParsePrivateKey(hostKey)
|
signer, err := ssh.ParsePrivateKey(hostKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error parsing SSH host key type %q from %q: %w", typ, keyDir, err)
|
||||||
}
|
}
|
||||||
keys = append(keys, signer)
|
keys = append(keys, signer)
|
||||||
}
|
}
|
||||||
@ -115,24 +121,21 @@ func (b *LocalBackend) hostKeyFileOrCreate(keyDir, typ string) ([]byte, error) {
|
|||||||
return pemGen, err
|
return pemGen, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) getSystemSSH_HostKeys() (ret []ssh.Signer, err error) {
|
func (b *LocalBackend) getSystemSSH_HostKeys() (ret map[string]ssh.Signer) {
|
||||||
// TODO(bradfitz): cache this?
|
|
||||||
for _, typ := range keyTypes {
|
for _, typ := range keyTypes {
|
||||||
filename := "/etc/ssh/ssh_host_" + typ + "_key"
|
filename := "/etc/ssh/ssh_host_" + typ + "_key"
|
||||||
hostKey, err := ioutil.ReadFile(filename)
|
hostKey, err := ioutil.ReadFile(filename)
|
||||||
if os.IsNotExist(err) || len(bytes.TrimSpace(hostKey)) == 0 {
|
if err != nil || len(bytes.TrimSpace(hostKey)) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signer, err := ssh.ParsePrivateKey(hostKey)
|
signer, err := ssh.ParsePrivateKey(hostKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading private key %s: %w", filename, err)
|
b.logf("warning: error reading host key %s: %v (generating one instead)", filename, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
ret = append(ret, signer)
|
mak.Set(&ret, typ, signer)
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) getSSHHostKeyPublicStrings() (ret []string) {
|
func (b *LocalBackend) getSSHHostKeyPublicStrings() (ret []string) {
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
func TestSSHKeyGen(t *testing.T) {
|
func TestSSHKeyGen(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
lb := &LocalBackend{varRoot: dir}
|
lb := &LocalBackend{varRoot: dir}
|
||||||
keys, err := lb.getTailscaleSSH_HostKeys()
|
keys, err := lb.getTailscaleSSH_HostKeys(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ func TestSSHKeyGen(t *testing.T) {
|
|||||||
t.Fatalf("keys = %v; want %v", got, want)
|
t.Fatalf("keys = %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
keys2, err := lb.getTailscaleSSH_HostKeys()
|
keys2, err := lb.getTailscaleSSH_HostKeys(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user