Skip to content

Commit

Permalink
generate cert
Browse files Browse the repository at this point in the history
  • Loading branch information
dvush committed Sep 25, 2024
1 parent 99bae9f commit 96df65e
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 126 deletions.
24 changes: 5 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,10 @@ v: ## Show the version
clean: ## Clean the build directory
rm -rf build/

.PHONY: build-cli
build-cli: ## Build the CLI
.PHONY: build
build: ## Build the HTTP server
@mkdir -p ./build
go build -trimpath -ldflags "-X github.com/flashbots/orderflow-proxy/common.Version=${VERSION}" -v -o ./build/cli cmd/cli/main.go

.PHONY: build-httpserver
build-httpserver: ## Build the HTTP server
@mkdir -p ./build
go build -trimpath -ldflags "-X github.com/flashbots/orderflow-proxy/common.Version=${VERSION}" -v -o ./build/httpserver cmd/httpserver/main.go
go build -trimpath -ldflags "-X github.com/flashbots/orderflow-proxy/common.Version=${VERSION}" -v -o ./build/orderflow-proxy cmd/httpserver/main.go

##@ Test & Development

Expand Down Expand Up @@ -75,17 +70,8 @@ cover-html: ## Run tests with coverage and open the HTML report
go tool cover -html=/tmp/go-sim-lb.cover.tmp
unlink /tmp/go-sim-lb.cover.tmp

.PHONY: docker-cli
docker-cli: ## Build the CLI Docker image
DOCKER_BUILDKIT=1 docker build \
--platform linux/amd64 \
--build-arg VERSION=${VERSION} \
--file cli.dockerfile \
--tag your-project \
.

.PHONY: docker-httpserver
docker-httpserver: ## Build the HTTP server Docker image
.PHONY: docker
docker: ## Build the HTTP server Docker image
DOCKER_BUILDKIT=1 docker build \
--platform linux/amd64 \
--build-arg VERSION=${VERSION} \
Expand Down
58 changes: 16 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,31 @@
# go-template
# orderflow-proxy

[![Goreport status](https://goreportcard.com/badge/github.com/flashbots/orderflow-proxy)](https://goreportcard.com/report/github.com/flashbots/go-template)
[![Test status](https://github.com/flashbots/orderflow-proxy/actions/workflows/checks.yml/badge.svg?branch=main)](https://github.com/flashbots/go-template/actions?query=workflow%3A%22Checks%22)

Toolbox and building blocks for new Go projects, to get started quickly and right-footed!

* [`Makefile`](https://github.com/flashbots/orderflow-proxy/blob/main/Makefile) with `lint`, `test`, `build`, `fmt` and more
* Linting with `gofmt`, `gofumpt`, `go vet`, `staticcheck` and `golangci-lint`
* Logging setup using the [slog logger](https://pkg.go.dev/golang.org/x/exp/slog) (with debug and json logging options)
* [GitHub Workflows](.github/workflows/) for linting and testing, as well as releasing and publishing Docker images
* Entry files for [CLI](/cmd/cli/main.go) and [HTTP server](/cmd/httpserver/main.go)
* Webserver with
* Graceful shutdown, implementing `livez`, `readyz` and draining API handlers
* Prometheus metrics
* Using https://pkg.go.dev/github.com/go-chi/chi/v5 for routing
* [Urfave](https://cli.urfave.org/) for cli args
* https://github.com/uber-go/nilaway
* See also:
* Public project setup: https://github.com/flashbots/flashbots-repository-template
* Repository for common Go utilities: https://github.com/flashbots/go-utils

Pick and choose whatever is useful to you! Don't feel the need to use everything, or even to follow this structure.

---

## Getting started

**Build CLI**
**Build**

```bash
make build-cli
```
make build
``**

**Build HTTP server**
## Run

```bash
make build-httpserver
```
`./build/orderflow-proxy`

**Install dev dependencies**
Will

```bash
go install mvdan.cc/[email protected]
go install honnef.co/go/tools/cmd/[email protected]
go install github.com/golangci/golangci-lint/cmd/[email protected]
go install go.uber.org/nilaway/cmd/[email protected]
go install github.com/daixiang0/[email protected]
```
* create metrics server
* internal server (liveness endpoints)
* orderflow proxy server that will generate self signed certificate and use it to accept requests that will be proxied to the local builder endpoint

**Lint, test, format**
Flags for the orderflow proxy

```bash
make lint
make test
make fmt
```
--listen-addr value address to listen on for orderflow proxy API (default: "127.0.0.1:9090")
--builder-endpoint value address to send local ordeflow to (default: "127.0.0.1:8546")
--cert-duration value generated certificate duration (default: 8760h0m0s)
--cert-hosts value [ --cert-hosts value ] generated certificate hosts (default: "127.0.0.1", "localhost")
```
55 changes: 0 additions & 55 deletions cmd/cli/main.go

This file was deleted.

Binary file added cmd/httpserver/httpserver
Binary file not shown.
56 changes: 51 additions & 5 deletions cmd/httpserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import (

"github.com/flashbots/orderflow-proxy/common"
"github.com/flashbots/orderflow-proxy/httpserver"
"github.com/flashbots/orderflow-proxy/proxy"
"github.com/google/uuid"
"github.com/urfave/cli/v2" // imports as package "cli"
)

var flags []cli.Flag = []cli.Flag{
&cli.StringFlag{
Name: "listen-addr",
Name: "internal-listen-addr",
Value: "127.0.0.1:8080",
Usage: "address to listen on for API",
Usage: "address to listen on for internal API",
},
&cli.StringFlag{
Name: "metrics-addr",
Expand Down Expand Up @@ -54,15 +55,35 @@ var flags []cli.Flag = []cli.Flag{
Value: 45,
Usage: "seconds to wait in drain HTTP request",
},
&cli.StringFlag{
Name: "listen-addr",
Value: "127.0.0.1:9090",
Usage: "address to listen on for orderflow proxy API",
},
&cli.StringFlag{
Name: "builder-endpoint",
Value: "127.0.0.1:8546",
Usage: "address to send local ordeflow to",
},
&cli.DurationFlag{
Name: "cert-duration",
Value: time.Hour * 24 * 365,
Usage: "generated certificate duration",
},
&cli.StringSliceFlag{
Name: "cert-hosts",
Value: cli.NewStringSlice("127.0.0.1", "localhost"),
Usage: "generated certificate hosts",
},
}

func main() {
app := &cli.App{
Name: "httpserver",
Name: "orderflow-proxy",
Usage: "Serve API, and metrics",
Flags: flags,
Action: func(cCtx *cli.Context) error {
listenAddr := cCtx.String("listen-addr")
internalListenAddr := cCtx.String("internal-listen-addr")
metricsAddr := cCtx.String("metrics-addr")
logJSON := cCtx.Bool("log-json")
logDebug := cCtx.Bool("log-debug")
Expand All @@ -84,7 +105,7 @@ func main() {
}

cfg := &httpserver.HTTPServerConfig{
ListenAddr: listenAddr,
ListenAddr: internalListenAddr,
MetricsAddr: metricsAddr,
Log: log,
EnablePprof: enablePprof,
Expand All @@ -104,6 +125,31 @@ func main() {
exit := make(chan os.Signal, 1)
signal.Notify(exit, os.Interrupt, syscall.SIGTERM)
srv.RunInBackground()

builderEndpoint := cCtx.String("builder-endpoint")
listedAddr := cCtx.String("listen-addr")
certDuration := cCtx.Duration("cert-duration")
certHosts := cCtx.StringSlice("cert-hosts")
proxyConfig := &proxy.Config{
Log: log,
MetricsServer: srv.MetricsSrv,
BuilderEndpoint: builderEndpoint,
ListenAddr: listedAddr,
CertValidDuration: certDuration,
CertHosts: certHosts,
}

proxy, err := proxy.New(*proxyConfig)
if err != nil {
cfg.Log.Error("failed to create proxy server", "err", err)
return err
}
err = proxy.RunProxyInBackground()
if err != nil {
cfg.Log.Error("failed to start proxy server", "err", err)
return err
}

<-exit

// Shutdown server once termination signal is received
Expand Down
2 changes: 1 addition & 1 deletion httpserver/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

func (srv *Server) handleAPI(w http.ResponseWriter, r *http.Request) {
m := srv.metricsSrv.Float64Histogram(
m := srv.MetricsSrv.Float64Histogram(
"request_duration_api",
"API request handling duration",
metrics.UomMicroseconds,
Expand Down
8 changes: 4 additions & 4 deletions httpserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Server struct {
log *slog.Logger

srv *http.Server
metricsSrv *metrics.MetricsServer
MetricsSrv *metrics.MetricsServer
}

func New(cfg *HTTPServerConfig) (srv *Server, err error) {
Expand All @@ -46,7 +46,7 @@ func New(cfg *HTTPServerConfig) (srv *Server, err error) {
cfg: cfg,
log: cfg.Log,
srv: nil,
metricsSrv: metricsSrv,
MetricsSrv: metricsSrv,
}
srv.isReady.Swap(true)

Expand Down Expand Up @@ -84,7 +84,7 @@ func (srv *Server) RunInBackground() {
if srv.cfg.MetricsAddr != "" {
go func() {
srv.log.With("metricsAddress", srv.cfg.MetricsAddr).Info("Starting metrics server")
err := srv.metricsSrv.ListenAndServe()
err := srv.MetricsSrv.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
srv.log.Error("HTTP server failed", "err", err)
}
Expand Down Expand Up @@ -115,7 +115,7 @@ func (srv *Server) Shutdown() {
ctx, cancel := context.WithTimeout(context.Background(), srv.cfg.GracefulShutdownDuration)
defer cancel()

if err := srv.metricsSrv.Shutdown(ctx); err != nil {
if err := srv.MetricsSrv.Shutdown(ctx); err != nil {
srv.log.Error("Graceful metrics server shutdown failed", "err", err)
} else {
srv.log.Info("Metrics server gracefully stopped")
Expand Down
79 changes: 79 additions & 0 deletions proxy/cert_gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package proxy

Check failure on line 1 in proxy/cert_gen.go

View workflow job for this annotation

GitHub Actions / Lint

at least one file in a package should have a package comment (ST1000)

import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"time"
)

// hosts is a list of ip / dns names for the certificate

Check failure on line 16 in proxy/cert_gen.go

View workflow job for this annotation

GitHub Actions / Lint

comment on exported function GenerateCert should be of the form "GenerateCert ..." (ST1020)
func GenerateCert(validFor time.Duration, hosts []string) (cert, key []byte, err error) {
// copied from https://go.dev/src/crypto/tls/generate_cert.go
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

Check failure on line 19 in proxy/cert_gen.go

View workflow job for this annotation

GitHub Actions / Lint

this value of err is never used (SA4006)
keyUsage := x509.KeyUsageDigitalSignature

notBefore := time.Now()
notAfter := notBefore.Add(validFor)

serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, err
}

template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme"},
},
NotBefore: notBefore,
NotAfter: notAfter,

KeyUsage: keyUsage,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}

for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}

// certificate is its own CA
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign

derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
return nil, nil, err
}

var certOut bytes.Buffer
if err = pem.Encode(&certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return nil, nil, err
}
cert = certOut.Bytes()

privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, nil, err
}

var keyOut bytes.Buffer
err = pem.Encode(&keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
if err != nil {
return nil, nil, err
}
key = keyOut.Bytes()
return
}
Loading

0 comments on commit 96df65e

Please sign in to comment.