bad-key-revoker: also revoke accounts with blocked keys#8837
bad-key-revoker: also revoke accounts with blocked keys#8837aarongable wants to merge 2 commits into
Conversation
|
@aarongable, this PR adds one or more new feature flags: DeactivateBadKeyAccounts. As such, this PR must be accompanied by a review of the Let's Encrypt CP/CPS to ensure that our behavior both before and after this flag is flipped is compliant with that document. Please conduct such a review, then add your findings to the PR description in a paragraph beginning with "CPS Compliance Review:". |
There was a problem hiding this comment.
Nice, updating the PR to use the "revoked" status gives us a clear understanding of the source of the state change.
Looking through Boulder at how we treat account status, and especially revoked, this will be the first use of revoked for us! I don't think there's any immediate problems with this but there's some defense in depth changes that we should consider:
- Inside of
wfe.lookupJWK()we make the correct comparison:core.AcmeStatus(account.Status) != core.StatusValidbut the comment above it// Verify the account is not deactivatedshould be updated to indicate what this clause is guarding against. - Inside of the anonymous function
returnExistingAcct()(inside ofwfe.NewAccount()) we perform the wrong comparisonif core.AcmeStatus(acctPB.Status) == core.StatusDeactivatedand the comment here should be updated. Today this is unreachable thanks to the earlier call towfe.validSelfAuthenticatedPOST()which usesGoodKey()to check for blocked keys. sa.UpdateRegistrationKey()performsUPDATE registrations SET jwk = ?, jwk_sha256 = ? WHERE id = ? LIMIT 1with no status guard, unlikeDeactivateRegistration()which performsUPDATE registrations SET status = ? WHERE status = ? AND id = ? LIMIT 1.- Lastly, I think there's a race we can narrow here. When we rollover an account key in the WFE we do not check the current account key against
blockedKeys, only the new one. Once we add a key toblockedKeyswe have ~bad-key-revoker backlog + maxReplicationTime + intervalbefore thebad-key-revokerwill revoke an account with that key. What would you think about checking the old key as well?
| // DeactivateBadKeyAccounts controls whether bad-key-revoker will attempt | ||
| // to find and deactivate accounts using keys which have been added to the | ||
| // blockedKeys table. | ||
| DeactivateBadKeyAccounts bool |
There was a problem hiding this comment.
The name of this feature flag and the comment needs to be updated.
When bad-key-revoker is processing a new row from the blockedKeys table, also revoke any accounts whose key matches the newly-blocked key. "Revoking" is the equivalent of "deactivating" under RFC 8555, but initiated by the ACME Server instead of at the request of the Client. This ensures that a key compromise doesn't allow a bad actor to take over an ACME account.
Put the new behavior behind a feature flag, because it requires a database permission change that will have to be deployed separately. Also add a new helper function to core/util.go, to ensure that the way we calculate account key hashes never diverges from the way we compute certificate key hashes.
Fixes #5683
IN-12841 tracks the corresponding SRE-side database and config changes
CPS Compliance Review: our statement regarding our behavior when compromise is demonstrated is "When key compromise is demonstrated, ISRG blocks the key from use in future issuance and revokes at least all unexpired non-Short-lived Subscriber Certificates that used that key." This does not preclude us from taking further actions, such as revoking accounts using the same key. We may want to document this new behavior in our CP/CPS in the future, but doing so is not necessary.