Skip to content

Commit

Permalink
Add a new remoteva binary (#7437)
Browse files Browse the repository at this point in the history
* Adds a new `remoteva` binary that takes a distinct configuration from
the existing `boulder-va`
* Removed the `boulder-remoteva` name registration from `boulder-va`. 
  * Existing users of `boulder-remoteva` must either 
1. laterally migrate to `boulder-va` which uses that same config, or
    2. switch to using `remoteva` with a new config.

Part of #5294
  • Loading branch information
pgporada authored May 6, 2024
1 parent b7553f1 commit c1561b0
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 70 deletions.
53 changes: 7 additions & 46 deletions cmd/boulder-va/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,19 @@ import (

"github.com/letsencrypt/boulder/bdns"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/config"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
"github.com/letsencrypt/boulder/va"
vaConfig "github.com/letsencrypt/boulder/va/config"
vapb "github.com/letsencrypt/boulder/va/proto"
)

type Config struct {
VA struct {
cmd.ServiceConfig

UserAgent string

IssuerDomain string

// DNSTries is the number of times to try a DNS query (that has a temporary error)
// before giving up. May be short-circuited by deadlines. A zero value
// will be turned into 1.
DNSTries int
DNSProvider *cmd.DNSProvider `validate:"required_without=DNSStaticResolvers"`
// DNSStaticResolvers is a list of DNS resolvers. Each entry must
// be a host or IP and port separated by a colon. IPv6 addresses
// must be enclosed in square brackets.
DNSStaticResolvers []string `validate:"required_without=DNSProvider,dive,hostname_port"`
DNSTimeout config.Duration `validate:"required"`
DNSAllowLoopbackAddresses bool

vaConfig.Common
RemoteVAs []cmd.GRPCClientConfig `validate:"omitempty,dive"`
MaxRemoteValidationFailures int `validate:"omitempty,min=0,required_with=RemoteVAs"`

Features features.Config

AccountURIPrefixes []string `validate:"min=1,dive,required,url"`
Features features.Config
}

Syslog cmd.SyslogConfig
Expand All @@ -60,27 +40,13 @@ func main() {
var c Config
err := cmd.ReadConfigFile(*configFile, &c)
cmd.FailOnError(err, "Reading JSON config file into config structure")
err = c.VA.SetDefaultsAndValidate(grpcAddr, debugAddr)
cmd.FailOnError(err, "Setting and validating default config values")

features.Set(c.VA.Features)

if *grpcAddr != "" {
c.VA.GRPC.Address = *grpcAddr
}
if *debugAddr != "" {
c.VA.DebugAddr = *debugAddr
}

scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.VA.DebugAddr)
defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString())

if c.VA.DNSTimeout.Duration == 0 {
cmd.Fail("'dnsTimeout' is required")
}
dnsTries := c.VA.DNSTries
if dnsTries < 1 {
dnsTries = 1
}
clk := cmd.Clock()

var servers bdns.ServerProvider
Expand Down Expand Up @@ -108,7 +74,7 @@ func main() {
servers,
scope,
clk,
dnsTries,
c.VA.DNSTries,
logger,
tlsConfig)
} else {
Expand All @@ -117,11 +83,10 @@ func main() {
servers,
scope,
clk,
dnsTries,
c.VA.DNSTries,
logger,
tlsConfig)
}

var remotes []va.RemoteVA
if len(c.VA.RemoteVAs) > 0 {
for _, rva := range c.VA.RemoteVAs {
Expand Down Expand Up @@ -157,13 +122,9 @@ func main() {
&vapb.VA_ServiceDesc, vai).Add(
&vapb.CAA_ServiceDesc, vai).Build(tlsConfig, scope, clk)
cmd.FailOnError(err, "Unable to setup VA gRPC server")

cmd.FailOnError(start(), "VA gRPC service failed")
}

func init() {
cmd.RegisterCommand("boulder-va", main, &cmd.ConfigValidator{Config: &Config{}})
// We register under two different names, because it's convenient for the
// remote VAs to show up under a different program name when looking at logs.
cmd.RegisterCommand("boulder-remoteva", main, &cmd.ConfigValidator{Config: &Config{}})
}
1 change: 0 additions & 1 deletion cmd/boulder-va/main_test.go

This file was deleted.

1 change: 1 addition & 0 deletions cmd/boulder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
_ "github.com/letsencrypt/boulder/cmd/nonce-service"
_ "github.com/letsencrypt/boulder/cmd/notify-mailer"
_ "github.com/letsencrypt/boulder/cmd/ocsp-responder"
_ "github.com/letsencrypt/boulder/cmd/remoteva"
_ "github.com/letsencrypt/boulder/cmd/reversed-hostname-checker"
_ "github.com/letsencrypt/boulder/cmd/rocsp-tool"
"github.com/letsencrypt/boulder/core"
Expand Down
14 changes: 9 additions & 5 deletions cmd/boulder/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ func TestConfigValidation(t *testing.T) {
fileNames = []string{"publisher.json"}
case "boulder-ra":
fileNames = []string{"ra.json"}
case "boulder-remoteva":
case "boulder-sa":
fileNames = []string{"sa.json"}
case "boulder-va":
fileNames = []string{
"va.json",
"va-remote-a.json",
"va-remote-b.json",
}
case "boulder-sa":
fileNames = []string{"sa.json"}
case "boulder-va":
fileNames = []string{"va.json"}
case "remoteva":
fileNames = []string{
"remoteva-a.json",
"remoteva-b.json",
}
case "boulder-wfe2":
fileNames = []string{"wfe2.json"}
case "nonce-service":
Expand Down
12 changes: 8 additions & 4 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,18 @@ type HostnamePolicyConfig struct {

// TLSConfig represents certificates and a key for authenticated TLS.
type TLSConfig struct {
CertFile string `validate:"required"`
KeyFile string `validate:"required"`
CertFile string `validate:"required"`
KeyFile string `validate:"required"`
// The CACertFile file may contain any number of root certificates and will
// be deduplicated internally.
CACertFile string `validate:"required"`
}

// Load reads and parses the certificates and key listed in the TLSConfig, and
// returns a *tls.Config suitable for either client or server use. Prometheus
// metrics for various certificate fields will be exported.
// returns a *tls.Config suitable for either client or server use. The
// CACertFile file may contain any number of root certificates and will be
// deduplicated internally. Prometheus metrics for various certificate fields
// will be exported.
func (t *TLSConfig) Load(scope prometheus.Registerer) (*tls.Config, error) {
if t == nil {
return nil, fmt.Errorf("nil TLS section in config")
Expand Down
110 changes: 110 additions & 0 deletions cmd/remoteva/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package notmain

import (
"context"
"flag"
"os"
"time"

"github.com/letsencrypt/boulder/bdns"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
"github.com/letsencrypt/boulder/va"
vaConfig "github.com/letsencrypt/boulder/va/config"
vapb "github.com/letsencrypt/boulder/va/proto"
)

type Config struct {
RVA struct {
vaConfig.Common
Features features.Config
}

Syslog cmd.SyslogConfig
OpenTelemetry cmd.OpenTelemetryConfig
}

func main() {
grpcAddr := flag.String("addr", "", "gRPC listen address override")
debugAddr := flag.String("debug-addr", "", "Debug server address override")
configFile := flag.String("config", "", "File path to the configuration file for this service")
flag.Parse()
if *configFile == "" {
flag.Usage()
os.Exit(1)
}

var c Config
err := cmd.ReadConfigFile(*configFile, &c)
cmd.FailOnError(err, "Reading JSON config file into config structure")
err = c.RVA.SetDefaultsAndValidate(grpcAddr, debugAddr)
cmd.FailOnError(err, "Setting and validating default config values")
features.Set(c.RVA.Features)

scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.RVA.DebugAddr)
defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString())
clk := cmd.Clock()

var servers bdns.ServerProvider
proto := "udp"
if features.Get().DOH {
proto = "tcp"
}

if len(c.RVA.DNSStaticResolvers) != 0 {
servers, err = bdns.NewStaticProvider(c.RVA.DNSStaticResolvers)
cmd.FailOnError(err, "Couldn't start static DNS server resolver")
} else {
servers, err = bdns.StartDynamicProvider(c.RVA.DNSProvider, 60*time.Second, proto)
cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver")
}
defer servers.Stop()

tlsConfig, err := c.RVA.TLS.Load(scope)
cmd.FailOnError(err, "tlsConfig config")

var resolver bdns.Client
if !c.RVA.DNSAllowLoopbackAddresses {
resolver = bdns.New(
c.RVA.DNSTimeout.Duration,
servers,
scope,
clk,
c.RVA.DNSTries,
logger,
tlsConfig)
} else {
resolver = bdns.NewTest(
c.RVA.DNSTimeout.Duration,
servers,
scope,
clk,
c.RVA.DNSTries,
logger,
tlsConfig)
}

vai, err := va.NewValidationAuthorityImpl(
resolver,
nil, // Our RVAs will never have RVAs of their own.
0, // Only the VA is concerned with max validation failures
c.RVA.UserAgent,
c.RVA.IssuerDomain,
scope,
clk,
logger,
c.RVA.AccountURIPrefixes)
cmd.FailOnError(err, "Unable to create Remote-VA server")

start, err := bgrpc.NewServer(c.RVA.GRPC, logger).Add(
&vapb.VA_ServiceDesc, vai).Add(
&vapb.CAA_ServiceDesc, vai).Build(tlsConfig, scope, clk)
cmd.FailOnError(err, "Unable to setup Remote-VA gRPC server")
cmd.FailOnError(start(), "Remote-VA gRPC service failed")
}

func init() {
cmd.RegisterCommand("remoteva", main, &cmd.ConfigValidator{Config: &Config{}})
}
48 changes: 48 additions & 0 deletions test/config-next/remoteva-a.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"rva": {
"userAgent": "remoteva-a",
"dnsTries": 3,
"dnsStaticResolvers": [
"10.77.77.77:8343",
"10.77.77.77:8443"
],
"dnsTimeout": "1s",
"dnsAllowLoopbackAddresses": true,
"issuerDomain": "happy-hacker-ca.invalid",
"tls": {
"caCertfile": "test/grpc-creds/minica.pem",
"certFile": "test/grpc-creds/rva.boulder/cert.pem",
"keyFile": "test/grpc-creds/rva.boulder/key.pem"
},
"grpc": {
"maxConnectionAge": "30s",
"services": {
"va.VA": {
"clientNames": [
"va.boulder"
]
},
"grpc.health.v1.Health": {
"clientNames": [
"health-checker.boulder"
]
}
}
},
"features": {
"DOH": true
},
"accountURIPrefixes": [
"http://boulder.service.consul:4000/acme/reg/",
"http://boulder.service.consul:4001/acme/acct/"
]
},
"syslog": {
"stdoutlevel": 4,
"sysloglevel": -1
},
"openTelemetry": {
"endpoint": "bjaeger:4317",
"sampleratio": 1
}
}
48 changes: 48 additions & 0 deletions test/config-next/remoteva-b.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"rva": {
"userAgent": "remoteva-b",
"dnsTries": 3,
"dnsStaticResolvers": [
"10.77.77.77:8343",
"10.77.77.77:8443"
],
"dnsTimeout": "1s",
"dnsAllowLoopbackAddresses": true,
"issuerDomain": "happy-hacker-ca.invalid",
"tls": {
"caCertfile": "test/grpc-creds/minica.pem",
"certFile": "test/grpc-creds/rva.boulder/cert.pem",
"keyFile": "test/grpc-creds/rva.boulder/key.pem"
},
"grpc": {
"maxConnectionAge": "30s",
"services": {
"va.VA": {
"clientNames": [
"va.boulder"
]
},
"grpc.health.v1.Health": {
"clientNames": [
"health-checker.boulder"
]
}
}
},
"features": {
"DOH": true
},
"accountURIPrefixes": [
"http://boulder.service.consul:4000/acme/reg/",
"http://boulder.service.consul:4001/acme/acct/"
]
},
"syslog": {
"stdoutlevel": 4,
"sysloglevel": -1
},
"openTelemetry": {
"endpoint": "bjaeger:4317",
"sampleratio": 1
}
}
2 changes: 1 addition & 1 deletion test/config-next/va-remote-a.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"va": {
"userAgent": "boulder-remote-a",
"userAgent": "boulder-remoteva-a",
"dnsTries": 3,
"dnsStaticResolvers": [
"10.77.77.77:8343",
Expand Down
2 changes: 1 addition & 1 deletion test/config-next/va-remote-b.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"va": {
"userAgent": "boulder-remote-b",
"userAgent": "boulder-remoteva-b",
"dnsTries": 3,
"dnsStaticResolvers": [
"10.77.77.77:8343",
Expand Down
Loading

0 comments on commit c1561b0

Please sign in to comment.