-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
advancedtls: Rename custom verification function APIs #7140
Conversation
@@ -76,8 +76,8 @@ func main() { | |||
IdentityOptions: advancedtls.IdentityCertificateOptions{ | |||
IdentityProvider: identityProvider, | |||
}, | |||
VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) { | |||
return &advancedtls.VerificationResults{}, nil | |||
VerifyPeer: func(params *advancedtls.HandshakeVerificationInfo) (*advancedtls.PostHandshakeVerificationResults, error) { |
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.
Looking at both 'main.go' examples it looks like 'xOptions' is used more here, so I'm leaning towards 'HandshakeVerificationOptions'
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.
See other comment
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, let's ask Doug to have the final look.
security/advancedtls/advancedtls.go
Outdated
// PostHandshakeVerificationFunc returns nil | ||
// if the authorization fails; otherwise returns an empty struct. |
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 don't understand this.
The convention is that functions reutrn <zero value AKA nil here>, error
or error and _, nil
on success. If nil, nil
is illegal, then that makes the API confusing and hard to use -- in which case you should have it return a value instead of a pointer.
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 returns nil, error
in the case the authorization fails, <currently empty struct>, nil
on success
We discussed and don't think there is harm in keeping the struct even though it's currently unused - there's a good chance it could be in the future and it's already implemented as such
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 - it's a little unusual but should be OK. If that's what you want you should make sure you're panicking if you call it and the function ever returns nil, 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 don't think there's a compelling reason to return a pointer vs. a struct if that is what is making this unclear, but that would represent a breaking behavior change. Looking at it, I don't think nil, nil
is illegal, it just means there's no information to pass back out.
I added some text to the comment to make it a little more clear.
That being said, looking at it again today with fresh eyes, it's called here in our code. And the struct is always thrown away. So I'm rethinking the value of keeping this in the API. Will discuss with my team and add another comment soon.
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 says "otherwise returns an empty struct" which implies that nil, nil
is invalid. If nil, nil
is valid, then you can just delete this part of the documentation. Returning <zero>, error
or _, nil
is just how regular Go conventions always work.
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.
Ah I see, I'll remove that part and then this is resolved? I think that it's more pain that its worth to remove the struct return
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.
SGTM. Maybe PostHandshakeVerificationFunc should return an error if the authorization should fail
or If PostHandshakeVerificationFunc returns an error, authorization fails
or something? (Something a user implements shouldn't be documented as "this is what it does" but "this is what you should make it do" or "this is how the library responds based on what it does".)
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.
Re-worded, PTAL
// verification has been completed. | ||
// PostHandshakeVerificationFunc returns nil | ||
// if the authorization fails; otherwise returns an empty struct. | ||
type PostHandshakeVerificationFunc func(params *HandshakeVerificationInfo) (*PostHandshakeVerificationResults, error) |
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.
Suggestion: PeerVerificationFunc
(and all associated types)? It's a shorter name and (maybe?) is named after the intent of the thing vs. when it happens.
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.
We want to make sure that we are differentiating between verification happening after the normal chain building and verification that happens by default (which this is), and overriding the base chain building and verification itself.
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'm not sure I follow all this.
What is "post handshake verification" exactly? And you're saying this can be used to replace the default behavior? What is the default behavior? Do you have any examples of what users would want to do with this?
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's two main different ways users could desire to customize verification behavior.
During verification we takes the peer's untrusted chain and build a chain from it to a trusted root.
- A user could want to fully replace this chain building behavior (rarer, more difficult use-case that is not supported but might be in the future).
- A user could also just want to do additional checks after the regular default chain building (this is a much more common use-case). We want to preemptively make sure the naming for (2) does not get it confused with (1), as we see them as fully different features with different use cases.
A concrete example of (2) is doing additional check on the hostname of the peer's cert.
A concrete example of (1) would be fully changing the process by which you build a chain to a trusted root using other information, for example SPIFFE IDs.
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.
What's the API for (2)? VerifyPeer
?
So is it the case that if you specify this callback then VerifyPeer
isn't called?
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 the API for (2) is VerifyPeer
. When set it eventually cascades to here -
grpc-go/security/advancedtls/advancedtls.go
Lines 581 to 582 in 34de5cf
if c.verifyFunc != nil { | |
_, err := c.verifyFunc(&VerificationFuncParams{ |
And
VerifyPeer
is of type PostHandshakeVerificationFunc
, I think renaming this option from VerifyPeer
to something more clear is probably belongs in this PR as well
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.
Renamed VerifyPeer
in the settings struct, PTAL
Can you please resolve the conflicts as well? Thanks! |
Fixed merge conflicts, should be all good |
security/advancedtls/advancedtls.go
Outdated
// AdditionalPeerVerification is a custom verification check after certificate signature | ||
// check. | ||
// If this is set, we will perform this customized check after doing the | ||
// normal check(s) indicated by setting VType. |
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.
VType->VerificationType?
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.
Ah I think I lost some in the merge, good catch
security/advancedtls/advancedtls.go
Outdated
// AdditionalPeerVerification is a custom verification check after certificate signature | ||
// check. | ||
// If this is set, we will perform this customized check after doing the | ||
// normal check(s) indicated by setting VType. |
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.
VerificationType
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.
Good catch
// TODO(gtcooke94) Remove this block when remove o.VerifyPeer | ||
// Set AdditionalPeerVerification if the user is still using VerifyPeer. | ||
if o.VerifyPeer != nil { | ||
o.AdditionalPeerVerification = o.VerifyPeer |
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.
if o.AdditionalPeerVerification != nil { return <err> }
?
Or ignore the old deprecated field VerifyPeer
instead by reversing it:
if o.AdditionalPeerVerification == nil {
o.AdditionalPeerVerification = o.VerifyPeer
}
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's not required, so the error return I think doesn't make the most sense.
The reverse works too, I guess it just matters for the precedence - I was going with "if the old field is set they probably haven't migrated", but the bottom is good too as a "if the new field isn't set take whatever is in the old field"
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.
The error would be "you set two fields that mean the same thing, one of which is deprecated: what were you thinking?" 😆
This change renames the APIs for injecting a custom verification function such that the names are clearer that it is occurs post-handshake with already built chains and does not replace the base chain building and chain verification that the underlying security library does.
I've left type aliases to the old names and marked them as deprecated.
(To add to release notes? - In advancedtls, change
CustomVerificationFunc
toPostHandshakeVerificationFunc
,VerificationFuncParams
toHandshakeVerificationInfo
, andVerificationResults
toPostHandshakeVerificationResults
.)RELEASE NOTES: none