Skip to content

Commit bb2f187

Browse files
authored
Pubkey server (#1)
1 parent 39c5afa commit bb2f187

File tree

11 files changed

+65
-115
lines changed

11 files changed

+65
-115
lines changed

Makefile

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ v:
1111
clean:
1212
rm -rf build/
1313

14-
.PHONY: build-cli
15-
build-cli:
16-
@mkdir -p ./build
17-
go build -trimpath -ldflags "-X github.com/flashbots/ssh-pubkey-server/common.Version=${VERSION}" -v -o ./build/cli cmd/cli/main.go
18-
1914
.PHONY: build-httpserver
2015
build-httpserver:
2116
@mkdir -p ./build
@@ -64,15 +59,6 @@ cover-html:
6459
go tool cover -html=/tmp/go-sim-lb.cover.tmp
6560
unlink /tmp/go-sim-lb.cover.tmp
6661

67-
.PHONY: docker-cli
68-
docker-cli:
69-
DOCKER_BUILDKIT=1 docker build \
70-
--platform linux/amd64 \
71-
--build-arg VERSION=${VERSION} \
72-
--file cli.dockerfile \
73-
--tag your-project \
74-
.
75-
7662
.PHONY: docker-httpserver
7763
docker-httpserver:
7864
DOCKER_BUILDKIT=1 docker build \

README.md

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,16 @@
33
[![Goreport status](https://goreportcard.com/badge/github.com/flashbots/ssh-pubkey-server)](https://goreportcard.com/report/github.com/flashbots/go-template)
44
[![Test status](https://github.com/flashbots/ssh-pubkey-server/workflows/Checks/badge.svg?branch=main)](https://github.com/flashbots/go-template/actions?query=workflow%3A%22Checks%22)
55

6-
Toolbox and building blocks for new Go projects, to get started quickly and right-footed!
7-
8-
* [`Makefile`](https://github.com/flashbots/ssh-pubkey-server/blob/main/Makefile) with `lint`, `test`, `build`, `fmt` and more
9-
* Linting with `gofmt`, `gofumpt`, `go vet`, `staticcheck` and `golangci-lint`
10-
* Logging setup using the [slog logger](https://pkg.go.dev/golang.org/x/exp/slog) (with debug and json logging options)
11-
* [GitHub Workflows](.github/workflows/) for linting and testing, as well as releasing and publishing Docker images
12-
* Entry files for [CLI](/cmd/cli/main.go) and [HTTP server](/cmd/httpserver/main.go)
13-
* Webserver with
14-
* Graceful shutdown, implementing `livez`, `readyz` and draining API handlers
15-
* Prometheus metrics
16-
* Using https://pkg.go.dev/github.com/go-chi/chi/v5 for routing
17-
* [Urfave](https://cli.urfave.org/) for cli args
18-
* https://github.com/uber-go/nilaway
19-
* See also:
20-
* Public project setup: https://github.com/flashbots/flashbots-repository-template
21-
* Repository for common Go utilities: https://github.com/flashbots/go-utils
22-
23-
Pick and choose whatever is useful to you! Don't feel the need to use everything, or even to follow this structure.
24-
256
---
267

278
## Getting started
289

29-
**Build CLI**
10+
**Run CLI**
11+
12+
The following will request server ssh pubkey through a proxy, and separately run ssh-keyscan and will return the matching server keys that you can then append to your known_hosts.
3013

3114
```bash
32-
make build-cli
15+
./cmd/cli/add_to_known_hosts.sh <attested http proxy> <host ip> >> ~/.ssh/known_hosts
3316
```
3417

3518
**Build HTTP server**
@@ -38,6 +21,12 @@ make build-cli
3821
make build-httpserver
3922
```
4023

24+
**Run pubkey server**
25+
26+
```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]
28+
```
29+
4130
**Install dev dependencies**
4231

4332
```bash

cli.dockerfile

Lines changed: 0 additions & 18 deletions
This file was deleted.

cmd/cli/add_to_known_hosts.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/sh
2+
3+
# Usage: ./add_to_known_hosts.sh <http proxy> <host ip> >> ~/.ssh/known_hosts
4+
# Makes sure the pubkey returned from proxy matches ssh-keyscan of the host, and formats in a way that can be appended to known_hosts
5+
6+
if [ $1 = "-h" ]; then
7+
echo "Usage: ./add_to_known_hosts.sh <http proxy> <host ip> >> ~/.ssh/known_hosts (or append manually)"
8+
exit 0;
9+
fi
10+
11+
pubkey=`curl -s $1/pubkey`
12+
ssh-keyscan -H "$2" 2>/dev/null | grep "${pubkey}"

cmd/cli/main.go

Lines changed: 0 additions & 55 deletions
This file was deleted.

cmd/httpserver/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import (
1414
)
1515

1616
var flags []cli.Flag = []cli.Flag{
17+
&cli.StringFlag{
18+
Name: "ssh-pubkey-file",
19+
Value: "/etc/ssh/ssh_host_ed25519_key.pub",
20+
Usage: "path to file containing pubkey to serve",
21+
},
1722
&cli.StringFlag{
1823
Name: "listen-addr",
1924
Value: "127.0.0.1:8080",
@@ -93,6 +98,8 @@ func main() {
9398
GracefulShutdownDuration: 30 * time.Second,
9499
ReadTimeout: 60 * time.Second,
95100
WriteTimeout: 30 * time.Second,
101+
102+
SSHPubkeyPath: cCtx.String("ssh-pubkey-file"),
96103
}
97104

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

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/flashbots/ssh-pubkey-server
22

3-
go 1.21
3+
go 1.22
44

55
require (
66
github.com/flashbots/go-utils v0.6.1-0.20240610084140-4461ab748667

httpserver/handler.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/flashbots/ssh-pubkey-server/metrics"
88
)
99

10-
func (s *Server) handleAPI(w http.ResponseWriter, r *http.Request) {
10+
func (s *Server) handleGetPubkey(w http.ResponseWriter, r *http.Request) {
1111
m := s.metricsSrv.Float64Histogram(
1212
"request_duration_api",
1313
"API request handling duration",
@@ -18,9 +18,10 @@ func (s *Server) handleAPI(w http.ResponseWriter, r *http.Request) {
1818
m.Record(r.Context(), float64(time.Since(start).Microseconds()))
1919
}(time.Now())
2020

21-
// do work
22-
23-
w.WriteHeader(http.StatusOK)
21+
_, err := w.Write(s.sshPubkey)
22+
if err != nil {
23+
s.log.Error("could not serve pubkey", "err", err)
24+
}
2425
}
2526

2627
func (s *Server) handleLivenessCheck(w http.ResponseWriter, r *http.Request) {

httpserver/handler_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,22 @@ func Test_Handlers_Healthcheck_Drain_Undrain(t *testing.T) {
3232
DrainDuration: latency,
3333
ListenAddr: listenAddr,
3434
Log: getTestLogger(),
35+
SSHPubkeyPath: "./test_key.pub",
3536
})
3637
require.NoError(t, err)
3738

39+
{ // Check pubkey
40+
req := httptest.NewRequest(http.MethodGet, "http://localhost"+listenAddr+"/pubkey", nil) //nolint:goconst,nolintlint
41+
w := httptest.NewRecorder()
42+
s.handleGetPubkey(w, req)
43+
resp := w.Result()
44+
defer resp.Body.Close()
45+
data, err := io.ReadAll(resp.Body)
46+
require.NoError(t, err)
47+
require.Equal(t, http.StatusOK, resp.StatusCode)
48+
require.Equal(t, data, []byte("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFGGVd5nQewq0hETk2Tr/P7OZxTW/4aftdfh9/cAe7FC"))
49+
}
50+
3851
{ // Check health
3952
req := httptest.NewRequest(http.MethodGet, "http://localhost"+listenAddr+"/readyz", nil) //nolint:goconst,nolintlint
4053
w := httptest.NewRecorder()

httpserver/server.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package httpserver
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"log/slog"
78
"net/http"
9+
"os"
810
"time"
911

12+
"github.com/flashbots/go-utils/httplogger"
1013
"github.com/flashbots/ssh-pubkey-server/common"
1114
"github.com/flashbots/ssh-pubkey-server/metrics"
12-
"github.com/flashbots/go-utils/httplogger"
1315
"github.com/go-chi/chi/v5"
1416
"github.com/go-chi/chi/v5/middleware"
1517
"go.uber.org/atomic"
@@ -25,13 +27,17 @@ type HTTPServerConfig struct {
2527
GracefulShutdownDuration time.Duration
2628
ReadTimeout time.Duration
2729
WriteTimeout time.Duration
30+
31+
SSHPubkeyPath string
2832
}
2933

3034
type Server struct {
3135
cfg *HTTPServerConfig
3236
isReady atomic.Bool
3337
log *slog.Logger
3438

39+
sshPubkey []byte
40+
3541
srv *http.Server
3642
metricsSrv *metrics.MetricsServer
3743
}
@@ -42,16 +48,24 @@ func New(cfg *HTTPServerConfig) (srv *Server, err error) {
4248
return nil, err
4349
}
4450

51+
sshPubkey, err := os.ReadFile(cfg.SSHPubkeyPath)
52+
if err != nil {
53+
return nil, err
54+
}
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(" "))
57+
4558
srv = &Server{
4659
cfg: cfg,
4760
log: cfg.Log,
61+
sshPubkey: sshPubkey,
4862
srv: nil,
4963
metricsSrv: metricsSrv,
5064
}
5165
srv.isReady.Swap(true)
5266

5367
mux := chi.NewRouter()
54-
mux.With(srv.httpLogger).Get("/api", srv.handleAPI) // Never serve at `/` (root) path
68+
mux.With(srv.httpLogger).Get("/pubkey", srv.handleGetPubkey) // Never serve at `/` (root) path
5569
mux.With(srv.httpLogger).Get("/livez", srv.handleLivenessCheck)
5670
mux.With(srv.httpLogger).Get("/readyz", srv.handleReadinessCheck)
5771
mux.With(srv.httpLogger).Get("/drain", srv.handleDrain)

httpserver/test_key.pub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFGGVd5nQewq0hETk2Tr/P7OZxTW/4aftdfh9/cAe7FC user@host

0 commit comments

Comments
 (0)