New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve renewal rate limiting #2832
Changes from 2 commits
a79a73d
b0d8345
ed3ff70
369dfbc
76e30d1
4ec800d
712b4a6
8314b9e
c32623c
10c32a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -434,10 +434,10 @@ func (ssa *SQLStorageAuthority) countCertificatesByExactName(domain string, earl | |
} | ||
|
||
// countCertificates returns, for a single domain, the count of | ||
// non-renewal certificates issued in the given time range for that domain using the | ||
// non-renewal certificate issuances in the given time range for that domain using the | ||
// provided query, assumed to be either `countCertificatesExactSelect` or | ||
// `countCertificatesSelect`. Renewals of certificates issued within the same | ||
// window are considered "free" and not returned as part of this count. | ||
// window are considered "free" and are not counted. | ||
// | ||
// The highest count this function can return is 10,000. If there are more | ||
// certificates than that matching one of the provided domain names, it will return | ||
|
@@ -1046,10 +1046,14 @@ func (ssa *SQLStorageAuthority) CountFQDNSets(ctx context.Context, window time.D | |
return count, err | ||
} | ||
|
||
// getFQDNSetsBySerials returns a slice of []byte `setHash` entries from the | ||
// fqdnSets table for the certificate serials provided. | ||
func (ssa *SQLStorageAuthority) getFQDNSetsBySerials(serials []string) ([][]byte, error) { | ||
var fqdnSets [][]byte | ||
// setHash is a []byte representing the hash of an FQDN Set | ||
type setHash []byte | ||
|
||
// getFQDNSetsBySerials finds the setHashes corresponding to a set of | ||
// certificate serials. These serials can be used to check whether any | ||
// certificates have been issued for the same set of names previously. | ||
func (ssa *SQLStorageAuthority) getFQDNSetsBySerials(serials []string) ([]setHash, error) { | ||
var fqdnSets []setHash | ||
|
||
// It is unexpected that this function would be called with no serials | ||
if len(serials) == 0 { | ||
|
@@ -1065,32 +1069,38 @@ func (ssa *SQLStorageAuthority) getFQDNSetsBySerials(serials []string) ([][]byte | |
qmarks[i] = "?" | ||
} | ||
query := "SELECT setHash FROM fqdnSets " + | ||
"WHERE serial IN (" + strings.Join(qmarks, ",") + ") " | ||
"WHERE serial IN (" + strings.Join(qmarks, ",") + ")" | ||
_, err := ssa.dbMap.Select( | ||
&fqdnSets, | ||
query, | ||
params...) | ||
|
||
if err != nil && err != sql.ErrNoRows { | ||
// NOTE(@cpu): We don't explicitly check if `err != sql.ErrNoRows` here | ||
// because we *want* ErrNoRows to be treated as an error since its an internal | ||
// consistency violation. The serials existed when we found them in | ||
// issuedNames, they should continue to exist here. | ||
if err != nil { | ||
return nil, err | ||
} | ||
return fqdnSets, nil | ||
} | ||
|
||
// getNewIssuancesByFQDNSet returns a count of new issuances (renewals are not | ||
// included) for a given slice of fqdnSets that were issued after the earliest | ||
// included) for a given slice of fqdnSets that occurred after the earliest | ||
// parameter. | ||
func (ssa *SQLStorageAuthority) getNewIssuancesByFQDNSet(fqdnSets [][]byte, earliest time.Time) (int, error) { | ||
func (ssa *SQLStorageAuthority) getNewIssuancesByFQDNSet(fqdnSets []setHash, earliest time.Time) (int, error) { | ||
var results []struct { | ||
Serial string | ||
SetHash []byte | ||
SetHash setHash | ||
Issued time.Time | ||
} | ||
|
||
qmarks := make([]string, len(fqdnSets)) | ||
params := make([]interface{}, len(fqdnSets)) | ||
for i, setHash := range fqdnSets { | ||
params[i] = setHash | ||
// We have to cast the setHash back to []byte here since the sql package | ||
// isn't able to convert `sa.setHash` for the parameter value itself | ||
params[i] = []byte(setHash) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Side note: probably doesn't make sense for this since it's a single use but we could add a converter case to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point. Agreed that its probably not worth it here, but good to know for the future. |
||
qmarks[i] = "?" | ||
} | ||
|
||
|
@@ -1115,15 +1125,15 @@ func (ssa *SQLStorageAuthority) getNewIssuancesByFQDNSet(fqdnSets [][]byte, earl | |
return 0, err | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per above comment you're also not consistently returning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch - in that case I'll just update the whole thing to use |
||
} | ||
|
||
processedSetHashes := make(map[string]struct{}) | ||
processedSetHashes := make(map[string]bool) | ||
issuanceCount := 0 | ||
// Loop through each set hash result, counting issuance per unique set hash | ||
// Loop through each set hash result, counting issuances per unique set hash | ||
// that are within the window specified by the earliest parameter | ||
for _, result := range results { | ||
key := string(result.SetHash) | ||
// Skip set hashes that we have already processed - we only care about the | ||
// first issuance | ||
if _, exists := processedSetHashes[key]; exists { | ||
if processedSetHashes[key] { | ||
continue | ||
} | ||
|
||
|
@@ -1134,7 +1144,7 @@ func (ssa *SQLStorageAuthority) getNewIssuancesByFQDNSet(fqdnSets [][]byte, earl | |
|
||
// Otherwise note the issuance and mark the set hash as processed | ||
issuanceCount++ | ||
processedSetHashes[key] = struct{}{} | ||
processedSetHashes[key] = true | ||
} | ||
|
||
// Return the count of how many non-renewal issuances there were | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, but even better would be to use the same number of lines to explicitly check for ErrNoRows, and log an error saying something about "internal consistency violation" like above. Leans a little more in the "self-documenting code" direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolved (I pushed the commit but it hasn't shown up yet. Maybe some GH lag?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There it is: Fixed in 76e30d1