-
Notifications
You must be signed in to change notification settings - Fork 74
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
Introduce certificate pool structure and remove multiple encode/decode process #375
Conversation
Hi @arsenalzp. Thanks for your PR. I'm waiting for a cert-manager member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
/ok-to-test |
Let me fix typos! |
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.
Thanks for working on this @arsenalzp! I did a first review pass. Please take a look!
pkg/util/pem.go
Outdated
@@ -121,3 +104,29 @@ func DecodeX509CertificateChainBytes(certBytes []byte) ([]*x509.Certificate, err | |||
|
|||
return certs, nil | |||
} | |||
|
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.
I think the following functions should have CertPool
as receiver. Why not?
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.
Also, we could rename the functions as follows:
- GetSplitPEMBundle -> AsSplitPEMBundle
- GetSplitPEMBundleBytes -> AsPEMBundleBytes
- GetSplitPEMBundleStrings-> AsPEMBundleStrings
- GetCertsList -> AsCertificateList
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.
Functions were renamed.
Regarding CertPool
as argument for DecodeX509CertificateChainBytes().
Let me explain: an idea here is PEM
is responsible for providing prepared data for consumers in form that is needed by consumers, consumers by themself shouldn't know how, where data was taken from, CertPool
is responsible for store, manage, filter, de-duplicate, etc of Certificates
, it provides data for PEM
, so end consumers shouldn't know how CertPool
works inside (encapsulation).
Imagine, we want to provide DER
encoded data instead of PEM
one.
Moreover, I'm thinking about making CertPool
abstract structure (interface).
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.
Regarding CertPool as argument for DecodeX509CertificateChainBytes()
I think Erik was referring to the functions below (AsSplitPEMBundle, AsPEMBundleBytes, AsCertificateList, GetCertificatesQuantity) rather than DecodeX509CertificateChainBytes.
An idea here is
PEM
is responsible for providing prepared data for consumers in form that is needed by consumers, consumers by themself shouldn't know how, where data was taken from, CertPool is responsible for store, manage, filter, de-duplicate, etc of Certificates, it provides data forPEM
, so end consumers shouldn't know how CertPool works inside (encapsulation).
I'm not sure what PEM
refers to. Is it a type that will be created in the future and that, for now, exists through the existence of the AsPEM functions?
Imagine, we want to provide
DER
encoded data instead of PEM one.
I imagine that CertPool would just need to have a couple of receiver functions:
func (*CertPool) AsDER() [][]byte
func (*CertPool) AsPEMBundle() []byte
func (*CertPool) AsPEM() [][]byte
func (*CertPool) Count() int
Why is adding receiver functions a bad idea? I don't see the benefits of encapsulating the "export" (DER or PEM) logic.
Moreover, I'm thinking about making CertPool abstract structure (interface).
What would be the benefits of turning this into an interface? Would that be for testing purposes?
aac3ec6
to
a200310
Compare
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.
I think we are approaching the finish line here, but there are still some "style" comments I would like to see fixed. :-)
pkg/util/pem.go
Outdated
|
||
func GetCertificatesQuantity(certPool *CertPool) int { | ||
return certPool.size() | ||
} |
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.
Why can't we just export the size
function and delete this function?
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.
It would be easy to calculate a size for other kind of storages in the future. As was stated earlier it was done because I wanted to encapsulate the insides of Certificates pool
.
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.
Ok, I don't understand your argument, but this can stay - it's "just" a name. 😉 If you still want to alias the Size
function I think GetCertificateCount
could be a better name.
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.
I wanted to encapsulate the insides of Certificates pool.
Thanks for the clarification.
Can you elaborate on the need for encapsulating CertPool's behavior, and why the count of certificate in the certificate pool shouldn't be exposed?
I don't think that the behaviors "counting certificates", "exporting certificates to a PEM bundle", and "exporting certificates to a slide of DER bytes" need to be encapsulated away. More generally, I'm not convinced that encapsulation will solve anything in this context. I'd love to know more, though!
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.
Hello colleagues,
Behavior of CertPool
should be hidden from its consumers. For example we are going to substitute current CertPool
by one from x509
package or even third-party. As little possibilities to works with CertPool
directly are given to consumers, as little components coupling we have.
From my opinion CertPool
acts like io.Writer
or io.Reader
.
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.
Behavior of
CertPool
should be hidden from its consumers. For example we are going to substitute currentCertPool
by one fromx509
package or even third-party. As little possibilities to works withCertPool
directly are given to consumers, as little components coupling we have. From my opinionCertPool
acts likeio.Writer
orio.Reader
.
This does not make sense to me. Creating util-wrapper functions does not change your stated concern. It just looks very strange to me to have dummy single-statement functions. Making the CertPool
type internal probably makes sense - to allow ourselves more freedom to modify it over time.
@arsenalzp I have a big refactoring incoming: #378. It would be nice to get this PR merged soon. 😉 |
Hello, |
Sure, there is no urgency. I just have some extra time for open source work this week. |
e0e7df7
to
4cb0887
Compare
Done |
pkg/bundle/source.go
Outdated
@@ -99,27 +98,19 @@ func (b *bundle) buildSourceBundle(ctx context.Context, sources []trustapi.Bundl | |||
return bundleData{}, fmt.Errorf("failed to retrieve bundle from source: %w", err) | |||
} | |||
|
|||
opts := util.ValidateAndSanitizeOptions{FilterExpired: b.Options.FilterExpiredCerts} | |||
sanitizedBundle, err := util.ValidateAndSanitizePEMBundleWithOptions([]byte(sourceData), opts) | |||
err = util.ValidateAndSplitPEMBundle(certPool, []byte(sourceData)) |
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.
I find the function name a bit strange when used in this context. It is not evident, at least not to me, that the certs from sourceData
are appended to certPool
.
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.
Yes, I agree with you, we can improve naming. Which suggestions ?
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.
err = util.ValidateAndSplitPEMBundle(certPool, []byte(sourceData)) | |
err = certPool.AppendCertsFromPEM([]byte(sourceData)) |
Similar to https://pkg.go.dev/crypto/x509#CertPool.AppendCertsFromPEM.
In general, let us use functions with CertPool as receiver, and avoid the dummy "utils" wrapper functions. As noted many times already in reviews of this PR. 😸
06316db
to
5cc56c4
Compare
pkg/bundle/source.go
Outdated
@@ -99,27 +98,19 @@ func (b *bundle) buildSourceBundle(ctx context.Context, sources []trustapi.Bundl | |||
return bundleData{}, fmt.Errorf("failed to retrieve bundle from source: %w", err) | |||
} | |||
|
|||
opts := util.ValidateAndSanitizeOptions{FilterExpired: b.Options.FilterExpiredCerts} | |||
sanitizedBundle, err := util.ValidateAndSanitizePEMBundleWithOptions([]byte(sourceData), opts) | |||
err = util.ValidateAndSplitPEMBundle(certPool, []byte(sourceData)) |
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.
err = util.ValidateAndSplitPEMBundle(certPool, []byte(sourceData)) | |
err = certPool.AppendCertsFromPEM([]byte(sourceData)) |
Similar to https://pkg.go.dev/crypto/x509#CertPool.AppendCertsFromPEM.
In general, let us use functions with CertPool as receiver, and avoid the dummy "utils" wrapper functions. As noted many times already in reviews of this PR. 😸
pkg/util/pem.go
Outdated
|
||
func GetCertificatesQuantity(certPool *CertPool) int { | ||
return certPool.size() | ||
} |
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.
Behavior of
CertPool
should be hidden from its consumers. For example we are going to substitute currentCertPool
by one fromx509
package or even third-party. As little possibilities to works withCertPool
directly are given to consumers, as little components coupling we have. From my opinionCertPool
acts likeio.Writer
orio.Reader
.
This does not make sense to me. Creating util-wrapper functions does not change your stated concern. It just looks very strange to me to have dummy single-statement functions. Making the CertPool
type internal probably makes sense - to allow ourselves more freedom to modify it over time.
I didn't want to change code drastically. |
@arsenalzp Do you have the energy to rebase and resolve the current conflicts? Sorry, but we had to get the serious issue merged and released. 😸 |
@erikgb @arsenalzp I rebased the PR and applied the code suggestions. |
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.
Only minor nits/suggestions left. Almost GTM.
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.
/lgtm
Thanks for finishing this @inteon! 🚀
…ng done. Signed-off-by: Oleksandr Krutko <[email protected]>
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: erikgb, inteon The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
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.
/lgtm
This PR introduce certificate pool structure which is mainly used to hold Certificates.
I want to decouple PEM operations from Certificates pool ones.
Deduplication option for certificate pool was also introduced - deduplication process can be optionally disabled.
It is related to #305