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

Add client certificate, require client certificate verification #1924

Merged
merged 11 commits into from
Oct 24, 2023
41 changes: 31 additions & 10 deletions arbnode/dataposter/data_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,22 +175,36 @@ func NewDataPoster(ctx context.Context, opts *DataPosterOpts) (*DataPoster, erro
}

func rpcClient(ctx context.Context, opts *ExternalSignerCfg) (*rpc.Client, error) {
rootCrt, err := os.ReadFile(opts.RootCA)
if err != nil {
return nil, fmt.Errorf("error reading external signer root CA: %w", err)
tlsCfg := &tls.Config{
MinVersion: tls.VersionTLS12,
}

if opts.ClientCert != "" && opts.ClientPrivateKey != "" {
log.Info("Client certificate for external signer is enabled")
clientCert, err := tls.LoadX509KeyPair(opts.ClientCert, opts.ClientPrivateKey)
if err != nil {
return nil, fmt.Errorf("error loading client certificate and private key: %w", err)
}
tlsCfg.Certificates = []tls.Certificate{clientCert}
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(rootCrt)

if opts.RootCA != "" {
rootCrt, err := os.ReadFile(opts.RootCA)
if err != nil {
return nil, fmt.Errorf("error reading external signer root CA: %w", err)
}
rootCertPool := x509.NewCertPool()
rootCertPool.AppendCertsFromPEM(rootCrt)
tlsCfg.RootCAs = rootCertPool
}

return rpc.DialOptions(
ctx,
opts.URL,
rpc.WithHTTPClient(
&http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: pool,
},
TLSClientConfig: tlsCfg,
},
},
),
Expand Down Expand Up @@ -743,9 +757,14 @@ type ExternalSignerCfg struct {
Address string `koanf:"address"`
// API method name (e.g. eth_signTransaction).
Method string `koanf:"method"`
// Path to the external signer root CA certificate.
// (Optional) Path to the external signer root CA certificate.
// This allows us to use self-signed certificats on the external signer.
RootCA string `koanf:"root-ca"`
// (Optional) Client certificate for mtls.
ClientCert string `koanf:"client-cert"`
// (Optional) Client certificate key for mtls.
// This is required when client-cert is set.
ClientPrivateKey string `koanf:"client-private-key"`
}

type DangerousConfig struct {
Expand Down Expand Up @@ -788,6 +807,8 @@ func addExternalSignerOptions(prefix string, f *pflag.FlagSet) {
f.String(prefix+".address", DefaultDataPosterConfig.ExternalSigner.Address, "external signer address")
f.String(prefix+".method", DefaultDataPosterConfig.ExternalSigner.Method, "external signer method")
f.String(prefix+".root-ca", DefaultDataPosterConfig.ExternalSigner.RootCA, "external signer root CA")
f.String(prefix+".client-cert", DefaultDataPosterConfig.ExternalSigner.ClientCert, "rpc client cert")
f.String(prefix+".client-private-key", DefaultDataPosterConfig.ExternalSigner.ClientPrivateKey, "rpc client private key")
}

var DefaultDataPosterConfig = DataPosterConfig{
Expand Down
31 changes: 26 additions & 5 deletions arbnode/dataposter/dataposter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package dataposter

import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -74,10 +76,12 @@ func TestExternalSigner(t *testing.T) {
}()
signer, addr, err := externalSigner(ctx,
&ExternalSignerCfg{
Address: srv.address.Hex(),
URL: "https://localhost:1234",
Method: "test_signTransaction",
RootCA: cert,
Address: srv.address.Hex(),
URL: "https://localhost:1234",
Method: "test_signTransaction",
RootCA: cert,
ClientCert: "./testdata/client.crt",
ClientPrivateKey: "./testdata/client.key",
})
if err != nil {
t.Fatalf("Error getting external signer: %v", err)
Expand Down Expand Up @@ -129,7 +133,24 @@ func newServer(ctx context.Context, t *testing.T) (*http.Server, *server) {
"test_signTransaction": s.signTransaction,
}
m := http.NewServeMux()
httpSrv := &http.Server{Addr: ":1234", Handler: m, ReadTimeout: 5 * time.Second}

clientCert, err := os.ReadFile("./testdata/client.crt")
if err != nil {
t.Fatalf("Error reading client certificate: %v", err)
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(clientCert)

httpSrv := &http.Server{
Addr: ":1234",
Handler: m,
ReadTimeout: 5 * time.Second,
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: pool,
},
}
m.HandleFunc("/", s.mux)
return httpSrv, s
}
Expand Down
52 changes: 52 additions & 0 deletions arbnode/dataposter/testdata/client.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[req]
default_bits = 2048
default_keyfile = server-key.pem
distinguished_name = subject
req_extensions = req_ext
x509_extensions = x509_ext
string_mask = utf8only

[subject]
countryName = CH
countryName_default = CH

stateOrProvinceName = Zurich
stateOrProvinceName_default = ZH

localityName = city
localityName_default = Zurich

organizationName = Offchain Labs
organizationName_default = Offchain Labs

commonName = offchainlabs.ch
commonName_default = localhost

emailAddress = Email Address
emailAddress_default = [email protected]

[x509_ext]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"

[req_ext]
subjectKeyIdentifier = hash

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"

[alternate_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1

[alternate_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1

28 changes: 28 additions & 0 deletions arbnode/dataposter/testdata/client.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIE0jCCA7qgAwIBAgIUPaBB3/hHMpZfGB3VOw1+mHG4LnUwDQYJKoZIhvcNAQEL
BQAwgYMxCzAJBgNVBAYTAkNIMQswCQYDVQQIDAJaSDEPMA0GA1UEBwwGWnVyaWNo
MRYwFAYDVQQKDA1PZmZjaGFpbiBMYWJzMRIwEAYDVQQDDAlsb2NhbGhvc3QxKjAo
BgkqhkiG9w0BCQEWG25vdGFiaWdkZWFsQG9mZmNoYWlubGFicy5jaDAeFw0yMzEw
MTYxNDU2MjhaFw0yNDEwMTUxNDU2MjhaMIGDMQswCQYDVQQGEwJDSDELMAkGA1UE
CAwCWkgxDzANBgNVBAcMBlp1cmljaDEWMBQGA1UECgwNT2ZmY2hhaW4gTGFiczES
MBAGA1UEAwwJbG9jYWxob3N0MSowKAYJKoZIhvcNAQkBFhtub3RhYmlnZGVhbEBv
ZmZjaGFpbmxhYnMuY2gwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1
1asfUzv07QTVwlM4o3g51ilIFEApPkpdQej/GIItLEVRQW+GI9jYuEM07wdwMhSH
JPFNbZB3dmBuqDLx13hY03ufyeY+nab0/sO6x13kXChvIqgPRyJtkEAoYkMM3W0D
S6HeL/6DFoTQ2xAlZb/7i/9deuUwDL3MNVSjPCm9PjFzSOFgAQQud2uUT7aENGuG
Whw3oXz9gU/8gv3keLzcIa2PHyEW5M7jeGSYMjfW3wr0d+Z5mSNRc/U6kncKi06c
QrMKrgFfF7a5kHgxUL7bRCGgCMemXe7VfrW6oKT11JcLWDKhe+uo6bNXUptek55H
HfQi6x8cbM46/h3riZA3AgMBAAGjggE6MIIBNjAdBgNVHQ4EFgQUQD2BOems0+JQ
br234cW5noMmXRIwga0GA1UdIwSBpTCBoqGBiaSBhjCBgzELMAkGA1UEBhMCQ0gx
CzAJBgNVBAgMAlpIMQ8wDQYDVQQHDAZadXJpY2gxFjAUBgNVBAoMDU9mZmNoYWlu
IExhYnMxEjAQBgNVBAMMCWxvY2FsaG9zdDEqMCgGCSqGSIb3DQEJARYbbm90YWJp
Z2RlYWxAb2ZmY2hhaW5sYWJzLmNoghQ9oEHf+Ecyll8YHdU7DX6YcbgudTAJBgNV
HRMEAjAAMAsGA1UdDwQEAwIFoDAfBgNVHREEGDAWgglsb2NhbGhvc3SCCTEyNy4w
LjAuMTAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh
dGUwDQYJKoZIhvcNAQELBQADggEBAF4EVkOZZeMIvv0JViP7NsmIl2ke/935x6Hd
hQiLUw13XHYXzMa5/8Y5fnKjttBODpFoQlwjgI18vzuYzItYMBc2cabQJcpfG+Wq
M3m/wl1TC2XOuHj1E4RA/nU3tslntahtXG+vkks9RN+f9irHUhDRR6AGSnSB2Gi/
B2OGmXn7S4Qge8+fGHAjN+tlu+tOoEWP6R3if/a9UIe5EGM8QTe4zw6lr+iPrOhC
M94pK5IEWn5IIGhr3zJIYkm/Dp+rFqhV1sqPOjjFLVCA7KJ3jVVVHlcm4Xa/+fyk
CIm7/VAmnbeUNlMbkXNOfQMeku8Iwsu80pvf3kjhU/PgO/5oojk=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions arbnode/dataposter/testdata/client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC11asfUzv07QTV
wlM4o3g51ilIFEApPkpdQej/GIItLEVRQW+GI9jYuEM07wdwMhSHJPFNbZB3dmBu
qDLx13hY03ufyeY+nab0/sO6x13kXChvIqgPRyJtkEAoYkMM3W0DS6HeL/6DFoTQ
2xAlZb/7i/9deuUwDL3MNVSjPCm9PjFzSOFgAQQud2uUT7aENGuGWhw3oXz9gU/8
gv3keLzcIa2PHyEW5M7jeGSYMjfW3wr0d+Z5mSNRc/U6kncKi06cQrMKrgFfF7a5
kHgxUL7bRCGgCMemXe7VfrW6oKT11JcLWDKhe+uo6bNXUptek55HHfQi6x8cbM46
/h3riZA3AgMBAAECggEADUboCYMCpm+LqIhzNCtqswQD6QsiSwCmqs8nuKZGk9ue
+hmZj5IpgMJZLrgvWY4s+PGfgiRR/28QCBrVXkETiZ5zirQFN4tvLlKcSK4xZf29
FBRUCiPxck36NhiqrBNOi1Mn8BKedl4cESkvSu1cvcmeOh100HPcHfLDVqHx3qsl
D/5yMkT2+zdhtLa+X3nkAa+3aibOvgtyfkV679e20CG6h89N9GBKkTXO8ioLZZVm
84ksnd4FcpTo7ebJJxElEB+ZA4akPHbF6ArUmcpqtGso5GtwqqO2ZlguSn2XQT0d
jqvOG4DwfSXk6SpE/dpWvU92fmxWAxZvGrZNgDyJ2QKBgQDyQ8NN4b80Yza/YXar
LWx8A6B0eMc1dXgt9m3UUI+titt45jEcaXhCX01FRFTznWGmWFtJmcWBoaQVPVel
IcDYQSxEuBUrCeI75ocv/IQtENaiX3TK7Nlz5RHfpQpfDVJq45lpiD38CGkYkAif
9pSzC8aup4W3WR0JJZ1AOHUZaQKBgQDAJNJnaSNzB+eDWTKCIN5V9X3QMkmjsuir
Nf2lBXHYARnlYWAbtYFG12wLJQMTNX5ewVQQrWtsdPkGPpCnPLelUTxMssrsXjej
JlLzYUfzRBqEXMI3AA9bVdiauxId2RTcp2F81SM1keCMcuHYxrzVkBSOC9u3wCnb
Whb6+feInwKBgQCbzgC5AcoaQwReqKvNAvWV/C8hONvFAbs8tBOGTBlbHsZvRnun
Lh1tciUbuwp3cmvuszxiZUakS/RexIitZrvDWIbD2y+h8kVRCL1Am0HWSdH/syxF
pXVkF5obHuVApCyxGZb8S+axRCdy6I7jcY3IaHZqtMpGVEVcMJilSKnmoQKBgQCC
tEmgaMfhhx34nqOaG4vDA4T7LEolnh1h4g9RwztnCZC5FZ1QHA79xqrLhfjqhzgY
cwChe6aYl5WSptq1uLrgLTuMnQ8m7QyB4h8JSkKse8ZiBctjqJnJssLutpSjUzk6
xG2vgjk6RqpuP/PcB40K5cDlw7FJ9OFEQqthPMsi1wKBgQC0/vv5bY3DQ+wV6gUy
nFoSa/XNHaa8y7jmmlCnWJqs6DAAQQ3VW0tPX03GYL/NDcI+PwzYDHDkSB6Qa/o8
VzVGK1/kr/+bveNvqmi0vNb54fMFLveGgsY4Cu1cffiw8m6nYJ/V4eCsHfpF1B5L
5HDnt5rFKt1Mi9WsUSRtxipxBA==
-----END PRIVATE KEY-----
3 changes: 1 addition & 2 deletions cmd/genericconf/pprof.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ func StartPprof(address string) {
log.Info("Starting metrics server with pprof", "addr", fmt.Sprintf("http://%s/debug/metrics", address))
log.Info("Pprof endpoint", "addr", fmt.Sprintf("http://%s/debug/pprof", address))
go func() {
// #nosec G114
if err := http.ListenAndServe(address, http.DefaultServeMux); err != nil {
if err := http.ListenAndServe(address, http.DefaultServeMux); /* #nosec G114 */ err != nil {
log.Error("Failure in running pprof server", "err", err)
}
}()
Expand Down
Loading