-
Notifications
You must be signed in to change notification settings - Fork 4.6k
credentials: fix behavior of grpc.WithAuthority and credential handshake precedence #8488
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
Changes from 2 commits
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 |
|---|---|---|
|
|
@@ -96,10 +96,11 @@ func (c CommonAuthInfo) GetCommonAuthInfo() CommonAuthInfo { | |
| return c | ||
| } | ||
|
|
||
| // ProtocolInfo provides information regarding the gRPC wire protocol version, | ||
| // security protocol, security protocol version in use, server name, etc. | ||
| // ProtocolInfo provides static information regarding transport credentials. | ||
| type ProtocolInfo struct { | ||
| // ProtocolVersion is the gRPC wire protocol version. | ||
| // | ||
| // Deprecated: this is unused by gRPC. | ||
| ProtocolVersion string | ||
| // SecurityProtocol is the security protocol in use. | ||
| SecurityProtocol string | ||
|
|
@@ -109,7 +110,16 @@ type ProtocolInfo struct { | |
| // | ||
| // Deprecated: please use Peer.AuthInfo. | ||
| SecurityVersion string | ||
| // ServerName is the user-configured server name. | ||
| // ServerName is the user-configured server name. If set, this overrides | ||
|
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. My first reading of this comment made me think that this is a value that the user can set. But that is not the case. This is a value returned by gRPC to the user. Would it be possible to reword this a little so that it is clear that this only conveys the creds' view of things. 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. I think your initial understanding was correct. This is returned by the credentials implementation and read by gRPC. The user controls how this is set by configuring the credentials directly. |
||
| // the default :authority header used for all RPCs on the channel using the | ||
| // containing credentials, unless grpc.WithAuthority is set on the channel, | ||
| // in which case that setting will take precedence. | ||
| // | ||
| // This must be a valid `:authority` header according to | ||
| // [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2). | ||
| // | ||
| // Deprecated: Users should use grpc.WithAuthority to override the authority | ||
| // on a channel instead of configuring the credentials. | ||
| ServerName string | ||
| } | ||
|
|
||
|
|
@@ -172,13 +182,17 @@ type TransportCredentials interface { | |
| Info() ProtocolInfo | ||
| // Clone makes a copy of this TransportCredentials. | ||
| Clone() TransportCredentials | ||
| // OverrideServerName specifies the value used for the following: | ||
| // - verifying the hostname on the returned certificates | ||
| // - as SNI in the client's handshake to support virtual hosting | ||
| // - as the value for `:authority` header at stream creation time | ||
| // OverrideServerName specifies the value used for the following: - | ||
arjan-bal marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // verifying the hostname on the returned certificates - as SNI in the | ||
| // client's handshake to support virtual hosting - as the value for | ||
| // `:authority` header at stream creation time | ||
| // | ||
| // The provided string should be a valid `:authority` header according to | ||
| // [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2). | ||
| // | ||
| // Deprecated: use grpc.WithAuthority instead. Will be supported | ||
| // throughout 1.x. | ||
| // Deprecated: this method is unused by gRPC. Users should use | ||
| // grpc.WithAuthority to override the authority on a channel instead of | ||
| // configuring the credentials. | ||
| OverrideServerName(string) error | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -110,14 +110,14 @@ func (c tlsCreds) Info() ProtocolInfo { | |||||||||||
| func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) { | ||||||||||||
| // use local cfg to avoid clobbering ServerName if using multiple endpoints | ||||||||||||
| cfg := credinternal.CloneTLSConfig(c.config) | ||||||||||||
| if cfg.ServerName == "" { | ||||||||||||
| serverName, _, err := net.SplitHostPort(authority) | ||||||||||||
| if err != nil { | ||||||||||||
| // If the authority had no host port or if the authority cannot be parsed, use it as-is. | ||||||||||||
| serverName = authority | ||||||||||||
| } | ||||||||||||
| cfg.ServerName = serverName | ||||||||||||
|
|
||||||||||||
|
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. Should we document on the 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. It's not ignored, actually. It's used by the channel in the logic mentioned in the first PR comment, as long as the user didn't manually override the channel's authority. Lines 1810 to 1813 in 9fa3267
Line 106 in 9fa3267
|
||||||||||||
| serverName, _, err := net.SplitHostPort(authority) | ||||||||||||
| if err != nil { | ||||||||||||
| // If the authority had no host port or if the authority cannot be parsed, use it as-is. | ||||||||||||
| serverName = authority | ||||||||||||
| } | ||||||||||||
| cfg.ServerName = serverName | ||||||||||||
|
|
||||||||||||
| conn := tls.Client(rawConn, cfg) | ||||||||||||
| errChannel := make(chan error, 1) | ||||||||||||
| go func() { | ||||||||||||
|
|
@@ -259,9 +259,11 @@ func applyDefaults(c *tls.Config) *tls.Config { | |||||||||||
| // certificates to establish the identity of the client need to be included in | ||||||||||||
| // the credentials (eg: for mTLS), use NewTLS instead, where a complete | ||||||||||||
| // tls.Config can be specified. | ||||||||||||
| // serverNameOverride is for testing only. If set to a non empty string, | ||||||||||||
| // it will override the virtual host name of authority (e.g. :authority header | ||||||||||||
| // field) in requests. | ||||||||||||
| // | ||||||||||||
| // serverNameOverride is for testing only. If set to a non empty string, it will | ||||||||||||
| // override the virtual host name of authority (e.g. :authority header field) in | ||||||||||||
| // requests. Users should use grpc.WithAuthority passed to grpc.NewClient to | ||||||||||||
| // override the authority of the client instead. | ||||||||||||
| func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials { | ||||||||||||
| return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}) | ||||||||||||
| } | ||||||||||||
|
|
@@ -271,9 +273,11 @@ func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) Transpor | |||||||||||
| // certificates to establish the identity of the client need to be included in | ||||||||||||
| // the credentials (eg: for mTLS), use NewTLS instead, where a complete | ||||||||||||
| // tls.Config can be specified. | ||||||||||||
| // serverNameOverride is for testing only. If set to a non empty string, | ||||||||||||
| // it will override the virtual host name of authority (e.g. :authority header | ||||||||||||
| // field) in requests. | ||||||||||||
| // | ||||||||||||
| // serverNameOverride is for testing only. If set to a non empty string, it will | ||||||||||||
| // override the virtual host name of authority (e.g. :authority header field) in | ||||||||||||
| // requests. Users should use grpc.WithAuthority passed to grpc.NewClient to | ||||||||||||
| // override the authority of the client instead. | ||||||||||||
| func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) { | ||||||||||||
| b, err := os.ReadFile(certFile) | ||||||||||||
| if err != 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.
Is this a breaking change? Should this be release noted?
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 a behavior change. Unclear if it's breaking; I would call it a bug fix. I'll mention it in the notes.
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.
Added:
Also, properly percent-encode the port (if needed, which is very unlikely) when the target string omits the hostname and only specifies a port (
grpc.NewClient(":<port-number-or-name>")).