Skip to content

Commit 37b85fb

Browse files
VA/RVA: Add metadata necessary for the MPIC ballot (#7732)
- Add `Perspective` and `RIR` fields to the remote-va configuration - Configure RVA ValidationAuthorityImpl instances with the contents of the JSON configuration - Configure VA ValidationAuthorityImpl instances with the constant `va.PrimaryPerspective` - Log `Perspective` for non-Primary Perspectives, per the MPIC requirements in section 5.4.1 (2) vii of the BRs. Also log the RIR for posterity. - Introduce `ValidationResult` RPC fields `Perspective` and `Rir`, which are not currently used but will be required for corroboration in #7616 Fixes #7613 Part of #7615 Part of #7616
1 parent c5dae06 commit 37b85fb

File tree

10 files changed

+175
-43
lines changed

10 files changed

+175
-43
lines changed

cmd/boulder-va/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ func main() {
115115
scope,
116116
clk,
117117
logger,
118-
c.VA.AccountURIPrefixes)
118+
c.VA.AccountURIPrefixes,
119+
va.PrimaryPerspective,
120+
"")
119121
cmd.FailOnError(err, "Unable to create VA server")
120122

121123
start, err := bgrpc.NewServer(c.VA.GRPC, logger).Add(

cmd/remoteva/main.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,29 @@ type Config struct {
2020
RVA struct {
2121
vaConfig.Common
2222

23+
// Perspective uniquely identifies the Network Perspective used to
24+
// perform the validation, as specified in BRs Section 5.4.1,
25+
// Requirement 2.7 ("Multi-Perspective Issuance Corroboration attempts
26+
// from each Network Perspective"). It should uniquely identify a group
27+
// of RVAs deployed in the same datacenter.
28+
//
29+
// TODO(#7615): Make mandatory.
30+
Perspective string `validate:"omitempty"`
31+
32+
// RIR indicates the Regional Internet Registry where this RVA is
33+
// located. This field is used to identify the RIR region from which a
34+
// given validation was performed, as specified in the "Phased
35+
// Implementation Timeline" in BRs Section 3.2.2.9. It must be one of
36+
// the following values:
37+
// - ARIN
38+
// - RIPE
39+
// - APNIC
40+
// - LACNIC
41+
// - AfriNIC
42+
//
43+
// TODO(#7615): Make mandatory.
44+
RIR string `validate:"omitempty,oneof=ARIN RIPE APNIC LACNIC AfriNIC"`
45+
2346
// SkipGRPCClientCertVerification, when disabled as it should typically
2447
// be, will cause the remoteva server (which receives gRPCs from a
2548
// boulder-va client) to use our default RequireAndVerifyClientCert
@@ -118,7 +141,9 @@ func main() {
118141
scope,
119142
clk,
120143
logger,
121-
c.RVA.AccountURIPrefixes)
144+
c.RVA.AccountURIPrefixes,
145+
c.RVA.Perspective,
146+
c.RVA.RIR)
122147
cmd.FailOnError(err, "Unable to create Remote-VA server")
123148

124149
start, err := bgrpc.NewServer(c.RVA.GRPC, logger).Add(

core/objects.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ type ValidationRecord struct {
129129
Port string `json:"port,omitempty"`
130130
AddressesResolved []net.IP `json:"addressesResolved,omitempty"`
131131
AddressUsed net.IP `json:"addressUsed,omitempty"`
132+
132133
// AddressesTried contains a list of addresses tried before the `AddressUsed`.
133134
// Presently this will only ever be one IP from `AddressesResolved` since the
134135
// only retry is in the case of a v6 failure with one v4 fallback. E.g. if
@@ -144,10 +145,29 @@ type ValidationRecord struct {
144145
// ...
145146
// }
146147
AddressesTried []net.IP `json:"addressesTried,omitempty"`
148+
147149
// ResolverAddrs is the host:port of the DNS resolver(s) that fulfilled the
148150
// lookup for AddressUsed. During recursive A and AAAA lookups, a record may
149151
// instead look like A:host:port or AAAA:host:port
150152
ResolverAddrs []string `json:"resolverAddrs,omitempty"`
153+
154+
// Perspective uniquely identifies the Network Perspective used to perform
155+
// the validation, as specified in BRs Section 5.4.1, Requirement 2.7
156+
// ("Multi-Perspective Issuance Corroboration attempts from each Network
157+
// Perspective"). It should uniquely identify either the Primary Perspective
158+
// (VA) or a group of RVAs deployed in the same datacenter.
159+
Perspective string `json:"perspective,omitempty"`
160+
161+
// RIR indicates the Regional Internet Registry where this RVA is located.
162+
// This field is used to identify the RIR region from which a given
163+
// validation was performed, as specified in the "Phased Implementation
164+
// Timeline" in BRs Section 3.2.2.9. It must be one of the following values:
165+
// - ARIN
166+
// - RIPE
167+
// - APNIC
168+
// - LACNIC
169+
// - AfriNIC
170+
RIR string `json:"rir,omitempty"`
151171
}
152172

153173
// Challenge is an aggregate of all data needed for any challenges.

test/config-next/remoteva-a.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
"accountURIPrefixes": [
3737
"http://boulder.service.consul:4000/acme/reg/",
3838
"http://boulder.service.consul:4001/acme/acct/"
39-
]
39+
],
40+
"perspective": "development",
41+
"rir": "ARIN"
4042
},
4143
"syslog": {
4244
"stdoutlevel": 4,

test/config-next/remoteva-b.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
"accountURIPrefixes": [
3737
"http://boulder.service.consul:4000/acme/reg/",
3838
"http://boulder.service.consul:4001/acme/acct/"
39-
]
39+
],
40+
"perspective": "development",
41+
"rir": "RIPE"
4042
},
4143
"syslog": {
4244
"stdoutlevel": 4,

va/caa_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ func (b caaBrokenDNS) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, s
589589
}
590590

591591
func TestDisabledMultiCAARechecking(t *testing.T) {
592-
brokenRVA := setupRemote(nil, "broken", caaBrokenDNS{})
592+
brokenRVA, _ := setupRemote(nil, "broken", caaBrokenDNS{}, "", "")
593593
remoteVAs := []RemoteVA{{brokenRVA, "broken"}}
594594
va, _ := setup(nil, 0, "local", remoteVAs, nil)
595595

@@ -663,10 +663,10 @@ func TestMultiCAARechecking(t *testing.T) {
663663
brokenUA = "broken"
664664
hijackedUA = "hijacked"
665665
)
666-
remoteVA := setupRemote(nil, remoteUA, nil)
667-
brokenVA := setupRemote(nil, brokenUA, caaBrokenDNS{})
666+
remoteVA, _ := setupRemote(nil, remoteUA, nil, "", "")
667+
brokenVA, _ := setupRemote(nil, brokenUA, caaBrokenDNS{}, "", "")
668668
// Returns incorrect results
669-
hijackedVA := setupRemote(nil, hijackedUA, caaHijackedDNS{})
669+
hijackedVA, _ := setupRemote(nil, hijackedUA, caaHijackedDNS{}, "", "")
670670

671671
testCases := []struct {
672672
name string

va/proto/va.pb.go

Lines changed: 42 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

va/proto/va.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ message AuthzMeta {
4040
message ValidationResult {
4141
repeated core.ValidationRecord records = 1;
4242
core.ProblemDetails problems = 2;
43+
string perspective = 3;
44+
string rir = 4;
4345
}

va/va.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import (
3131
vapb "github.com/letsencrypt/boulder/va/proto"
3232
)
3333

34+
const PrimaryPerspective = "Primary"
35+
3436
var (
3537
// badTLSHeader contains the string 'HTTP /' which is returned when
3638
// we try to talk TLS to a server that only talks HTTP
@@ -256,6 +258,8 @@ type ValidationAuthorityImpl struct {
256258
maxRemoteFailures int
257259
accountURIPrefixes []string
258260
singleDialTimeout time.Duration
261+
perspective string
262+
rir string
259263

260264
metrics *vaMetrics
261265
}
@@ -274,6 +278,8 @@ func NewValidationAuthorityImpl(
274278
clk clock.Clock,
275279
logger blog.Logger,
276280
accountURIPrefixes []string,
281+
perspective string,
282+
rir string,
277283
) (*ValidationAuthorityImpl, error) {
278284

279285
if len(accountURIPrefixes) == 0 {
@@ -300,6 +306,8 @@ func NewValidationAuthorityImpl(
300306
// used for the DialContext operations that take place during an
301307
// HTTP-01 challenge validation.
302308
singleDialTimeout: 10 * time.Second,
309+
perspective: perspective,
310+
rir: rir,
303311
}
304312

305313
return va, nil
@@ -314,6 +322,8 @@ type verificationRequestEvent struct {
314322
ValidationLatency float64
315323
Error string `json:",omitempty"`
316324
InternalError string `json:",omitempty"`
325+
Perspective string `json:",omitempty"`
326+
RIR string `json:",omitempty"`
317327
}
318328

319329
// ipError is an error type used to pass though the IP address of the remote
@@ -668,6 +678,18 @@ func (va *ValidationAuthorityImpl) PerformValidation(ctx context.Context, req *v
668678
logEvent.Challenge.Status = core.StatusValid
669679
}
670680

681+
if va.perspective != "" && va.perspective != PrimaryPerspective {
682+
// This validation was performed by a remote VA. According to the
683+
// requirements in section 5.4.1 (2) vii of the BRs we need to log
684+
// the perspective used. Additionally, we'll log the RIR where this
685+
// RVA is located.
686+
//
687+
// TODO(#7615): Make these fields mandatory for non-Primary
688+
// perspectives and remove the (va.perspective != "") check.
689+
logEvent.Perspective = va.perspective
690+
logEvent.RIR = va.rir
691+
}
692+
671693
va.metrics.localValidationTime.With(prometheus.Labels{
672694
"type": string(logEvent.Challenge.Type),
673695
"result": string(logEvent.Challenge.Status),

0 commit comments

Comments
 (0)