From 636d30f4a9a2a83b7cfc12c5f99178daff4e8fbd Mon Sep 17 00:00:00 2001 From: Samantha Date: Mon, 11 Sep 2023 15:06:16 -0400 Subject: [PATCH] ratelimit: Overhaul metrics for the our existing rate limits (#7054) - Use constants for each rate limit name to ensure consistency when labeling metrics - Consistently check `.Enabled()` outside of each limit check RA method - Replace the existing checks counter with a latency histogram Part of #5545 --- ra/ra.go | 193 +++++++++++++++++++++++---------------- ra/ra_test.go | 15 ++- ratelimit/rate-limits.go | 36 ++++++++ ratelimits/limiter.go | 10 ++ 4 files changed, 173 insertions(+), 81 deletions(-) diff --git a/ra/ra.go b/ra/ra.go index 95e846a0c..21c7c2fc7 100644 --- a/ra/ra.go +++ b/ra/ra.go @@ -46,6 +46,7 @@ import ( pubpb "github.com/letsencrypt/boulder/publisher/proto" rapb "github.com/letsencrypt/boulder/ra/proto" "github.com/letsencrypt/boulder/ratelimit" + "github.com/letsencrypt/boulder/ratelimits" "github.com/letsencrypt/boulder/reloader" "github.com/letsencrypt/boulder/revocation" sapb "github.com/letsencrypt/boulder/sa/proto" @@ -106,9 +107,9 @@ type RegistrationAuthorityImpl struct { ctpolicy *ctpolicy.CTPolicy ctpolicyResults *prometheus.HistogramVec - rateLimitCounter *prometheus.CounterVec revocationReasonCounter *prometheus.CounterVec namesPerCert *prometheus.HistogramVec + rlCheckLatency *prometheus.HistogramVec newRegCounter prometheus.Counter recheckCAACounter prometheus.Counter newCertCounter prometheus.Counter @@ -159,11 +160,11 @@ func NewRegistrationAuthorityImpl( ) stats.MustRegister(namesPerCert) - rateLimitCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "ra_ratelimits", - Help: "A counter of RA ratelimit checks labelled by type and pass/exceed", - }, []string{"limit", "result"}) - stats.MustRegister(rateLimitCounter) + rlCheckLatency := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: "ratelimitsv1_check_latency_seconds", + Help: fmt.Sprintf("Latency of ratelimit checks labeled by limit=[name] and decision=[%s|%s], in seconds", ratelimits.Allowed, ratelimits.Denied), + }, []string{"limit", "decision"}) + stats.MustRegister(rlCheckLatency) newRegCounter := prometheus.NewCounter(prometheus.CounterOpts{ Name: "new_registrations", @@ -251,7 +252,7 @@ func NewRegistrationAuthorityImpl( issuersByNameID: issuersByNameID, issuersByID: issuersByID, namesPerCert: namesPerCert, - rateLimitCounter: rateLimitCounter, + rlCheckLatency: rlCheckLatency, newRegCounter: newRegCounter, recheckCAACounter: recheckCAACounter, newCertCounter: newCertCounter, @@ -364,10 +365,6 @@ type registrationCounter func(context.Context, *sapb.CountRegistrationsByIPReque // provided registrationCounter function to determine if the limit has been // exceeded for a given IP or IP range func (ra *RegistrationAuthorityImpl) checkRegistrationIPLimit(ctx context.Context, limit ratelimit.RateLimitPolicy, ip net.IP, counter registrationCounter) error { - if !limit.Enabled() { - return nil - } - now := ra.clk.Now() count, err := counter(ctx, &sapb.CountRegistrationsByIPRequest{ Ip: ip, @@ -393,13 +390,19 @@ func (ra *RegistrationAuthorityImpl) checkRegistrationLimits(ctx context.Context // Check the registrations per IP limit using the CountRegistrationsByIP SA // function that matches IP addresses exactly exactRegLimit := ra.rlPolicies.RegistrationsPerIP() - err := ra.checkRegistrationIPLimit(ctx, exactRegLimit, ip, ra.SA.CountRegistrationsByIP) - if err != nil { - ra.rateLimitCounter.WithLabelValues("registrations_by_ip", "exceeded").Inc() - ra.log.Infof("Rate limit exceeded, RegistrationsByIP, IP: %s", ip) - return err + if exactRegLimit.Enabled() { + started := ra.clk.Now() + err := ra.checkRegistrationIPLimit(ctx, exactRegLimit, ip, ra.SA.CountRegistrationsByIP) + elapsed := ra.clk.Since(started) + if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.RegistrationsPerIP, ratelimits.Denied).Observe(elapsed.Seconds()) + ra.log.Infof("Rate limit exceeded, RegistrationsPerIP, by IP: %q", ip) + } + return err + } + ra.rlCheckLatency.WithLabelValues(ratelimit.RegistrationsPerIP, ratelimits.Allowed).Observe(elapsed.Seconds()) } - ra.rateLimitCounter.WithLabelValues("registrations_by_ip", "pass").Inc() // We only apply the fuzzy reg limit to IPv6 addresses. // Per https://golang.org/pkg/net/#IP.To4 "If ip is not an IPv4 address, To4 @@ -412,15 +415,23 @@ func (ra *RegistrationAuthorityImpl) checkRegistrationLimits(ctx context.Context // CountRegistrationsByIPRange SA function that fuzzy-matches IPv6 addresses // within a larger address range fuzzyRegLimit := ra.rlPolicies.RegistrationsPerIPRange() - err = ra.checkRegistrationIPLimit(ctx, fuzzyRegLimit, ip, ra.SA.CountRegistrationsByIPRange) - if err != nil { - ra.rateLimitCounter.WithLabelValues("registrations_by_ip_range", "exceeded").Inc() - ra.log.Infof("Rate limit exceeded, RegistrationsByIPRange, IP: %s", ip) - // For the fuzzyRegLimit we use a new error message that specifically - // mentions that the limit being exceeded is applied to a *range* of IPs - return berrors.RateLimitError(0, "too many registrations for this IP range") + if fuzzyRegLimit.Enabled() { + started := ra.clk.Now() + err := ra.checkRegistrationIPLimit(ctx, fuzzyRegLimit, ip, ra.SA.CountRegistrationsByIPRange) + elapsed := ra.clk.Since(started) + if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.RegistrationsPerIPRange, ratelimits.Denied).Observe(elapsed.Seconds()) + ra.log.Infof("Rate limit exceeded, RegistrationsByIPRange, IP: %q", ip) + + // For the fuzzyRegLimit we use a new error message that specifically + // mentions that the limit being exceeded is applied to a *range* of IPs + return berrors.RateLimitError(0, "too many registrations for this IP range") + } + return err + } + ra.rlCheckLatency.WithLabelValues(ratelimit.RegistrationsPerIPRange, ratelimits.Allowed).Observe(elapsed.Seconds()) } - ra.rateLimitCounter.WithLabelValues("registrations_by_ip_range", "pass").Inc() return nil } @@ -553,38 +564,33 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error { return nil } -func (ra *RegistrationAuthorityImpl) checkPendingAuthorizationLimit(ctx context.Context, regID int64) error { - limit := ra.rlPolicies.PendingAuthorizationsPerAccount() - if limit.Enabled() { - // This rate limit's threshold can only be overridden on a per-regID basis, - // not based on any other key. - threshold := limit.GetThreshold("", regID) - if threshold == -1 { - return nil - } - countPB, err := ra.SA.CountPendingAuthorizations2(ctx, &sapb.RegistrationID{ - Id: regID, - }) - if err != nil { - return err - } - if countPB.Count >= threshold { - ra.rateLimitCounter.WithLabelValues("pending_authorizations_by_registration_id", "exceeded").Inc() - ra.log.Infof("Rate limit exceeded, PendingAuthorizationsByRegID, regID: %d", regID) - return berrors.RateLimitError(0, "too many currently pending authorizations: %d", countPB.Count) - } - ra.rateLimitCounter.WithLabelValues("pending_authorizations_by_registration_id", "pass").Inc() +func (ra *RegistrationAuthorityImpl) checkPendingAuthorizationLimit(ctx context.Context, regID int64, limit ratelimit.RateLimitPolicy) error { + // This rate limit's threshold can only be overridden on a per-regID basis, + // not based on any other key. + threshold := limit.GetThreshold("", regID) + if threshold == -1 { + return nil + } + countPB, err := ra.SA.CountPendingAuthorizations2(ctx, &sapb.RegistrationID{ + Id: regID, + }) + if err != nil { + return err + } + if countPB.Count >= threshold { + ra.log.Infof("Rate limit exceeded, PendingAuthorizationsByRegID, regID: %d", regID) + return berrors.RateLimitError(0, "too many currently pending authorizations: %d", countPB.Count) } return nil } // checkInvalidAuthorizationLimits checks the failed validation limit for each // of the provided hostnames. It returns the first error. -func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimits(ctx context.Context, regID int64, hostnames []string) error { +func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimits(ctx context.Context, regID int64, hostnames []string, limits ratelimit.RateLimitPolicy) error { results := make(chan error, len(hostnames)) for _, hostname := range hostnames { go func(hostname string) { - results <- ra.checkInvalidAuthorizationLimit(ctx, regID, hostname) + results <- ra.checkInvalidAuthorizationLimit(ctx, regID, hostname, limits) }(hostname) } // We don't have to wait for all of the goroutines to finish because there's @@ -599,11 +605,7 @@ func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimits(ctx context return nil } -func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimit(ctx context.Context, regID int64, hostname string) error { - limit := ra.rlPolicies.InvalidAuthorizationsPerAccount() - if !limit.Enabled() { - return nil - } +func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimit(ctx context.Context, regID int64, hostname string, limit ratelimit.RateLimitPolicy) error { latest := ra.clk.Now().Add(ra.pendingAuthorizationLifetime) earliest := latest.Add(-limit.Window.Duration) req := &sapb.CountInvalidAuthorizationsRequest{ @@ -631,11 +633,7 @@ func (ra *RegistrationAuthorityImpl) checkInvalidAuthorizationLimit(ctx context. // checkNewOrdersPerAccountLimit enforces the rlPolicies `NewOrdersPerAccount` // rate limit. This rate limit ensures a client can not create more than the // specified threshold of new orders within the specified time window. -func (ra *RegistrationAuthorityImpl) checkNewOrdersPerAccountLimit(ctx context.Context, acctID int64) error { - limit := ra.rlPolicies.NewOrdersPerAccount() - if !limit.Enabled() { - return nil - } +func (ra *RegistrationAuthorityImpl) checkNewOrdersPerAccountLimit(ctx context.Context, acctID int64, limit ratelimit.RateLimitPolicy) error { now := ra.clk.Now() count, err := ra.SA.CountOrders(ctx, &sapb.CountOrdersRequest{ AccountID: acctID, @@ -650,10 +648,8 @@ func (ra *RegistrationAuthorityImpl) checkNewOrdersPerAccountLimit(ctx context.C // There is no meaningful override key to use for this rate limit noKey := "" if count.Count >= limit.GetThreshold(noKey, acctID) { - ra.rateLimitCounter.WithLabelValues("new_order_by_registration_id", "exceeded").Inc() return berrors.RateLimitError(0, "too many new orders recently") } - ra.rateLimitCounter.WithLabelValues("new_order_by_registration_id", "pass").Inc() return nil } @@ -1403,7 +1399,6 @@ func (ra *RegistrationAuthorityImpl) checkCertificatesPerNameLimit(ctx context.C return fmt.Errorf("checking renewal exemption for %q: %s", names, err) } if exists.Exists { - ra.rateLimitCounter.WithLabelValues("certificates_for_domain", "FQDN set bypass").Inc() return nil } @@ -1421,7 +1416,6 @@ func (ra *RegistrationAuthorityImpl) checkCertificatesPerNameLimit(ctx context.C retryString := earliest.Add(limit.Window.Duration).Format(time.RFC3339) ra.log.Infof("Rate limit exceeded, CertificatesForDomain, regID: %d, domains: %s", regID, strings.Join(namesOutOfLimit, ", ")) - ra.rateLimitCounter.WithLabelValues("certificates_for_domain", "exceeded").Inc() if len(namesOutOfLimit) > 1 { var subErrors []berrors.SubBoulderError for _, name := range namesOutOfLimit { @@ -1434,7 +1428,6 @@ func (ra *RegistrationAuthorityImpl) checkCertificatesPerNameLimit(ctx context.C } return berrors.RateLimitError(retryAfter, "too many certificates already issued for %q. Retry after %s", namesOutOfLimit[0], retryString) } - ra.rateLimitCounter.WithLabelValues("certificates_for_domain", "pass").Inc() return nil } @@ -1483,40 +1476,75 @@ func (ra *RegistrationAuthorityImpl) checkCertificatesPerFQDNSetLimit(ctx contex } } -func (ra *RegistrationAuthorityImpl) checkLimits(ctx context.Context, names []string, regID int64) error { - // Check if there is rate limit space for a new order within the current window. - err := ra.checkNewOrdersPerAccountLimit(ctx, regID) - if err != nil { - return err +func (ra *RegistrationAuthorityImpl) checkNewOrderLimits(ctx context.Context, names []string, regID int64) error { + newOrdersPerAccountLimits := ra.rlPolicies.NewOrdersPerAccount() + if newOrdersPerAccountLimits.Enabled() { + started := ra.clk.Now() + err := ra.checkNewOrdersPerAccountLimit(ctx, regID, newOrdersPerAccountLimits) + elapsed := ra.clk.Since(started) + if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.NewOrdersPerAccount, ratelimits.Denied).Observe(elapsed.Seconds()) + } + return err + } + ra.rlCheckLatency.WithLabelValues(ratelimit.NewOrdersPerAccount, ratelimits.Allowed).Observe(elapsed.Seconds()) } certNameLimits := ra.rlPolicies.CertificatesPerName() if certNameLimits.Enabled() { + started := ra.clk.Now() err := ra.checkCertificatesPerNameLimit(ctx, names, certNameLimits, regID) + elapsed := ra.clk.Since(started) if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerName, ratelimits.Denied).Observe(elapsed.Seconds()) + } return err } + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerName, ratelimits.Allowed).Observe(elapsed.Seconds()) } - fqdnFastLimits := ra.rlPolicies.CertificatesPerFQDNSetFast() - if fqdnFastLimits.Enabled() { - err := ra.checkCertificatesPerFQDNSetLimit(ctx, names, fqdnFastLimits, regID) + fqdnLimitsFast := ra.rlPolicies.CertificatesPerFQDNSetFast() + if fqdnLimitsFast.Enabled() { + started := ra.clk.Now() + err := ra.checkCertificatesPerFQDNSetLimit(ctx, names, fqdnLimitsFast, regID) + elapsed := ra.clk.Since(started) if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerFQDNSetFast, ratelimits.Denied).Observe(elapsed.Seconds()) + } return err } + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerFQDNSetFast, ratelimits.Allowed).Observe(elapsed.Seconds()) } fqdnLimits := ra.rlPolicies.CertificatesPerFQDNSet() if fqdnLimits.Enabled() { + started := ra.clk.Now() err := ra.checkCertificatesPerFQDNSetLimit(ctx, names, fqdnLimits, regID) + elapsed := ra.clk.Since(started) if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerFQDNSet, ratelimits.Denied).Observe(elapsed.Seconds()) + } return err } + ra.rlCheckLatency.WithLabelValues(ratelimit.CertificatesPerFQDNSet, ratelimits.Allowed).Observe(elapsed.Seconds()) } - err = ra.checkInvalidAuthorizationLimits(ctx, regID, names) - if err != nil { - return err + invalidAuthzPerAccountLimits := ra.rlPolicies.InvalidAuthorizationsPerAccount() + if invalidAuthzPerAccountLimits.Enabled() { + started := ra.clk.Now() + err := ra.checkInvalidAuthorizationLimits(ctx, regID, names, invalidAuthzPerAccountLimits) + elapsed := ra.clk.Since(started) + if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.InvalidAuthorizationsPerAccount, ratelimits.Denied).Observe(elapsed.Seconds()) + } + return err + } + ra.rlCheckLatency.WithLabelValues(ratelimit.InvalidAuthorizationsPerAccount, ratelimits.Allowed).Observe(elapsed.Seconds()) } return nil @@ -2366,7 +2394,7 @@ func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.New } // Check if there is rate limit space for issuing a certificate. - err = ra.checkLimits(ctx, newOrder.Names, newOrder.RegistrationID) + err = ra.checkNewOrderLimits(ctx, newOrder.Names, newOrder.RegistrationID) if err != nil { return nil, err } @@ -2444,9 +2472,18 @@ func (ra *RegistrationAuthorityImpl) NewOrder(ctx context.Context, req *rapb.New // If the order isn't fully authorized we need to check that the client has // rate limit room for more pending authorizations if len(missingAuthzNames) > 0 { - err := ra.checkPendingAuthorizationLimit(ctx, newOrder.RegistrationID) - if err != nil { - return nil, err + pendingAuthzLimits := ra.rlPolicies.PendingAuthorizationsPerAccount() + if pendingAuthzLimits.Enabled() { + started := ra.clk.Now() + err := ra.checkPendingAuthorizationLimit(ctx, newOrder.RegistrationID, pendingAuthzLimits) + elapsed := ra.clk.Since(started) + if err != nil { + if errors.Is(err, berrors.RateLimit) { + ra.rlCheckLatency.WithLabelValues(ratelimit.PendingAuthorizationsPerAccount, ratelimits.Denied).Observe(elapsed.Seconds()) + } + return nil, err + } + ra.rlCheckLatency.WithLabelValues(ratelimit.PendingAuthorizationsPerAccount, ratelimits.Allowed).Observe(elapsed.Seconds()) } } diff --git a/ra/ra_test.go b/ra/ra_test.go index e69e7c1ba..f965f298d 100644 --- a/ra/ra_test.go +++ b/ra/ra_test.go @@ -55,6 +55,7 @@ import ( pubpb "github.com/letsencrypt/boulder/publisher/proto" rapb "github.com/letsencrypt/boulder/ra/proto" "github.com/letsencrypt/boulder/ratelimit" + "github.com/letsencrypt/boulder/ratelimits" "github.com/letsencrypt/boulder/sa" sapb "github.com/letsencrypt/boulder/sa/proto" "github.com/letsencrypt/boulder/test" @@ -230,7 +231,7 @@ var testKeyPolicy = goodkey.KeyPolicy{ var ctx = context.Background() -// dummyRateLimitConfig satisfies the ratelimit.RateLimitConfig interface while +// dummyRateLimitConfig satisfies the rl.RateLimitConfig interface while // allowing easy mocking of the individual RateLimitPolicy's type dummyRateLimitConfig struct { CertificatesPerNamePolicy ratelimit.RateLimitPolicy @@ -641,6 +642,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { // There should be no errors - it is within the RegistrationsPerIP rate limit _, err := ra.NewRegistration(ctx, reg) test.AssertNotError(t, err, "Unexpected error adding new IPv4 registration") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Allowed}, 1) // Create another registration for the same IPv4 address by changing the key reg.Key = newAcctKey(t) @@ -650,6 +652,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { _, err = ra.NewRegistration(ctx, reg) test.AssertError(t, err, "No error adding duplicate IPv4 registration") test.AssertEquals(t, err.Error(), "too many registrations for this IP: see https://letsencrypt.org/docs/too-many-registrations-for-this-ip/") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Denied}, 1) // Create a registration for an IPv6 address reg.Key = newAcctKey(t) @@ -658,6 +661,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { // There should be no errors - it is within the RegistrationsPerIP rate limit _, err = ra.NewRegistration(ctx, reg) test.AssertNotError(t, err, "Unexpected error adding a new IPv6 registration") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Allowed}, 2) // Create a 2nd registration for the IPv6 address by changing the key reg.Key = newAcctKey(t) @@ -667,6 +671,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { _, err = ra.NewRegistration(ctx, reg) test.AssertError(t, err, "No error adding duplicate IPv6 registration") test.AssertEquals(t, err.Error(), "too many registrations for this IP: see https://letsencrypt.org/docs/too-many-registrations-for-this-ip/") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIP, "decision": ratelimits.Denied}, 2) // Create a registration for an IPv6 address in the same /48 reg.Key = newAcctKey(t) @@ -676,6 +681,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { // within the RegistrationsPerIPRange limit _, err = ra.NewRegistration(ctx, reg) test.AssertNotError(t, err, "Unexpected error adding second IPv6 registration in the same /48") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIPRange, "decision": ratelimits.Allowed}, 2) // Create a registration for yet another IPv6 address in the same /48 reg.Key = newAcctKey(t) @@ -686,6 +692,7 @@ func TestNewRegistrationRateLimit(t *testing.T) { _, err = ra.NewRegistration(ctx, reg) test.AssertError(t, err, "No error adding a third IPv6 registration in the same /48") test.AssertEquals(t, err.Error(), "too many registrations for this IP range: see https://letsencrypt.org/docs/rate-limits/") + test.AssertMetricWithLabelsEquals(t, ra.rlCheckLatency, prometheus.Labels{"limit": ratelimit.RegistrationsPerIPRange, "decision": ratelimits.Denied}, 1) } type NoUpdateSA struct { @@ -1048,9 +1055,10 @@ func TestAuthzFailedRateLimitingNewOrder(t *testing.T) { } testcase := func() { + limit := ra.rlPolicies.InvalidAuthorizationsPerAccount() ra.SA = &mockInvalidAuthorizationsAuthority{domainWithFailures: "all.i.do.is.lose.com"} err := ra.checkInvalidAuthorizationLimits(ctx, Registration.Id, - []string{"charlie.brown.com", "all.i.do.is.lose.com"}) + []string{"charlie.brown.com", "all.i.do.is.lose.com"}, limit) test.AssertError(t, err, "checkInvalidAuthorizationLimits did not encounter expected rate limit error") test.AssertEquals(t, err.Error(), "too many failed authorizations recently: see https://letsencrypt.org/docs/failed-validation-limit/") } @@ -2157,7 +2165,8 @@ func TestPendingAuthorizationsUnlimited(t *testing.T) { ra.SA = &mockSACountPendingFails{} - err := ra.checkPendingAuthorizationLimit(context.Background(), 13) + limit := ra.rlPolicies.PendingAuthorizationsPerAccount() + err := ra.checkPendingAuthorizationLimit(context.Background(), 13, limit) test.AssertNotError(t, err, "checking pending authorization limit") } diff --git a/ratelimit/rate-limits.go b/ratelimit/rate-limits.go index 422b634ad..bbca3dc40 100644 --- a/ratelimit/rate-limits.go +++ b/ratelimit/rate-limits.go @@ -8,6 +8,42 @@ import ( "github.com/letsencrypt/boulder/strictyaml" ) +const ( + // CertificatesPerName is the name of the CertificatesPerName rate limit + // when referenced in metric labels. + CertificatesPerName = "certificates_per_domain_per_account" + + // RegistrationsPerIP is the name of the RegistrationsPerIP rate limit when + // referenced in metric labels. + RegistrationsPerIP = "registrations_per_ip" + + // RegistrationsPerIPRange is the name of the RegistrationsPerIPRange rate + // limit when referenced in metric labels. + RegistrationsPerIPRange = "registrations_per_ipv6_range" + + // PendingAuthorizationsPerAccount is the name of the + // PendingAuthorizationsPerAccount rate limit when referenced in metric + // labels. + PendingAuthorizationsPerAccount = "pending_authorizations_per_account" + + // InvalidAuthorizationsPerAccount is the name of the + // InvalidAuthorizationsPerAccount rate limit when referenced in metric + // labels. + InvalidAuthorizationsPerAccount = "failed_authorizations_per_account" + + // CertificatesPerFQDNSet is the name of the CertificatesPerFQDNSet rate + // limit when referenced in metric labels. + CertificatesPerFQDNSet = "certificates_per_fqdn_set_per_account" + + // CertificatesPerFQDNSetFast is the name of the CertificatesPerFQDNSetFast + // rate limit when referenced in metric labels. + CertificatesPerFQDNSetFast = "certificates_per_fqdn_set_per_account_fast" + + // NewOrdersPerAccount is the name of the NewOrdersPerAccount rate limit + // when referenced in metric labels. + NewOrdersPerAccount = "new_orders_per_account" +) + // Limits is defined to allow mock implementations be provided during unit // testing type Limits interface { diff --git a/ratelimits/limiter.go b/ratelimits/limiter.go index 8666e8791..d5cd9fad9 100644 --- a/ratelimits/limiter.go +++ b/ratelimits/limiter.go @@ -10,6 +10,16 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const ( + // Allowed is used for rate limit metrics, it's the value of the 'decision' + // label when a request was allowed. + Allowed = "allowed" + + // Denied is used for rate limit metrics, it's the value of the 'decision' + // label when a request was denied. + Denied = "denied" +) + // ErrInvalidCost indicates that the cost specified was <= 0. var ErrInvalidCost = fmt.Errorf("invalid cost, must be > 0")