-
Notifications
You must be signed in to change notification settings - Fork 240
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
proposal: consider adding a chain storage interface to ctfe #691
Comments
Hi Roland. You're right that the certificate chains can entail a significant amount of duplicate data, so your rationale for coming up with a scheme to deduplicate makes a lot of sense to me. We don't have the bandwidth to do this work, but we're open to pull requests that implement this behaviour. As Trillian and CTFE are both used elsewhere, this gives the following constraints:
Your proposal sounds good to me, i.e. that some kind of key is serialized to ExtraData, which is then parsed by CTFE, which uses this key to load the cert chain from a new storage backend . This will require CTFE being configured with a new backend storage. This backend should not be required if the new flag is not provided. I don't have strong opinions on what this key format or backend should be, but as a guiding pragmatic principle I propose that we start with the minimal thing that works for you, and we can make this more generic as other users need. I think we're on the same page here, but let me know if you think we're not :-) |
Hi Roland. I would also like to +1 on this idea, and the proposed suggestions from Martin. One thing to add re:
TL;DR: I think that you should store some identifier in The leaf hash may seem uniquely identifying a leaf, but I can see a couple of duplication issues (depending on whether you use the Merkle leaf hash, or Trillian's concept of "identity hash"):
|
Thanks for the input Pavel. My instinct would be to consider using a CAS for the certificate chains. Essentially, hash the bytes you originally stuck in ExtraData, and that's your key. Store the map of {Hash(chainBytes)->chainBytes} somewhere. If you do have a lot of duplicate chains, then the number of entries in the CAS will be small. When you read a range of certs for get-entries, you only need to do a lookup for the unique chains. |
Sounds good, we (Let's Encrypt) are definitely interested in seeing this get done, so are likely to spend engineering time working on it at some point in the near future. All of your feedback makes sense, I think the one main question I have is if we'd want to design this as a generic interface with a MySQL implementation (similarly to how trillian has the LogStorage interface, and then a handful of implementations) or just dive straight in with a MySQL implementation and call it a day (for now anyway)? |
For my part, I would recommend the latter (dive straight into whatever backend you're intending to use). First, it's difficult to craft an interface around a single implementation, and second, there's little to be gained (in fact, usually leading to premature generalisation). We can refactor later, especially if there's no interface that need to be maintained. |
Thanks @rolandshoemaker for the initiative. Here are the requirements and proposal. Requirements
ProposalTrillian
|
The pull requests to deduplicate the issuance chain in extra data are all merged. |
This is an extended version of google/trillian#1968 with more concrete numbers (and probably in the right place this time).
Currently ctfe sends both the leaf certificate and the rest of the chain (intermediates, and root) to trillian for storage. While the leaf is necessary for merkle tree operations (as part of the tree leaf) the rest of the chain is not, and is stored as an opaque blob in ExtraData. Unlike the leaf, which is unique, the chain is mostly made up of duplicated data since the number of possible chains is typically a (relatively) small number, especially when a CA is using a specific log for a hierarchy. Assuming most chains have three entries, a leaf, intermediate, and root, and that certificates are on average around 1.5kb a LeafData row ends up being about 5kb with the chain in ExtraData taking up 3kb of that (ignoring indexes and storage engine overhead).
Pulling this data out of the trillian storage backend would make it possible to more easily deduplicate this data, which would provide a significant storage win, and likely a bit of a performance win because the will be able to store more rows in memory/hot cache if they are smaller, I think the main benefit here would be in sequencing operations, and get-entries type operations.
Some concrete numbers for the oak 2020 Let's Encrypt log: the database for the log is around ~3TB for ~420 million entries. Looking through all the entries in the log the chains, excluding leaves, make up around 1TB of data (again this ignores the database overhead which would add some % to this number) of which only 1.5MB are unique certificates. Deduplicating this would be a ~33% storage win (which is not a insignificant cost).
I think there are two obvious approaches to this, using the ExtraData to store some kind of identifier, or set of identifiers that link to entries in a chain storage backend, or don't store anything in ExtraData and use the leaf identifier hash to as an entry in the chain storage backend to link it to the chain. Either way when the ctfe stored a chain it'd decompose the chain into leaf + rest, and send the rest to the chain storage backend, and then send the leaf to trillian. In the other direction once a leaf or set of leaves is returned the ctfe would then reconstruct the chain by querying the storage backend. The one downside here is that it would increase the number of database queries, i.e. for a get-entries call we currently only need N calls to the trillian database, but with two storage backends you would need N+1, in the best case, or N^2 in the worst depending on query/schema design.
I haven't specified a formal API in this proposal because I want to gauge interest in the overall concept, if there is interest I will try to spend some time coming up with a more concrete proposal.
The text was updated successfully, but these errors were encountered: