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
This commit is contained in:
parent
7068db96fe
commit
636d30f4a9
193
ra/ra.go
193
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
Loading…
Reference in New Issue