Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add mtls authentication for the API #87

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions op-defender/cmd/defender/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ func PSPExecutorMain(ctx *cli.Context, closeApp context.CancelCauseFunc) (cliapp
if err != nil {
return nil, fmt.Errorf("Failed to parse psp_executor config from flags: %w", err)
}
if err := cfg.Check(); err != nil {
return nil, err
}

metricsRegistry := opmetrics.NewRegistry()
executor := &executor.DefenderExecutor{}
Expand Down
33 changes: 31 additions & 2 deletions op-defender/psp_executor/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package psp_executor

import (
opservice "github.com/ethereum-optimism/optimism/op-service"
optls "github.com/ethereum-optimism/optimism/op-service/tls"
"github.com/ethereum/go-ethereum/common"

"github.com/urfave/cli/v2"
)

Expand All @@ -27,6 +27,7 @@ type CLIConfig struct {
SuperChainConfigAddress common.Address
SafeAddress common.Address
ChainID uint64
TLSConfig optls.CLIConfig
}

func ReadCLIFlags(ctx *cli.Context) (CLIConfig, error) {
Expand All @@ -39,13 +40,14 @@ func ReadCLIFlags(ctx *cli.Context) (CLIConfig, error) {
SafeAddress: common.HexToAddress(ctx.String(SafeAddressFlagName)),
ChainID: ctx.Uint64(ChainIDFlagName),
BlockDuration: ctx.Uint64(BlockDurationFlagName),
TLSConfig: optls.ReadCLIConfig(ctx),
}

return cfg, nil
}

func CLIFlags(envPrefix string) []cli.Flag {
return []cli.Flag{
flags := []cli.Flag{
&cli.StringFlag{
Name: NodeURLFlagName,
Usage: "Node URL of a peer",
Expand Down Expand Up @@ -97,4 +99,31 @@ func CLIFlags(envPrefix string) []cli.Flag {
Required: true,
},
}
// Add mtls flags
flags = append(flags, []cli.Flag{
&cli.StringFlag{
Name: optls.TLSCaCertFlagName,
Usage: "tls ca cert path",
EnvVars: opservice.PrefixEnvVar(envPrefix, "TLS_CA"),
},
&cli.StringFlag{
Name: optls.TLSCertFlagName,
Usage: "tls cert path",
EnvVars: opservice.PrefixEnvVar(envPrefix, "TLS_CERT"),
},
&cli.StringFlag{
Name: optls.TLSKeyFlagName,
Usage: "tls key",
EnvVars: opservice.PrefixEnvVar(envPrefix, "TLS_KEY"),
},
}...)
return flags
}

func (c CLIConfig) Check() error {

if err := c.TLSConfig.Check(); err != nil {
return err
}
return nil
}
43 changes: 42 additions & 1 deletion op-defender/psp_executor/defender.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package psp_executor
import (
"context"
"crypto/ecdsa"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
optls "github.com/ethereum-optimism/optimism/op-service/tls"
"github.com/ethereum-optimism/optimism/op-service/tls/certman"
"math/big"
"net/http"
"os"
Expand Down Expand Up @@ -85,6 +89,8 @@ type Defender struct {
highestBlockNumber *prometheus.GaugeVec
unexpectedRpcErrors *prometheus.CounterVec
GetNonceAndFetchAndSimulateAtBlockError *prometheus.CounterVec
// mtls configuration
TLSConfig optls.CLIConfig
}

// Define a struct that represents the data structure of your PSP.
Expand Down Expand Up @@ -364,6 +370,8 @@ func NewDefender(ctx context.Context, log log.Logger, m metrics.Factory, cfg CLI
Name: "unexpectedRpcErrors",
Help: "number of unexpected rpc errors",
}, []string{"section", "name"}),
/** mtls configuration **/
TLSConfig: cfg.TLSConfig,
}
chainID, err := defender.executor.ReturnCorrectChainID(l1client, cfg.ChainID)
if err != nil {
Expand Down Expand Up @@ -586,8 +594,41 @@ func (d *Defender) Run(ctx context.Context) {
time.Sleep(d.blockDuration * time.Second) // Sleep for `d.blockDuration` seconds to make sure the PSP is executed onchain.
}
}()
server := &http.Server{
Addr: ":" + d.port,
Handler: d.router,
}
if d.TLSConfig.TLSEnabled() {
d.log.Info("tlsConfig specified, loading tls config")
caCert, err := os.ReadFile(d.TLSConfig.TLSCaCert)
if err != nil {
d.log.Error("[MON] failed to read tls.ca", "error", err)
return
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

cm, err := certman.New(d.log, d.TLSConfig.TLSCert, d.TLSConfig.TLSKey)
if err != nil {
d.log.Error("[MON] failed to read tls cert or key", "err", err)
return
}
if err := cm.Watch(); err != nil {
d.log.Error("[MON] failed to start certman watcher", "err", err)
return
}
server.TLSConfig = &tls.Config{
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
return cm.GetCertificate(nil)
},
}

}

err := server.ListenAndServeTLS("", "") // Start the HTTP server blocking thread for now.

err := http.ListenAndServe(":"+d.port, d.router) // Start the HTTP server blocking thread for now.
if err != nil {
d.log.Crit("failed to start the API server", "error", err)
}
Expand Down