From c5491b9da8c5c5611da9fb4a50ea1356f10c23ea Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 4 May 2020 00:54:58 +0200 Subject: [PATCH] internal: add simple keyscanner This is an initial implementation and not a replacement candidate for ssh-keyscan since it does only scan the key of the algorithm the client and server agreed upon. This agreement may change depending on the key being used, making it useless for distributed usages. --- go.mod | 1 + internal/keyscan/keyscan.go | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 internal/keyscan/keyscan.go diff --git a/go.mod b/go.mod index 3c98c107..f1a5e416 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/fluxcd/source-controller v0.0.1-alpha.2 github.com/manifoldco/promptui v0.7.0 github.com/spf13/cobra v1.0.0 + golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 k8s.io/api v0.18.2 k8s.io/apimachinery v0.18.2 k8s.io/client-go v0.18.2 diff --git a/internal/keyscan/keyscan.go b/internal/keyscan/keyscan.go new file mode 100644 index 00000000..fce7f7eb --- /dev/null +++ b/internal/keyscan/keyscan.go @@ -0,0 +1,40 @@ +package keyscan + +import ( + "encoding/base64" + "fmt" + "net" + + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/knownhosts" +) + +func ScanKeys(host string) ([]byte, error) { + col := &collector{} + config := &ssh.ClientConfig{ + User: "git", + HostKeyCallback: col.StoreKey(), + } + client, err := ssh.Dial("tcp", host, config) + if err == nil { + defer client.Close() + } + if len(col.knownKeys) > 0 { + return col.knownKeys, nil + } + return col.knownKeys, err +} + +type collector struct { + knownKeys []byte +} + +func (c *collector) StoreKey() ssh.HostKeyCallback { + return func(hostname string, remote net.Addr, key ssh.PublicKey) error { + c.knownKeys = append( + c.knownKeys, + fmt.Sprintf("%s %s %s\n", knownhosts.Normalize(hostname), key.Type(), base64.StdEncoding.EncodeToString(key.Marshal()))..., + ) + return nil + } +}