Skip to content

Commit 962b09b

Browse files
authored
Support multiple keys (#5)
* Support multiple keys * Fix add to known hosts script
1 parent 5d242cc commit 962b09b

File tree

6 files changed

+52
-21
lines changed

6 files changed

+52
-21
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ make build-httpserver
2424
**Run pubkey server**
2525

2626
```bash
27-
go run ./cmd/httpserver/main.go [--listen-addr=127.0.0.1:8080] [--ssh-pubkey-file=/etc/ssh/ssh_host_ed25519_key.pub]
27+
go run ./cmd/httpserver/main.go [--listen-addr=127.0.0.1:8080] [--ssh-pubkey-file=/etc/ssh/ssh_host_ed25519_key.pub] [--ssh-pubkey-file=/path/to/container_key.pub]
2828
```
2929

30+
You can specify multiple `--ssh-pubkey-file` flags to serve multiple public keys. The server will serve all pubkeys at the `/pubkey` endpoint, separated by newlines.
31+
3032
**Install dev dependencies**
3133

3234
```bash

cmd/cli/add_to_known_hosts.sh

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,11 @@ if [ $1 = "-h" ]; then
88
exit 0;
99
fi
1010

11-
pubkey=`curl -s $1/pubkey`
12-
ssh-keyscan -H "$2" 2>/dev/null | grep "${pubkey}"
11+
pubkeys=`curl -s $1/pubkey`
12+
host_keys=`ssh-keyscan -H "$2" 2>/dev/null; ssh-keyscan -H -p 10022 "$2" 2>/dev/null`
13+
14+
echo "$pubkeys" | while IFS= read -r pubkey; do
15+
if [ -n "$pubkey" ]; then
16+
echo "$host_keys" | grep "${pubkey}"
17+
fi
18+
done

cmd/httpserver/main.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import (
1414
)
1515

1616
var flags []cli.Flag = []cli.Flag{
17-
&cli.StringFlag{
17+
&cli.StringSliceFlag{
1818
Name: "ssh-pubkey-file",
19-
Value: "/etc/ssh/ssh_host_ed25519_key.pub",
20-
Usage: "path to file containing pubkey to serve",
19+
Value: cli.NewStringSlice("/etc/ssh/ssh_host_ed25519_key.pub"),
20+
Usage: "path to file containing pubkey to serve (can be specified multiple times)",
2121
},
2222
&cli.StringFlag{
2323
Name: "listen-addr",
@@ -99,7 +99,7 @@ func main() {
9999
ReadTimeout: 60 * time.Second,
100100
WriteTimeout: 30 * time.Second,
101101

102-
SSHPubkeyPath: cCtx.String("ssh-pubkey-file"),
102+
SSHPubkeyPaths: cCtx.StringSlice("ssh-pubkey-file"),
103103
}
104104

105105
srv, err := httpserver.New(cfg)

httpserver/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func (s *Server) handleGetPubkey(w http.ResponseWriter, r *http.Request) {
1818
m.Record(r.Context(), float64(time.Since(start).Microseconds()))
1919
}(time.Now())
2020

21-
_, err := w.Write(s.sshPubkey)
21+
_, err := w.Write(s.sshPubkeys)
2222
if err != nil {
2323
s.log.Error("could not serve pubkey", "err", err)
2424
}

httpserver/handler_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ func Test_Handlers_Healthcheck_Drain_Undrain(t *testing.T) {
2929

3030
//nolint: exhaustruct
3131
s, err := New(&HTTPServerConfig{
32-
DrainDuration: latency,
33-
ListenAddr: listenAddr,
34-
Log: getTestLogger(),
35-
SSHPubkeyPath: "./test_key.pub",
32+
DrainDuration: latency,
33+
ListenAddr: listenAddr,
34+
Log: getTestLogger(),
35+
SSHPubkeyPaths: []string{"./test_key.pub", "./test_key.pub"},
3636
})
3737
require.NoError(t, err)
3838

@@ -45,7 +45,10 @@ func Test_Handlers_Healthcheck_Drain_Undrain(t *testing.T) {
4545
data, err := io.ReadAll(resp.Body)
4646
require.NoError(t, err)
4747
require.Equal(t, http.StatusOK, resp.StatusCode)
48-
require.Equal(t, data, []byte("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFGGVd5nQewq0hETk2Tr/P7OZxTW/4aftdfh9/cAe7FC"))
48+
expectedKey := []byte("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFGGVd5nQewq0hETk2Tr/P7OZxTW/4aftdfh9/cAe7FC")
49+
expectedOutput := append(expectedKey, '\n')
50+
expectedOutput = append(expectedOutput, expectedKey...)
51+
require.Equal(t, expectedOutput, data)
4952
}
5053

5154
{ // Check health

httpserver/server.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,37 +28,57 @@ type HTTPServerConfig struct {
2828
ReadTimeout time.Duration
2929
WriteTimeout time.Duration
3030

31-
SSHPubkeyPath string
31+
SSHPubkeyPaths []string
3232
}
3333

3434
type Server struct {
3535
cfg *HTTPServerConfig
3636
isReady atomic.Bool
3737
log *slog.Logger
3838

39-
sshPubkey []byte
39+
sshPubkeys []byte
4040

4141
srv *http.Server
4242
metricsSrv *metrics.MetricsServer
4343
}
4444

45-
func New(cfg *HTTPServerConfig) (srv *Server, err error) {
46-
metricsSrv, err := metrics.New(common.PackageName, cfg.MetricsAddr)
45+
func readAndFormatPubkey(path string) ([]byte, error) {
46+
if path == "" {
47+
return nil, nil
48+
}
49+
50+
pubkey, err := os.ReadFile(path)
4751
if err != nil {
4852
return nil, err
4953
}
5054

51-
sshPubkey, err := os.ReadFile(cfg.SSHPubkeyPath)
55+
// pubkey is in the form <type> <key> <host>. we want to drop the host
56+
return bytes.Join(bytes.Fields(pubkey)[0:2], []byte(" ")), nil
57+
}
58+
59+
func New(cfg *HTTPServerConfig) (srv *Server, err error) {
60+
metricsSrv, err := metrics.New(common.PackageName, cfg.MetricsAddr)
5261
if err != nil {
5362
return nil, err
5463
}
55-
// pubkey is in the form <type> <key> <host>. we want to drop the host
56-
sshPubkey = bytes.Join(bytes.Fields(sshPubkey)[0:2], []byte(" "))
64+
65+
var pubkeys [][]byte
66+
67+
// Read all specified pubkey files
68+
for _, path := range cfg.SSHPubkeyPaths {
69+
if pubkey, err := readAndFormatPubkey(path); err != nil {
70+
return nil, err
71+
} else if pubkey != nil {
72+
pubkeys = append(pubkeys, pubkey)
73+
}
74+
}
75+
76+
combinedPubkeys := bytes.Join(pubkeys, []byte("\n"))
5777

5878
srv = &Server{
5979
cfg: cfg,
6080
log: cfg.Log,
61-
sshPubkey: sshPubkey,
81+
sshPubkeys: combinedPubkeys,
6282
srv: nil,
6383
metricsSrv: metricsSrv,
6484
}

0 commit comments

Comments
 (0)