va: Make the primary VA aware of the Perspective and RIR of each remote (#7839)
- Make the primary VA aware of the expected Perspective and RIR of each remote VA. - All Perspectives should be unique, have the primary VA check for duplicate Perspectives at startup. - Update test setup functions to ensure that each remote VA client and corresponding inmem impl have a matching perspective and RIR. Part of #7819
This commit is contained in:
parent
7791262815
commit
c3948314ff
|
|
@ -15,10 +15,44 @@ import (
|
||||||
vapb "github.com/letsencrypt/boulder/va/proto"
|
vapb "github.com/letsencrypt/boulder/va/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RemoteVAGRPCClientConfig contains the information necessary to setup a gRPC
|
||||||
|
// client connection. The following GRPC client configuration field combinations
|
||||||
|
// are allowed:
|
||||||
|
//
|
||||||
|
// ServerIPAddresses, [Timeout]
|
||||||
|
// ServerAddress, DNSAuthority, [Timeout], [HostOverride]
|
||||||
|
// SRVLookup, DNSAuthority, [Timeout], [HostOverride], [SRVResolver]
|
||||||
|
// SRVLookups, DNSAuthority, [Timeout], [HostOverride], [SRVResolver]
|
||||||
|
type RemoteVAGRPCClientConfig struct {
|
||||||
|
cmd.GRPCClientConfig
|
||||||
|
// Perspective uniquely identifies the Network Perspective used to
|
||||||
|
// perform the validation, as specified in BRs Section 5.4.1,
|
||||||
|
// Requirement 2.7 ("Multi-Perspective Issuance Corroboration attempts
|
||||||
|
// from each Network Perspective"). It should uniquely identify a group
|
||||||
|
// of RVAs deployed in the same datacenter.
|
||||||
|
//
|
||||||
|
// TODO(#7615): Make mandatory.
|
||||||
|
Perspective string `validate:"omitempty"`
|
||||||
|
|
||||||
|
// RIR indicates the Regional Internet Registry where this RVA is
|
||||||
|
// located. This field is used to identify the RIR region from which a
|
||||||
|
// given validation was performed, as specified in the "Phased
|
||||||
|
// Implementation Timeline" in BRs Section 3.2.2.9. It must be one of
|
||||||
|
// the following values:
|
||||||
|
// - ARIN
|
||||||
|
// - RIPE
|
||||||
|
// - APNIC
|
||||||
|
// - LACNIC
|
||||||
|
// - AfriNIC
|
||||||
|
//
|
||||||
|
// TODO(#7615): Make mandatory.
|
||||||
|
RIR string `validate:"omitempty,oneof=ARIN RIPE APNIC LACNIC AfriNIC"`
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
VA struct {
|
VA struct {
|
||||||
vaConfig.Common
|
vaConfig.Common
|
||||||
RemoteVAs []cmd.GRPCClientConfig `validate:"omitempty,dive"`
|
RemoteVAs []RemoteVAGRPCClientConfig `validate:"omitempty,dive"`
|
||||||
// Deprecated and ignored
|
// Deprecated and ignored
|
||||||
MaxRemoteValidationFailures int `validate:"omitempty,min=0,required_with=RemoteVAs"`
|
MaxRemoteValidationFailures int `validate:"omitempty,min=0,required_with=RemoteVAs"`
|
||||||
Features features.Config
|
Features features.Config
|
||||||
|
|
@ -92,7 +126,7 @@ func main() {
|
||||||
if len(c.VA.RemoteVAs) > 0 {
|
if len(c.VA.RemoteVAs) > 0 {
|
||||||
for _, rva := range c.VA.RemoteVAs {
|
for _, rva := range c.VA.RemoteVAs {
|
||||||
rva := rva
|
rva := rva
|
||||||
vaConn, err := bgrpc.ClientSetup(&rva, tlsConfig, scope, clk)
|
vaConn, err := bgrpc.ClientSetup(&rva.GRPCClientConfig, tlsConfig, scope, clk)
|
||||||
cmd.FailOnError(err, "Unable to create remote VA client")
|
cmd.FailOnError(err, "Unable to create remote VA client")
|
||||||
remotes = append(
|
remotes = append(
|
||||||
remotes,
|
remotes,
|
||||||
|
|
@ -101,7 +135,9 @@ func main() {
|
||||||
VAClient: vapb.NewVAClient(vaConn),
|
VAClient: vapb.NewVAClient(vaConn),
|
||||||
CAAClient: vapb.NewCAAClient(vaConn),
|
CAAClient: vapb.NewCAAClient(vaConn),
|
||||||
},
|
},
|
||||||
Address: rva.ServerAddress,
|
Address: rva.ServerAddress,
|
||||||
|
Perspective: rva.Perspective,
|
||||||
|
RIR: rva.RIR,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"http://boulder.service.consul:4000/acme/reg/",
|
"http://boulder.service.consul:4000/acme/reg/",
|
||||||
"http://boulder.service.consul:4001/acme/acct/"
|
"http://boulder.service.consul:4001/acme/acct/"
|
||||||
],
|
],
|
||||||
"perspective": "development",
|
"perspective": "dadaist",
|
||||||
"rir": "ARIN"
|
"rir": "ARIN"
|
||||||
},
|
},
|
||||||
"syslog": {
|
"syslog": {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"http://boulder.service.consul:4000/acme/reg/",
|
"http://boulder.service.consul:4000/acme/reg/",
|
||||||
"http://boulder.service.consul:4001/acme/acct/"
|
"http://boulder.service.consul:4001/acme/acct/"
|
||||||
],
|
],
|
||||||
"perspective": "development",
|
"perspective": "surrealist",
|
||||||
"rir": "RIPE"
|
"rir": "RIPE"
|
||||||
},
|
},
|
||||||
"syslog": {
|
"syslog": {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
"http://boulder.service.consul:4000/acme/reg/",
|
"http://boulder.service.consul:4000/acme/reg/",
|
||||||
"http://boulder.service.consul:4001/acme/acct/"
|
"http://boulder.service.consul:4001/acme/acct/"
|
||||||
],
|
],
|
||||||
"perspective": "development",
|
"perspective": "cubist",
|
||||||
"rir": "ARIN"
|
"rir": "ARIN"
|
||||||
},
|
},
|
||||||
"syslog": {
|
"syslog": {
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,23 @@
|
||||||
{
|
{
|
||||||
"serverAddress": "rva1.service.consul:9397",
|
"serverAddress": "rva1.service.consul:9397",
|
||||||
"timeout": "15s",
|
"timeout": "15s",
|
||||||
"hostOverride": "rva1.boulder"
|
"hostOverride": "rva1.boulder",
|
||||||
|
"perspective": "dadaist",
|
||||||
|
"rir": "ARIN"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"serverAddress": "rva1.service.consul:9498",
|
"serverAddress": "rva1.service.consul:9498",
|
||||||
"timeout": "15s",
|
"timeout": "15s",
|
||||||
"hostOverride": "rva1.boulder"
|
"hostOverride": "rva1.boulder",
|
||||||
|
"perspective": "surrealist",
|
||||||
|
"rir": "RIPE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"serverAddress": "rva1.service.consul:9499",
|
"serverAddress": "rva1.service.consul:9499",
|
||||||
"timeout": "15s",
|
"timeout": "15s",
|
||||||
"hostOverride": "rva1.boulder"
|
"hostOverride": "rva1.boulder",
|
||||||
|
"perspective": "cubist",
|
||||||
|
"rir": "ARIN"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"accountURIPrefixes": [
|
"accountURIPrefixes": [
|
||||||
|
|
|
||||||
169
va/caa_test.go
169
va/caa_test.go
|
|
@ -590,9 +590,8 @@ func (b caaBrokenDNS) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, s
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDisabledMultiCAARechecking(t *testing.T) {
|
func TestDisabledMultiCAARechecking(t *testing.T) {
|
||||||
brokenRVA := setupRemote(nil, "broken", caaBrokenDNS{}, "", "")
|
remoteVAs := []remoteConf{{ua: "broken", rir: arin, dns: caaBrokenDNS{}}}
|
||||||
remoteVAs := []RemoteVA{{brokenRVA, "broken"}}
|
va, _ := setupWithRemotes(nil, "local", remoteVAs, nil)
|
||||||
va, _ := setup(nil, "local", remoteVAs, nil)
|
|
||||||
|
|
||||||
features.Set(features.Config{
|
features.Set(features.Config{
|
||||||
EnforceMultiCAA: false,
|
EnforceMultiCAA: false,
|
||||||
|
|
@ -664,15 +663,11 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
brokenUA = "broken"
|
brokenUA = "broken"
|
||||||
hijackedUA = "hijacked"
|
hijackedUA = "hijacked"
|
||||||
)
|
)
|
||||||
remoteVA := setupRemote(nil, remoteUA, nil, "", "")
|
|
||||||
brokenVA := setupRemote(nil, brokenUA, caaBrokenDNS{}, "", "")
|
|
||||||
// Returns incorrect results
|
|
||||||
hijackedVA := setupRemote(nil, hijackedUA, caaHijackedDNS{}, "", "")
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
domains string
|
domains string
|
||||||
remoteVAs []RemoteVA
|
remoteVAs []remoteConf
|
||||||
expectedProbSubstring string
|
expectedProbSubstring string
|
||||||
expectedProbType probs.ProblemType
|
expectedProbType probs.ProblemType
|
||||||
expectedDiffLogSubstring string
|
expectedDiffLogSubstring string
|
||||||
|
|
@ -683,10 +678,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
name: "all VAs functional, no CAA records",
|
name: "all VAs functional, no CAA records",
|
||||||
domains: "present-dns-only.com",
|
domains: "present-dns-only.com",
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: arin},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -702,10 +697,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
localDNSClient: caaBrokenDNS{},
|
localDNSClient: caaBrokenDNS{},
|
||||||
expectedProbSubstring: "While processing CAA for present-dns-only.com: dnsClient is broken",
|
expectedProbSubstring: "While processing CAA for present-dns-only.com: dnsClient is broken",
|
||||||
expectedProbType: probs.DNSProblem,
|
expectedProbType: probs.DNSProblem,
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: arin},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -720,10 +715,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
domains: "present-dns-only.com",
|
domains: "present-dns-only.com",
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -740,10 +735,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.DNSProblem,
|
expectedProbType: probs.DNSProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: ripe, dns: caaBrokenDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -760,10 +755,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.DNSProblem,
|
expectedProbType: probs.DNSProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: ripe, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: apnic, dns: caaBrokenDNS{}},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -777,10 +772,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
name: "all VAs functional, CAA issue type present",
|
name: "all VAs functional, CAA issue type present",
|
||||||
domains: "present.com",
|
domains: "present.com",
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: arin},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -795,10 +790,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
domains: "present.com",
|
domains: "present.com",
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -815,10 +810,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.DNSProblem,
|
expectedProbType: probs.DNSProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: ripe, dns: caaBrokenDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -835,10 +830,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.DNSProblem,
|
expectedProbType: probs.DNSProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"broken","Problem":{"type":"dns","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: arin, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: ripe, dns: caaBrokenDNS{}},
|
||||||
{brokenVA, brokenUA},
|
{ua: brokenUA, rir: apnic, dns: caaBrokenDNS{}},
|
||||||
},
|
},
|
||||||
expectedLabels: prometheus.Labels{
|
expectedLabels: prometheus.Labels{
|
||||||
"operation": opCAA,
|
"operation": opCAA,
|
||||||
|
|
@ -857,10 +852,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbSubstring: "CAA record for unsatisfiable.com prevents issuance",
|
expectedProbSubstring: "CAA record for unsatisfiable.com prevents issuance",
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: arin},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -868,10 +863,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
domains: "present.com",
|
domains: "present.com",
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -881,10 +876,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -894,10 +889,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: apnic, dns: caaHijackedDNS{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -905,10 +900,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
domains: "satisfiable-wildcard.com",
|
domains: "satisfiable-wildcard.com",
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -918,10 +913,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -931,10 +926,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: apnic, dns: caaHijackedDNS{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -942,10 +937,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
domains: "satisfiable-wildcard.com",
|
domains: "satisfiable-wildcard.com",
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":2,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: ripe},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -955,10 +950,10 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":1,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{remoteVA, remoteUA},
|
{ua: remoteUA, rir: apnic},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -968,17 +963,17 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
expectedProbType: probs.CAAProblem,
|
expectedProbType: probs.CAAProblem,
|
||||||
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
expectedDiffLogSubstring: `RemoteSuccesses":0,"RemoteFailures":[{"VAHostname":"hijacked","Problem":{"type":"caa","detail":"While processing CAA for`,
|
||||||
localDNSClient: caaMockDNS{},
|
localDNSClient: caaMockDNS{},
|
||||||
remoteVAs: []RemoteVA{
|
remoteVAs: []remoteConf{
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: arin, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: ripe, dns: caaHijackedDNS{}},
|
||||||
{hijackedVA, hijackedUA},
|
{ua: hijackedUA, rir: apnic, dns: caaHijackedDNS{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
va, mockLog := setup(nil, localUA, tc.remoteVAs, tc.localDNSClient)
|
va, mockLog := setupWithRemotes(nil, localUA, tc.remoteVAs, tc.localDNSClient)
|
||||||
defer mockLog.Clear()
|
defer mockLog.Clear()
|
||||||
|
|
||||||
// MultiCAAFullResults: false is inherently flaky because of the
|
// MultiCAAFullResults: false is inherently flaky because of the
|
||||||
|
|
@ -1011,8 +1006,8 @@ func TestMultiCAARechecking(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidRVACount int
|
var invalidRVACount int
|
||||||
for _, x := range va.remoteVAs {
|
for _, x := range tc.remoteVAs {
|
||||||
if x.Address == "broken" || x.Address == "hijacked" {
|
if x.ua == brokenUA || x.ua == hijackedUA {
|
||||||
invalidRVACount++
|
invalidRVACount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
29
va/va.go
29
va/va.go
|
|
@ -87,7 +87,9 @@ type RemoteClients struct {
|
||||||
// extract this metadata which is useful for debugging gRPC connection issues.
|
// extract this metadata which is useful for debugging gRPC connection issues.
|
||||||
type RemoteVA struct {
|
type RemoteVA struct {
|
||||||
RemoteClients
|
RemoteClients
|
||||||
Address string
|
Address string
|
||||||
|
Perspective string
|
||||||
|
RIR string
|
||||||
}
|
}
|
||||||
|
|
||||||
type vaMetrics struct {
|
type vaMetrics struct {
|
||||||
|
|
@ -235,6 +237,15 @@ func NewValidationAuthorityImpl(
|
||||||
return nil, errors.New("no account URI prefixes configured")
|
return nil, errors.New("no account URI prefixes configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, va1 := range remoteVAs {
|
||||||
|
for j, va2 := range remoteVAs {
|
||||||
|
// TODO(#7819): Remove the != "" check once perspective is required.
|
||||||
|
if i != j && va1.Perspective == va2.Perspective && va1.Perspective != "" {
|
||||||
|
return nil, fmt.Errorf("duplicate remote VA perspective %q", va1.Perspective)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pc := newDefaultPortConfig()
|
pc := newDefaultPortConfig()
|
||||||
|
|
||||||
va := &ValidationAuthorityImpl{
|
va := &ValidationAuthorityImpl{
|
||||||
|
|
@ -456,9 +467,11 @@ func (va *ValidationAuthorityImpl) performRemoteValidation(
|
||||||
}
|
}
|
||||||
|
|
||||||
type response struct {
|
type response struct {
|
||||||
addr string
|
addr string
|
||||||
result *vapb.ValidationResult
|
perspective string
|
||||||
err error
|
rir string
|
||||||
|
result *vapb.ValidationResult
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
subCtx, cancel := context.WithCancel(ctx)
|
subCtx, cancel := context.WithCancel(ctx)
|
||||||
|
|
@ -468,7 +481,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation(
|
||||||
for _, i := range rand.Perm(remoteVACount) {
|
for _, i := range rand.Perm(remoteVACount) {
|
||||||
go func(rva RemoteVA) {
|
go func(rva RemoteVA) {
|
||||||
res, err := rva.PerformValidation(subCtx, req)
|
res, err := rva.PerformValidation(subCtx, req)
|
||||||
responses <- &response{rva.Address, res, err}
|
responses <- &response{rva.Address, rva.Perspective, rva.RIR, res, err}
|
||||||
}(va.remoteVAs[i])
|
}(va.remoteVAs[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,7 +495,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation(
|
||||||
|
|
||||||
if resp.err != nil {
|
if resp.err != nil {
|
||||||
// Failed to communicate with the remote VA.
|
// Failed to communicate with the remote VA.
|
||||||
failed = append(failed, resp.addr)
|
failed = append(failed, resp.perspective)
|
||||||
|
|
||||||
if core.IsCanceled(resp.err) {
|
if core.IsCanceled(resp.err) {
|
||||||
currProb = probs.ServerInternal("Secondary domain validation RPC canceled")
|
currProb = probs.ServerInternal("Secondary domain validation RPC canceled")
|
||||||
|
|
@ -492,7 +505,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation(
|
||||||
}
|
}
|
||||||
} else if resp.result.Problems != nil {
|
} else if resp.result.Problems != nil {
|
||||||
// The remote VA returned a problem.
|
// The remote VA returned a problem.
|
||||||
failed = append(failed, resp.result.Perspective)
|
failed = append(failed, resp.perspective)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
currProb, err = bgrpc.PBToProblemDetails(resp.result.Problems)
|
currProb, err = bgrpc.PBToProblemDetails(resp.result.Problems)
|
||||||
|
|
@ -502,7 +515,7 @@ func (va *ValidationAuthorityImpl) performRemoteValidation(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The remote VA returned a successful result.
|
// The remote VA returned a successful result.
|
||||||
passed = append(passed, resp.result.Perspective)
|
passed = append(passed, resp.perspective)
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstProb == nil && currProb != nil {
|
if firstProb == nil && currProb != nil {
|
||||||
|
|
|
||||||
480
va/va_test.go
480
va/va_test.go
|
|
@ -162,6 +162,67 @@ func setupRemote(srv *httptest.Server, userAgent string, mockDNSClientOverride b
|
||||||
return RemoteClients{VAClient: &inMemVA{*rva}, CAAClient: &inMemVA{*rva}}
|
return RemoteClients{VAClient: &inMemVA{*rva}, CAAClient: &inMemVA{*rva}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RIRs
|
||||||
|
const (
|
||||||
|
arin = "ARIN"
|
||||||
|
ripe = "RIPE"
|
||||||
|
apnic = "APNIC"
|
||||||
|
lacnic = "LACNIC"
|
||||||
|
afrinic = "AFRINIC"
|
||||||
|
)
|
||||||
|
|
||||||
|
// remoteConf is used in conjunction with setupRemotes/withRemotes to configure
|
||||||
|
// a remote VA.
|
||||||
|
type remoteConf struct {
|
||||||
|
// ua is optional, will default to "user agent 1.0". When set to "broken" or
|
||||||
|
// "hijacked", the Address field of the resulting RemoteVA will be set to
|
||||||
|
// match. This is a bit hacky, but it's the easiest way to satisfy some of
|
||||||
|
// our existing TestMultiCAARechecking tests.
|
||||||
|
ua string
|
||||||
|
// rir is required.
|
||||||
|
rir string
|
||||||
|
// dns is optional.
|
||||||
|
dns bdns.Client
|
||||||
|
// impl is optional.
|
||||||
|
impl RemoteClients
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRemotes(confs []remoteConf, srv *httptest.Server) []RemoteVA {
|
||||||
|
remoteVAs := make([]RemoteVA, 0, len(confs))
|
||||||
|
for i, c := range confs {
|
||||||
|
if c.rir == "" {
|
||||||
|
panic("rir is required")
|
||||||
|
}
|
||||||
|
// perspective MUST be unique for each remote VA, otherwise the VA will
|
||||||
|
// fail to start.
|
||||||
|
perspective := fmt.Sprintf("dc-%d-%s", i, c.rir)
|
||||||
|
clients := setupRemote(srv, c.ua, c.dns, perspective, c.rir)
|
||||||
|
if c.impl != (RemoteClients{}) {
|
||||||
|
clients = c.impl
|
||||||
|
}
|
||||||
|
var address string
|
||||||
|
if c.ua == "broken" {
|
||||||
|
address = "broken"
|
||||||
|
}
|
||||||
|
if c.ua == "hijacked" {
|
||||||
|
address = "hijacked"
|
||||||
|
}
|
||||||
|
remoteVAs = append(remoteVAs, RemoteVA{
|
||||||
|
Address: address,
|
||||||
|
RemoteClients: clients,
|
||||||
|
Perspective: perspective,
|
||||||
|
RIR: c.rir,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return remoteVAs
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupWithRemotes(srv *httptest.Server, userAgent string, remotes []remoteConf, mockDNSClientOverride bdns.Client) (*ValidationAuthorityImpl, *blog.Mock) {
|
||||||
|
remoteVAs := setupRemotes(remotes, srv)
|
||||||
|
return setup(srv, userAgent, remoteVAs, mockDNSClientOverride)
|
||||||
|
}
|
||||||
|
|
||||||
type multiSrv struct {
|
type multiSrv struct {
|
||||||
*httptest.Server
|
*httptest.Server
|
||||||
|
|
||||||
|
|
@ -169,13 +230,10 @@ type multiSrv struct {
|
||||||
allowedUAs map[string]bool
|
allowedUAs map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *multiSrv) setAllowedUAs(allowedUAs map[string]bool) {
|
const (
|
||||||
s.mu.Lock()
|
slowUA = "slow remote"
|
||||||
defer s.mu.Unlock()
|
slowRemoteSleepMillis = 1000
|
||||||
s.allowedUAs = allowedUAs
|
)
|
||||||
}
|
|
||||||
|
|
||||||
const slowRemoteSleepMillis = 1000
|
|
||||||
|
|
||||||
func httpMultiSrv(t *testing.T, token string, allowedUAs map[string]bool) *multiSrv {
|
func httpMultiSrv(t *testing.T, token string, allowedUAs map[string]bool) *multiSrv {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
@ -185,7 +243,7 @@ func httpMultiSrv(t *testing.T, token string, allowedUAs map[string]bool) *multi
|
||||||
ms := &multiSrv{server, sync.Mutex{}, allowedUAs}
|
ms := &multiSrv{server, sync.Mutex{}, allowedUAs}
|
||||||
|
|
||||||
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.UserAgent() == "slow remote" {
|
if r.UserAgent() == slowUA {
|
||||||
time.Sleep(slowRemoteSleepMillis)
|
time.Sleep(slowRemoteSleepMillis)
|
||||||
}
|
}
|
||||||
ms.mu.Lock()
|
ms.mu.Lock()
|
||||||
|
|
@ -248,6 +306,32 @@ func (inmem inMemVA) IsCAAValid(ctx context.Context, req *vapb.IsCAAValidRequest
|
||||||
return inmem.rva.IsCAAValid(ctx, req)
|
return inmem.rva.IsCAAValid(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewValidationAuthorityImplWithDuplicateRemotes(t *testing.T) {
|
||||||
|
var remoteVAs []RemoteVA
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
remoteVAs = append(remoteVAs, RemoteVA{
|
||||||
|
RemoteClients: setupRemote(nil, "", nil, "dadaist", arin),
|
||||||
|
Perspective: "dadaist",
|
||||||
|
RIR: arin,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := NewValidationAuthorityImpl(
|
||||||
|
&bdns.MockClient{Log: blog.NewMock()},
|
||||||
|
remoteVAs,
|
||||||
|
"user agent 1.0",
|
||||||
|
"letsencrypt.org",
|
||||||
|
metrics.NoopRegisterer,
|
||||||
|
clock.NewFake(),
|
||||||
|
blog.NewMock(),
|
||||||
|
accountURIPrefixes,
|
||||||
|
"example perspective",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
test.AssertError(t, err, "NewValidationAuthorityImpl allowed duplicate remote perspectives")
|
||||||
|
test.AssertContains(t, err.Error(), "duplicate remote VA perspective \"dadaist\"")
|
||||||
|
}
|
||||||
|
|
||||||
func TestValidateMalformedChallenge(t *testing.T) {
|
func TestValidateMalformedChallenge(t *testing.T) {
|
||||||
va, _ := setup(nil, "", nil, nil)
|
va, _ := setup(nil, "", nil, nil)
|
||||||
|
|
||||||
|
|
@ -366,37 +450,11 @@ func TestDCVAndCAASequencing(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiVA(t *testing.T) {
|
func TestMultiVA(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
// Create a new challenge to use for the httpSrv
|
// Create a new challenge to use for the httpSrv
|
||||||
req := createValidationRequest("localhost", core.ChallengeTypeHTTP01)
|
req := createValidationRequest("localhost", core.ChallengeTypeHTTP01)
|
||||||
|
|
||||||
const (
|
|
||||||
remoteUA1 = "remote 1"
|
|
||||||
remoteUA2 = "remote 2"
|
|
||||||
remoteUA3 = "remote 3"
|
|
||||||
remoteUA4 = "remote 4"
|
|
||||||
localUA = "local 1"
|
|
||||||
)
|
|
||||||
allowedUAs := map[string]bool{
|
|
||||||
localUA: true,
|
|
||||||
remoteUA1: true,
|
|
||||||
remoteUA2: true,
|
|
||||||
remoteUA3: true,
|
|
||||||
remoteUA4: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an IPv4 test server
|
|
||||||
ms := httpMultiSrv(t, expectedToken, allowedUAs)
|
|
||||||
defer ms.Close()
|
|
||||||
|
|
||||||
remoteVA1 := setupRemote(ms.Server, remoteUA1, nil, "", "")
|
|
||||||
remoteVA2 := setupRemote(ms.Server, remoteUA2, nil, "", "")
|
|
||||||
remoteVA3 := setupRemote(ms.Server, remoteUA3, nil, "", "")
|
|
||||||
remoteVA4 := setupRemote(ms.Server, remoteUA4, nil, "", "")
|
|
||||||
remoteVAs := []RemoteVA{
|
|
||||||
{remoteVA1, remoteUA1},
|
|
||||||
{remoteVA2, remoteUA2},
|
|
||||||
{remoteVA3, remoteUA3},
|
|
||||||
}
|
|
||||||
brokenVA := RemoteClients{
|
brokenVA := RemoteClients{
|
||||||
VAClient: brokenRemoteVA{},
|
VAClient: brokenRemoteVA{},
|
||||||
CAAClient: brokenRemoteVA{},
|
CAAClient: brokenRemoteVA{},
|
||||||
|
|
@ -406,176 +464,187 @@ func TestMultiVA(t *testing.T) {
|
||||||
CAAClient: cancelledVA{},
|
CAAClient: cancelledVA{},
|
||||||
}
|
}
|
||||||
|
|
||||||
unauthorized := probs.Unauthorized(fmt.Sprintf(
|
|
||||||
`The key authorization file from the server did not match this challenge. Expected %q (got "???")`,
|
|
||||||
expectedKeyAuthorization))
|
|
||||||
expectedInternalErrLine := fmt.Sprintf(
|
|
||||||
`ERR: \[AUDIT\] Remote VA "broken".PerformValidation failed: %s`,
|
|
||||||
errBrokenRemoteVA.Error())
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
RemoteVAs []RemoteVA
|
Remotes []remoteConf
|
||||||
AllowedUAs map[string]bool
|
PrimaryUA string
|
||||||
ExpectedProb *probs.ProblemDetails
|
ExpectedProbType string
|
||||||
ExpectedLog string
|
ExpectedLogContains string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// With local and all remote VAs working there should be no problem.
|
// With local and all remote VAs working there should be no problem.
|
||||||
Name: "Local and remote VAs OK",
|
Name: "Local and remote VAs OK",
|
||||||
RemoteVAs: remoteVAs,
|
Remotes: []remoteConf{
|
||||||
AllowedUAs: allowedUAs,
|
{ua: pass, rir: arin},
|
||||||
|
{ua: pass, rir: ripe},
|
||||||
|
{ua: pass, rir: apnic},
|
||||||
|
},
|
||||||
|
PrimaryUA: pass,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If the local VA fails everything should fail
|
// If the local VA fails everything should fail
|
||||||
Name: "Local VA bad, remote VAs OK",
|
Name: "Local VA bad, remote VAs OK",
|
||||||
RemoteVAs: remoteVAs,
|
Remotes: []remoteConf{
|
||||||
AllowedUAs: map[string]bool{remoteUA1: true, remoteUA2: true},
|
{ua: pass, rir: arin},
|
||||||
ExpectedProb: unauthorized,
|
{ua: pass, rir: ripe},
|
||||||
|
{ua: pass, rir: apnic},
|
||||||
|
},
|
||||||
|
PrimaryUA: fail,
|
||||||
|
ExpectedProbType: string(probs.UnauthorizedProblem),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If one out of three remote VAs fails with an internal err it should succeed
|
// If one out of three remote VAs fails with an internal err it should succeed
|
||||||
Name: "Local VA ok, 1/3 remote VA internal err",
|
Name: "Local VA ok, 1/3 remote VA internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{remoteVA2, remoteUA2},
|
{ua: pass, rir: ripe},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: apnic, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If two out of three remote VAs fail with an internal err it should fail
|
// If two out of three remote VAs fail with an internal err it should fail
|
||||||
Name: "Local VA ok, 2/3 remote VAs internal err",
|
Name: "Local VA ok, 2/3 remote VAs internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: ripe, impl: brokenVA},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: apnic, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
ExpectedProb: probs.ServerInternal("During secondary domain validation: Secondary domain validation RPC failed"),
|
ExpectedProbType: string(probs.ServerInternalProblem),
|
||||||
// The real failure cause should be logged
|
// The real failure cause should be logged
|
||||||
ExpectedLog: expectedInternalErrLine,
|
ExpectedLogContains: errBrokenRemoteVA.Error(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If one out of five remote VAs fail with an internal err it should succeed
|
// If one out of five remote VAs fail with an internal err it should succeed
|
||||||
Name: "Local VA ok, 1/5 remote VAs internal err",
|
Name: "Local VA ok, 1/5 remote VAs internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{remoteVA2, remoteUA2},
|
{ua: pass, rir: ripe},
|
||||||
{remoteVA3, remoteUA3},
|
{ua: pass, rir: apnic},
|
||||||
{remoteVA4, remoteUA4},
|
{ua: pass, rir: lacnic},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: afrinic, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If two out of five remote VAs fail with an internal err it should fail
|
// If two out of five remote VAs fail with an internal err it should fail
|
||||||
Name: "Local VA ok, 2/5 remote VAs internal err",
|
Name: "Local VA ok, 2/5 remote VAs internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{remoteVA2, remoteUA2},
|
{ua: pass, rir: ripe},
|
||||||
{remoteVA3, remoteUA3},
|
{ua: pass, rir: apnic},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: arin, impl: brokenVA},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: ripe, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
ExpectedProb: probs.ServerInternal("During secondary domain validation: Secondary domain validation RPC failed"),
|
ExpectedProbType: string(probs.ServerInternalProblem),
|
||||||
// The real failure cause should be logged
|
// The real failure cause should be logged
|
||||||
ExpectedLog: expectedInternalErrLine,
|
ExpectedLogContains: errBrokenRemoteVA.Error(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If two out of six remote VAs fail with an internal err it should succeed
|
// If two out of six remote VAs fail with an internal err it should succeed
|
||||||
Name: "Local VA ok, 2/6 remote VAs internal err",
|
Name: "Local VA ok, 2/6 remote VAs internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{remoteVA2, remoteUA2},
|
{ua: pass, rir: ripe},
|
||||||
{remoteVA3, remoteUA3},
|
{ua: pass, rir: apnic},
|
||||||
{remoteVA4, remoteUA4},
|
{ua: pass, rir: lacnic},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: afrinic, impl: brokenVA},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: arin, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If three out of six remote VAs fail with an internal err it should fail
|
// If three out of six remote VAs fail with an internal err it should fail
|
||||||
Name: "Local VA ok, 4/6 remote VAs internal err",
|
Name: "Local VA ok, 4/6 remote VAs internal err",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{remoteVA2, remoteUA2},
|
{ua: pass, rir: ripe},
|
||||||
{remoteVA3, remoteUA3},
|
{ua: pass, rir: apnic},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: lacnic, impl: brokenVA},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: afrinic, impl: brokenVA},
|
||||||
{brokenVA, "broken"},
|
{ua: pass, rir: arin, impl: brokenVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
ExpectedProb: probs.ServerInternal("During secondary domain validation: Secondary domain validation RPC failed"),
|
ExpectedProbType: string(probs.ServerInternalProblem),
|
||||||
// The real failure cause should be logged
|
// The real failure cause should be logged
|
||||||
ExpectedLog: expectedInternalErrLine,
|
ExpectedLogContains: errBrokenRemoteVA.Error(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// With only one working remote VA there should be a validation failure
|
// With only one working remote VA there should be a validation failure
|
||||||
Name: "Local VA and one remote VA OK",
|
Name: "Local VA and one remote VA OK",
|
||||||
RemoteVAs: remoteVAs,
|
Remotes: []remoteConf{
|
||||||
AllowedUAs: map[string]bool{localUA: true, remoteUA2: true},
|
{ua: pass, rir: arin},
|
||||||
ExpectedProb: probs.Unauthorized(fmt.Sprintf(
|
{ua: fail, rir: ripe},
|
||||||
`During secondary domain validation: The key authorization file from the server did not match this challenge. Expected %q (got "???")`,
|
{ua: fail, rir: apnic},
|
||||||
expectedKeyAuthorization)),
|
},
|
||||||
|
PrimaryUA: pass,
|
||||||
|
ExpectedProbType: string(probs.UnauthorizedProblem),
|
||||||
|
ExpectedLogContains: "During secondary domain validation: The key authorization file from the server",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If one remote VA cancels, it should succeed
|
// If one remote VA cancels, it should succeed
|
||||||
Name: "Local VA and one remote VA OK, one cancelled VA",
|
Name: "Local VA and one remote VA OK, one cancelled VA",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{remoteVA1, remoteUA1},
|
{ua: pass, rir: arin},
|
||||||
{cancelledVA, remoteUA2},
|
{ua: pass, rir: ripe, impl: cancelledVA},
|
||||||
{remoteVA3, remoteUA3},
|
{ua: pass, rir: apnic},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If all remote VAs cancel, it should fail
|
// If all remote VAs cancel, it should fail
|
||||||
Name: "Local VA OK, three cancelled remote VAs",
|
Name: "Local VA OK, three cancelled remote VAs",
|
||||||
RemoteVAs: []RemoteVA{
|
Remotes: []remoteConf{
|
||||||
{cancelledVA, remoteUA1},
|
{ua: pass, rir: arin, impl: cancelledVA},
|
||||||
{cancelledVA, remoteUA2},
|
{ua: pass, rir: ripe, impl: cancelledVA},
|
||||||
{cancelledVA, remoteUA3},
|
{ua: pass, rir: apnic, impl: cancelledVA},
|
||||||
},
|
},
|
||||||
AllowedUAs: allowedUAs,
|
PrimaryUA: pass,
|
||||||
ExpectedProb: probs.ServerInternal("During secondary domain validation: Secondary domain validation RPC canceled"),
|
ExpectedProbType: string(probs.ServerInternalProblem),
|
||||||
|
ExpectedLogContains: "During secondary domain validation: Secondary domain validation RPC canceled",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// With the local and remote VAs seeing diff problems, we expect a problem.
|
// With the local and remote VAs seeing diff problems, we expect a problem.
|
||||||
Name: "Local and remote VA differential, full results, enforce multi VA",
|
Name: "Local and remote VA differential, full results, enforce multi VA",
|
||||||
RemoteVAs: remoteVAs,
|
Remotes: []remoteConf{
|
||||||
AllowedUAs: map[string]bool{localUA: true},
|
{ua: fail, rir: arin},
|
||||||
ExpectedProb: probs.Unauthorized(fmt.Sprintf(
|
{ua: fail, rir: ripe},
|
||||||
`During secondary domain validation: The key authorization file from the server did not match this challenge. Expected %q (got "???")`,
|
{ua: fail, rir: apnic},
|
||||||
expectedKeyAuthorization)),
|
},
|
||||||
|
PrimaryUA: pass,
|
||||||
|
ExpectedProbType: string(probs.UnauthorizedProblem),
|
||||||
|
ExpectedLogContains: "During secondary domain validation: The key authorization file from the server",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
// Configure the test server with the testcase allowed UAs.
|
t.Parallel()
|
||||||
ms.setAllowedUAs(tc.AllowedUAs)
|
|
||||||
|
// Configure one test server per test case so that all tests can run in parallel.
|
||||||
|
ms := httpMultiSrv(t, expectedToken, map[string]bool{pass: true, fail: false})
|
||||||
|
defer ms.Close()
|
||||||
|
|
||||||
// Configure a primary VA with testcase remote VAs.
|
// Configure a primary VA with testcase remote VAs.
|
||||||
localVA, mockLog := setup(ms.Server, localUA, tc.RemoteVAs, nil)
|
localVA, mockLog := setupWithRemotes(ms.Server, tc.PrimaryUA, tc.Remotes, nil)
|
||||||
|
|
||||||
// Perform all validations
|
// Perform all validations
|
||||||
res, _ := localVA.PerformValidation(ctx, req)
|
res, _ := localVA.PerformValidation(ctx, req)
|
||||||
if res.Problems == nil && tc.ExpectedProb != nil {
|
if res.Problems == nil && tc.ExpectedProbType != "" {
|
||||||
t.Errorf("expected prob %v, got nil", tc.ExpectedProb)
|
t.Errorf("expected prob %v, got nil", tc.ExpectedProbType)
|
||||||
} else if res.Problems != nil && tc.ExpectedProb == nil {
|
} else if res.Problems != nil && tc.ExpectedProbType == "" {
|
||||||
t.Errorf("expected no prob, got %v", res.Problems)
|
t.Errorf("expected no prob, got %v", res.Problems)
|
||||||
} else if res.Problems != nil && tc.ExpectedProb != nil {
|
} else if res.Problems != nil && tc.ExpectedProbType != "" {
|
||||||
// That result should match expected.
|
// That result should match expected.
|
||||||
test.AssertEquals(t, res.Problems.ProblemType, string(tc.ExpectedProb.Type))
|
test.AssertEquals(t, res.Problems.ProblemType, tc.ExpectedProbType)
|
||||||
test.AssertEquals(t, res.Problems.Detail, tc.ExpectedProb.Detail)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.ExpectedLog != "" {
|
if tc.ExpectedLogContains != "" {
|
||||||
lines := mockLog.GetAllMatching(tc.ExpectedLog)
|
lines := mockLog.GetAllMatching(tc.ExpectedLogContains)
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
t.Fatalf("Got log %v; expected %q", mockLog.GetAll(), tc.ExpectedLog)
|
t.Fatalf("Got log %v; expected %q", mockLog.GetAll(), tc.ExpectedLogContains)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -583,39 +652,48 @@ func TestMultiVA(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiVAEarlyReturn(t *testing.T) {
|
func TestMultiVAEarlyReturn(t *testing.T) {
|
||||||
const passUA = "pass"
|
t.Parallel()
|
||||||
const failUA = "fail"
|
|
||||||
// httpMultiSrv handles this specially by being slow
|
|
||||||
const slowRemoteUA = "slow remote"
|
|
||||||
allowedUAs := map[string]bool{
|
|
||||||
passUA: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
ms := httpMultiSrv(t, expectedToken, allowedUAs)
|
|
||||||
defer ms.Close()
|
|
||||||
|
|
||||||
makeRemotes := func(userAgent ...string) []RemoteVA {
|
|
||||||
var rvas []RemoteVA
|
|
||||||
for i, ua := range userAgent {
|
|
||||||
clients := setupRemote(ms.Server, ua, nil, "", "")
|
|
||||||
rva := RemoteVA{clients, fmt.Sprintf("remote VA %d hostname", i)}
|
|
||||||
rvas = append(rvas, rva)
|
|
||||||
}
|
|
||||||
return rvas
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
remoteUserAgents []string
|
remoteConfs []remoteConf
|
||||||
}{
|
}{
|
||||||
{remoteUserAgents: []string{slowRemoteUA, passUA, failUA}},
|
{
|
||||||
{remoteUserAgents: []string{slowRemoteUA, slowRemoteUA, passUA, passUA, failUA}},
|
remoteConfs: []remoteConf{
|
||||||
{remoteUserAgents: []string{slowRemoteUA, slowRemoteUA, passUA, passUA, failUA, failUA}},
|
{ua: slowUA, rir: arin},
|
||||||
|
{ua: pass, rir: ripe},
|
||||||
|
{ua: fail, rir: apnic},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
remoteConfs: []remoteConf{
|
||||||
|
{ua: slowUA, rir: arin},
|
||||||
|
{ua: slowUA, rir: ripe},
|
||||||
|
{ua: pass, rir: apnic},
|
||||||
|
{ua: pass, rir: arin},
|
||||||
|
{ua: fail, rir: ripe},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
remoteConfs: []remoteConf{
|
||||||
|
{ua: slowUA, rir: arin},
|
||||||
|
{ua: slowUA, rir: ripe},
|
||||||
|
{ua: pass, rir: apnic},
|
||||||
|
{ua: pass, rir: arin},
|
||||||
|
{ua: fail, rir: ripe},
|
||||||
|
{ua: fail, rir: apnic},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||||
rvas := makeRemotes(tc.remoteUserAgents...)
|
t.Parallel()
|
||||||
localVA, _ := setup(ms.Server, pass, rvas, nil)
|
|
||||||
|
// Configure one test server per test case so that all tests can run in parallel.
|
||||||
|
ms := httpMultiSrv(t, expectedToken, map[string]bool{pass: true, fail: false})
|
||||||
|
defer ms.Close()
|
||||||
|
|
||||||
|
localVA, _ := setupWithRemotes(ms.Server, pass, tc.remoteConfs, nil)
|
||||||
|
|
||||||
// Perform all validations
|
// Perform all validations
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
@ -643,35 +721,19 @@ func TestMultiVAEarlyReturn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiVAPolicy(t *testing.T) {
|
func TestMultiVAPolicy(t *testing.T) {
|
||||||
const (
|
t.Parallel()
|
||||||
remoteUA1 = "remote 1"
|
|
||||||
remoteUA2 = "remote 2"
|
|
||||||
remoteUA3 = "remote 3"
|
|
||||||
localUA = "local 1"
|
|
||||||
)
|
|
||||||
// Forbid all remote UAs to ensure that multi-va fails
|
|
||||||
allowedUAs := map[string]bool{
|
|
||||||
localUA: true,
|
|
||||||
remoteUA1: false,
|
|
||||||
remoteUA2: false,
|
|
||||||
remoteUA3: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
ms := httpMultiSrv(t, expectedToken, allowedUAs)
|
ms := httpMultiSrv(t, expectedToken, map[string]bool{pass: true, fail: false})
|
||||||
defer ms.Close()
|
defer ms.Close()
|
||||||
|
|
||||||
remoteVA1 := setupRemote(ms.Server, remoteUA1, nil, "", "")
|
remoteConfs := []remoteConf{
|
||||||
remoteVA2 := setupRemote(ms.Server, remoteUA2, nil, "", "")
|
{ua: fail, rir: arin},
|
||||||
remoteVA3 := setupRemote(ms.Server, remoteUA3, nil, "", "")
|
{ua: fail, rir: ripe},
|
||||||
|
{ua: fail, rir: apnic},
|
||||||
remoteVAs := []RemoteVA{
|
|
||||||
{remoteVA1, remoteUA1},
|
|
||||||
{remoteVA2, remoteUA2},
|
|
||||||
{remoteVA3, remoteUA3},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a local test VA with the two remote VAs
|
// Create a local test VA with the remote VAs
|
||||||
localVA, _ := setup(ms.Server, localUA, remoteVAs, nil)
|
localVA, _ := setupWithRemotes(ms.Server, pass, remoteConfs, nil)
|
||||||
|
|
||||||
// Perform validation for a domain not in the disabledDomains list
|
// Perform validation for a domain not in the disabledDomains list
|
||||||
req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01)
|
req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01)
|
||||||
|
|
@ -681,28 +743,19 @@ func TestMultiVAPolicy(t *testing.T) {
|
||||||
t.Error("expected prob from PerformValidation, got nil")
|
t.Error("expected prob from PerformValidation, got nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiVALogging(t *testing.T) {
|
func TestMultiVALogging(t *testing.T) {
|
||||||
const (
|
t.Parallel()
|
||||||
rva1UA = "remote 1"
|
|
||||||
rva2UA = "remote 2"
|
|
||||||
rva3UA = "remote 3"
|
|
||||||
localUA = "local 1"
|
|
||||||
)
|
|
||||||
|
|
||||||
ms := httpMultiSrv(t, expectedToken, map[string]bool{localUA: true, rva1UA: true, rva2UA: true})
|
ms := httpMultiSrv(t, expectedToken, map[string]bool{pass: true, fail: false})
|
||||||
defer ms.Close()
|
defer ms.Close()
|
||||||
|
|
||||||
rva1 := setupRemote(ms.Server, rva1UA, nil, "dev-arin", "ARIN")
|
remoteConfs := []remoteConf{
|
||||||
rva2 := setupRemote(ms.Server, rva2UA, nil, "dev-ripe", "RIPE")
|
{ua: pass, rir: arin},
|
||||||
rva3 := setupRemote(ms.Server, rva3UA, nil, "dev-ripe", "RIPE")
|
{ua: pass, rir: ripe},
|
||||||
|
{ua: pass, rir: apnic},
|
||||||
remoteVAs := []RemoteVA{
|
|
||||||
{rva1, rva1UA},
|
|
||||||
{rva2, rva2UA},
|
|
||||||
{rva3, rva3UA},
|
|
||||||
}
|
}
|
||||||
va, _ := setup(ms.Server, localUA, remoteVAs, nil)
|
|
||||||
|
va, _ := setupWithRemotes(ms.Server, pass, remoteConfs, nil)
|
||||||
req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01)
|
req := createValidationRequest("letsencrypt.org", core.ChallengeTypeHTTP01)
|
||||||
res, err := va.PerformValidation(ctx, req)
|
res, err := va.PerformValidation(ctx, req)
|
||||||
test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed with: %#v", res.Problems))
|
test.Assert(t, res.Problems == nil, fmt.Sprintf("validation failed with: %#v", res.Problems))
|
||||||
|
|
@ -762,19 +815,12 @@ func TestDetailedError(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogRemoteDifferentials(t *testing.T) {
|
func TestLogRemoteDifferentials(t *testing.T) {
|
||||||
// Create some remote VAs
|
remoteConfs := []remoteConf{
|
||||||
remoteVA1 := setupRemote(nil, "remote 1", nil, "", "")
|
{ua: pass, rir: arin},
|
||||||
remoteVA2 := setupRemote(nil, "remote 2", nil, "", "")
|
{ua: pass, rir: ripe},
|
||||||
remoteVA3 := setupRemote(nil, "remote 3", nil, "", "")
|
{ua: pass, rir: apnic},
|
||||||
// The VA will allow a max of 1 remote failure based on MPIC.
|
|
||||||
remoteVAs := []RemoteVA{
|
|
||||||
{remoteVA1, "remote 1"},
|
|
||||||
{remoteVA2, "remote 2"},
|
|
||||||
{remoteVA3, "remote 3"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localVA, mockLog := setup(nil, "local 1", remoteVAs, nil)
|
|
||||||
|
|
||||||
egProbA := probs.DNS("root DNS servers closed at 4:30pm")
|
egProbA := probs.DNS("root DNS servers closed at 4:30pm")
|
||||||
egProbB := probs.OrderNotReady("please take a number")
|
egProbB := probs.OrderNotReady("please take a number")
|
||||||
|
|
||||||
|
|
@ -813,7 +859,13 @@ func TestLogRemoteDifferentials(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
mockLog.Clear()
|
t.Parallel()
|
||||||
|
|
||||||
|
// Configure one test server per test case so that all tests can run in parallel.
|
||||||
|
ms := httpMultiSrv(t, expectedToken, map[string]bool{pass: true, fail: false})
|
||||||
|
defer ms.Close()
|
||||||
|
|
||||||
|
localVA, mockLog := setupWithRemotes(ms.Server, pass, remoteConfs, nil)
|
||||||
|
|
||||||
localVA.logRemoteResults(
|
localVA.logRemoteResults(
|
||||||
"example.com", 1999, "blorpus-01", tc.remoteProbs)
|
"example.com", 1999, "blorpus-01", tc.remoteProbs)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue