From c1561b070b86c67d9a3e9a1a39a6b41142d547df Mon Sep 17 00:00:00 2001 From: Phil Porada Date: Mon, 6 May 2024 16:29:29 -0400 Subject: [PATCH] Add a new remoteva binary (#7437) * 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 https://github.com/letsencrypt/boulder/issues/5294 --- cmd/boulder-va/main.go | 53 ++------------ cmd/boulder-va/main_test.go | 1 - cmd/boulder/main.go | 1 + cmd/boulder/main_test.go | 14 ++-- cmd/config.go | 12 ++-- cmd/remoteva/main.go | 110 ++++++++++++++++++++++++++++++ test/config-next/remoteva-a.json | 48 +++++++++++++ test/config-next/remoteva-b.json | 48 +++++++++++++ test/config-next/va-remote-a.json | 2 +- test/config-next/va-remote-b.json | 2 +- test/config-next/va.json | 10 +++ test/config/remoteva-a.json | 47 +++++++++++++ test/config/remoteva-b.json | 47 +++++++++++++ test/config/va-remote-a.json | 4 +- test/config/va-remote-b.json | 2 +- test/config/va.json | 10 +++ test/consul/config.hcl | 17 +++++ test/startservers.py | 16 +++-- test/v2_integration.py | 10 +-- va/config/config.go | 52 ++++++++++++++ 20 files changed, 436 insertions(+), 70 deletions(-) delete mode 100644 cmd/boulder-va/main_test.go create mode 100644 cmd/remoteva/main.go create mode 100644 test/config-next/remoteva-a.json create mode 100644 test/config-next/remoteva-b.json create mode 100644 test/config/remoteva-a.json create mode 100644 test/config/remoteva-b.json create mode 100644 va/config/config.go diff --git a/cmd/boulder-va/main.go b/cmd/boulder-va/main.go index 0bef1d4f1d1..032435fac49 100644 --- a/cmd/boulder-va/main.go +++ b/cmd/boulder-va/main.go @@ -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 @@ -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 @@ -108,7 +74,7 @@ func main() { servers, scope, clk, - dnsTries, + c.VA.DNSTries, logger, tlsConfig) } else { @@ -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 { @@ -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{}}) } diff --git a/cmd/boulder-va/main_test.go b/cmd/boulder-va/main_test.go deleted file mode 100644 index 227a9d4affb..00000000000 --- a/cmd/boulder-va/main_test.go +++ /dev/null @@ -1 +0,0 @@ -package notmain diff --git a/cmd/boulder/main.go b/cmd/boulder/main.go index 7bbd6a15d5e..c2fcfaab2ef 100644 --- a/cmd/boulder/main.go +++ b/cmd/boulder/main.go @@ -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" diff --git a/cmd/boulder/main_test.go b/cmd/boulder/main_test.go index f4e67e53806..45cfa1d6381 100644 --- a/cmd/boulder/main_test.go +++ b/cmd/boulder/main_test.go @@ -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": diff --git a/cmd/config.go b/cmd/config.go index 1a0309094c9..1a3edabff13 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -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") diff --git a/cmd/remoteva/main.go b/cmd/remoteva/main.go new file mode 100644 index 00000000000..e8364247752 --- /dev/null +++ b/cmd/remoteva/main.go @@ -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{}}) +} diff --git a/test/config-next/remoteva-a.json b/test/config-next/remoteva-a.json new file mode 100644 index 00000000000..14f7ef4de2a --- /dev/null +++ b/test/config-next/remoteva-a.json @@ -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 + } +} diff --git a/test/config-next/remoteva-b.json b/test/config-next/remoteva-b.json new file mode 100644 index 00000000000..82423314446 --- /dev/null +++ b/test/config-next/remoteva-b.json @@ -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 + } +} diff --git a/test/config-next/va-remote-a.json b/test/config-next/va-remote-a.json index 6b2c2c23bff..682e393f0bb 100644 --- a/test/config-next/va-remote-a.json +++ b/test/config-next/va-remote-a.json @@ -1,6 +1,6 @@ { "va": { - "userAgent": "boulder-remote-a", + "userAgent": "boulder-remoteva-a", "dnsTries": 3, "dnsStaticResolvers": [ "10.77.77.77:8343", diff --git a/test/config-next/va-remote-b.json b/test/config-next/va-remote-b.json index de0831dc5e4..e10964f72d1 100644 --- a/test/config-next/va-remote-b.json +++ b/test/config-next/va-remote-b.json @@ -1,6 +1,6 @@ { "va": { - "userAgent": "boulder-remote-b", + "userAgent": "boulder-remoteva-b", "dnsTries": 3, "dnsStaticResolvers": [ "10.77.77.77:8343", diff --git a/test/config-next/va.json b/test/config-next/va.json index f1f788d80d7..bd3ad7677e9 100644 --- a/test/config-next/va.json +++ b/test/config-next/va.json @@ -54,6 +54,16 @@ "serverAddress": "rva1.service.consul:9498", "timeout": "15s", "hostOverride": "rva1.boulder" + }, + { + "serverAddress": "rva2.service.consul:9897", + "timeout": "15s", + "hostOverride": "rva2.boulder" + }, + { + "serverAddress": "rva2.service.consul:9998", + "timeout": "15s", + "hostOverride": "rva2.boulder" } ], "maxRemoteValidationFailures": 1, diff --git a/test/config/remoteva-a.json b/test/config/remoteva-a.json new file mode 100644 index 00000000000..49d7ef5a869 --- /dev/null +++ b/test/config/remoteva-a.json @@ -0,0 +1,47 @@ +{ + "rva": { + "userAgent": "remoteva-a", + "debugAddr": ":8211", + "dnsTries": 3, + "dnsProvider": { + "dnsAuthority": "consul.service.consul", + "srvLookup": { + "service": "dns", + "domain": "service.consul" + } + }, + "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", + "address": ":9897", + "services": { + "va.VA": { + "clientNames": [ + "va.boulder" + ] + }, + "grpc.health.v1.Health": { + "clientNames": [ + "health-checker.boulder" + ] + } + } + }, + "features": {}, + "accountURIPrefixes": [ + "http://boulder.service.consul:4000/acme/reg/", + "http://boulder.service.consul:4001/acme/acct/" + ] + }, + "syslog": { + "stdoutlevel": 4, + "sysloglevel": 4 + } +} diff --git a/test/config/remoteva-b.json b/test/config/remoteva-b.json new file mode 100644 index 00000000000..5adc12af89a --- /dev/null +++ b/test/config/remoteva-b.json @@ -0,0 +1,47 @@ +{ + "rva": { + "userAgent": "remoteva-b", + "debugAddr": ":8212", + "dnsTries": 3, + "dnsProvider": { + "dnsAuthority": "consul.service.consul", + "srvLookup": { + "service": "dns", + "domain": "service.consul" + } + }, + "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", + "address": ":9998", + "services": { + "va.VA": { + "clientNames": [ + "va.boulder" + ] + }, + "grpc.health.v1.Health": { + "clientNames": [ + "health-checker.boulder" + ] + } + } + }, + "features": {}, + "accountURIPrefixes": [ + "http://boulder.service.consul:4000/acme/reg/", + "http://boulder.service.consul:4001/acme/acct/" + ] + }, + "syslog": { + "stdoutlevel": 4, + "sysloglevel": 4 + } +} diff --git a/test/config/va-remote-a.json b/test/config/va-remote-a.json index 5c5f647cf63..2a841578aaa 100644 --- a/test/config/va-remote-a.json +++ b/test/config/va-remote-a.json @@ -1,6 +1,6 @@ { "va": { - "userAgent": "boulder-remote-a", + "userAgent": "boulder-remoteva-a", "debugAddr": ":8011", "dnsTries": 3, "dnsProvider": { @@ -20,7 +20,7 @@ }, "grpc": { "maxConnectionAge": "30s", - "address": ":9097", + "address": ":9397", "services": { "va.VA": { "clientNames": [ diff --git a/test/config/va-remote-b.json b/test/config/va-remote-b.json index f4107e99144..eab681227ab 100644 --- a/test/config/va-remote-b.json +++ b/test/config/va-remote-b.json @@ -1,6 +1,6 @@ { "va": { - "userAgent": "boulder-remote-b", + "userAgent": "boulder-remoteva-b", "debugAddr": ":8012", "dnsTries": 3, "dnsProvider": { diff --git a/test/config/va.json b/test/config/va.json index f2639a4826c..efb346be49f 100644 --- a/test/config/va.json +++ b/test/config/va.json @@ -52,6 +52,16 @@ "serverAddress": "rva1.service.consul:9498", "timeout": "15s", "hostOverride": "rva1.boulder" + }, + { + "serverAddress": "rva2.service.consul:9897", + "timeout": "15s", + "hostOverride": "rva2.boulder" + }, + { + "serverAddress": "rva2.service.consul:9998", + "timeout": "15s", + "hostOverride": "rva2.boulder" } ], "maxRemoteValidationFailures": 1, diff --git a/test/consul/config.hcl b/test/consul/config.hcl index 7f630d5a888..b8543f5773e 100644 --- a/test/consul/config.hcl +++ b/test/consul/config.hcl @@ -176,6 +176,23 @@ services { tags = ["tcp"] // Required for SRV RR support in gRPC DNS resolution. } +# TODO(#5294) Remove rva2-a/b in favor of rva1-a/b +services { + id = "rva2-a" + name = "rva2" + address = "10.77.77.77" + port = 9897 + tags = ["tcp"] // Required for SRV RR support in gRPC DNS resolution. +} + +services { + id = "rva2-b" + name = "rva2" + address = "10.77.77.77" + port = 9998 + tags = ["tcp"] // Required for SRV RR support in gRPC DNS resolution. +} + services { id = "sa-a" name = "sa" diff --git a/test/startservers.py b/test/startservers.py index 022e08949f4..fcfdc942308 100644 --- a/test/startservers.py +++ b/test/startservers.py @@ -18,11 +18,19 @@ SERVICES = ( Service('boulder-remoteva-a', 8011, 9397, 'rva.boulder', - ('./bin/boulder', 'boulder-remoteva', '--config', os.path.join(config_dir, 'va-remote-a.json'), '--addr', ':9397', '--debug-addr', ':8011'), + ('./bin/boulder', 'boulder-va', '--config', os.path.join(config_dir, 'va-remote-a.json'), '--addr', ':9397', '--debug-addr', ':8011'), None), Service('boulder-remoteva-b', 8012, 9498, 'rva.boulder', - ('./bin/boulder', 'boulder-remoteva', '--config', os.path.join(config_dir, 'va-remote-b.json'), '--addr', ':9498', '--debug-addr', ':8012'), + ('./bin/boulder', 'boulder-va', '--config', os.path.join(config_dir, 'va-remote-b.json'), '--addr', ':9498', '--debug-addr', ':8012'), + None), + Service('remoteva-a', + 8211, 9897, 'rva.boulder', + ('./bin/boulder', 'remoteva', '--config', os.path.join(config_dir, 'remoteva-a.json'), '--addr', ':9897', '--debug-addr', ':8211'), + None), + Service('remoteva-b', + 8212, 9998, 'rva.boulder', + ('./bin/boulder', 'remoteva', '--config', os.path.join(config_dir, 'remoteva-b.json'), '--addr', ':9998', '--debug-addr', ':8212'), None), Service('boulder-sa-1', 8003, 9395, 'sa.boulder', @@ -57,11 +65,11 @@ Service('boulder-va-1', 8004, 9392, 'va.boulder', ('./bin/boulder', 'boulder-va', '--config', os.path.join(config_dir, 'va.json'), '--addr', ':9392', '--debug-addr', ':8004'), - ('boulder-remoteva-a', 'boulder-remoteva-b')), + ('boulder-remoteva-a', 'boulder-remoteva-b', 'remoteva-a', 'remoteva-b')), Service('boulder-va-2', 8104, 9492, 'va.boulder', ('./bin/boulder', 'boulder-va', '--config', os.path.join(config_dir, 'va.json'), '--addr', ':9492', '--debug-addr', ':8104'), - ('boulder-remoteva-a', 'boulder-remoteva-b')), + ('boulder-remoteva-a', 'boulder-remoteva-b', 'remoteva-a', 'remoteva-b')), Service('boulder-ca-1', 8001, 9393, 'ca.boulder', ('./bin/boulder', 'boulder-ca', '--config', os.path.join(config_dir, 'ca.json'), '--addr', ':9393', '--debug-addr', ':8001'), diff --git a/test/v2_integration.py b/test/v2_integration.py index 34c49dd412c..095263c9176 100644 --- a/test/v2_integration.py +++ b/test/v2_integration.py @@ -1004,8 +1004,8 @@ def test_http_multiva_threshold_pass(): client = chisel2.make_client() # Configure a guestlist that will pass the multiVA threshold test by - # allowing the primary VA and one remote. - guestlist = {"boulder": 1, "boulder-remote-b": 1} + # allowing the primary VA at some, but not all, remotes. + guestlist = {"boulder": 1, "boulder-remoteva-a": 1, "boulder-remoteva-b": 1, "remoteva-a": 1} hostname, cleanup = multiva_setup(client, guestlist) @@ -1019,9 +1019,9 @@ def test_http_multiva_threshold_pass(): def test_http_multiva_primary_fail_remote_pass(): client = chisel2.make_client() - # Configure a guestlist that will fail the primary VA check but allow the - # remote VAs - guestlist = {"boulder": 0, "boulder-remote-a": 1, "boulder-remote-b": 1} + # Configure a guestlist that will fail the primary VA check but allow all of + # the remote VAs. + guestlist = {"boulder": 0, "boulder-remoteva-a": 1, "boulder-remoteva-b": 1, "remoteva-a": 1, "remoteva-b": 1} hostname, cleanup = multiva_setup(client, guestlist) diff --git a/va/config/config.go b/va/config/config.go new file mode 100644 index 00000000000..28a430619ab --- /dev/null +++ b/va/config/config.go @@ -0,0 +1,52 @@ +package vacfg + +import ( + "fmt" + + "github.com/letsencrypt/boulder/cmd" + "github.com/letsencrypt/boulder/config" +) + +// Common contains all of the shared fields for a VA and a Remote VA (RVA). +type Common 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 + + AccountURIPrefixes []string `validate:"min=1,dive,required,url"` +} + +// SetDefaultsAndValidate performs some basic sanity checks on fields stored in +// the Common struct, defaulting them to a sane value when necessary. This +// method does mutate the Common struct. +func (c *Common) SetDefaultsAndValidate(grpcAddr, debugAddr *string) error { + if *grpcAddr != "" { + c.GRPC.Address = *grpcAddr + } + if *debugAddr != "" { + c.DebugAddr = *debugAddr + } + + if c.DNSTimeout.Duration <= 0 { + return fmt.Errorf("'dnsTimeout' is required") + } + + if c.DNSTries < 1 { + c.DNSTries = 1 + } + + return nil +}