Skip to content
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

xds: server-side security: server integration #4092

Merged
merged 7 commits into from
Dec 16, 2020

Conversation

easwars
Copy link
Contributor

@easwars easwars commented Dec 9, 2020

Summary of changes:

  • Add security integration to xds.GRPCServer:
    • Retrieve configured transport credentials from the underlying grpc.Server
    • Handle security configuration in received Listener resource
      • create appropriate certificate providers
      • setup HandshakeInfo to be passed to xds.Credentials
      • wrap the underlying net.Conn
        • support for setting and getting deadline
        • support for retrieving the HandshakeInfo
  • e2e test which exercises xDS security with a file watcher plugin.
  • A way to retrieve the transport credentials configured on a grpc.Server through the internal package.

@easwars
Copy link
Contributor Author

easwars commented Dec 14, 2020

@dfawley : This is now ready to be looked at. Thanks.

// GetServerCredentials returns the transport credentials configured on a
// gRPC server. An xDS-enabled server needs to know what type of credentials
// is configured on the underlying gRPC server. This is set by server.go.
GetServerCredentials interface{} // func (s interface{}) *credentials.TransportCredentials
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not func (s *grpc.Server) ...?

Also it seems the convention is mostly to not give names to the parameters, just list their types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot have this package depend on the grpc package, right. That would lead to a cyclic dependency.

Removed the parameter names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was referring to the comment. The type would still be interface{}

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this xds going to be redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention seems to be that we add the component prefix to errors that we generate. The same or closely related prefix might also get added by the prefix logger if the returned error is logged at some point. I still haven't looked at any real logs to see how useful/bad these prefixes are getting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a convention we should have, unless the error is leaving the xds component. Let's be careful about these so our logs are clear and not cluttered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I leave it as-is for now? We should probably discuss this and come up with a convention that we can follow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the pushback. If we're producing an error solely to log it later, it's equivalent to directly writing:

logger.Warning("Error doing whatever: xds: couldn't do that thing")

...which would result in the output:

[xds] [xds-server 0xf34a89d] Error doing whatever: xds: couldn't do that thing

...which has "xds" in it 3 times!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the xds prefix from the errors returned from here.

I didn't mean to pushback on the change you are suggesting here. I'm only saying that this is widespread and that we should talk about it and decide how we want to go about structuring error messages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all in favor of discussing and fixing the other areas! But I think we should not make things worse in the meantime.

Copy link
Contributor Author

@easwars easwars left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. PTAL.

// GetServerCredentials returns the transport credentials configured on a
// gRPC server. An xDS-enabled server needs to know what type of credentials
// is configured on the underlying gRPC server. This is set by server.go.
GetServerCredentials interface{} // func (s interface{}) *credentials.TransportCredentials
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot have this package depend on the grpc package, right. That would lead to a cyclic dependency.

Removed the parameter names.

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention seems to be that we add the component prefix to errors that we generate. The same or closely related prefix might also get added by the prefix logger if the returned error is logged at some point. I still haven't looked at any real logs to see how useful/bad these prefixes are getting.

@easwars easwars assigned dfawley and unassigned dfawley Dec 15, 2020
// GetServerCredentials returns the transport credentials configured on a
// gRPC server. An xDS-enabled server needs to know what type of credentials
// is configured on the underlying gRPC server. This is set by server.go.
GetServerCredentials interface{} // func (s interface{}) *credentials.TransportCredentials
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was referring to the comment. The type would still be interface{}

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a convention we should have, unless the error is leaving the xds component. Let's be careful about these so our logs are clear and not cluttered.

@dfawley dfawley assigned easwars and unassigned dfawley Dec 16, 2020
@easwars
Copy link
Contributor Author

easwars commented Dec 16, 2020

Had to rebase because of a merge conflict and the comments are now all over the place :(

@easwars
Copy link
Contributor Author

easwars commented Dec 16, 2020

For comments where I'm not able to reply inline:

  • Added the bc == nil check back
  • As for polluting the logs with our prefixes: can I leave it as-is for now. We should discuss this and come to a consensus on what would be the best strategy forward. It might require some wholesale changes
  • As for the type in the comment in the internal package: server.go which implements internal.GetServerCredentials accepts an interface{} and not a *grpc.Server. It then goes ahead and type asserts to a *grpc.Server. I did this so that tests which fake out the underlying grpc.Server will continue to work without extensive changes. Let me know if you still want me to change the type in the comment.

Thanks.

@@ -64,7 +64,7 @@ var (
// GetServerCredentials returns the transport credentials configured on a
// gRPC server. An xDS-enabled server needs to know what type of credentials
// is configured on the underlying gRPC server. This is set by server.go.
GetServerCredentials interface{} // func (interface{}) credentials.TransportCredentials
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're still type asserting this to interface{} so now the comment doesn't match reality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it now.

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the pushback. If we're producing an error solely to log it later, it's equivalent to directly writing:

logger.Warning("Error doing whatever: xds: couldn't do that thing")

...which would result in the output:

[xds] [xds-server 0xf34a89d] Error doing whatever: xds: couldn't do that thing

...which has "xds" in it 3 times!

@dfawley
Copy link
Member

dfawley commented Dec 16, 2020

As for the type in the comment in the internal package: server.go which implements internal.GetServerCredentials accepts an interface{} and not a *grpc.Server. It then goes ahead and type asserts to a *grpc.Server. I did this so that tests which fake out the underlying grpc.Server will continue to work without extensive changes. Let me know if you still want me to change the type in the comment.

Which tests do this?

Copy link
Contributor Author

@easwars easwars left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the type in the comment in the internal package: server.go which implements internal.GetServerCredentials accepts an interface{} and not a *grpc.Server. It then goes ahead and type asserts to a *grpc.Server. I did this so that tests which fake out the underlying grpc.Server will continue to work without extensive changes. Let me know if you still want me to change the type in the comment.

Which tests do this?

Tests in xds/server_test.go use a fakeGRPCServer to make sure that things like Serve(), Stop() etc on the xds.GRPCServer ends up calling the appropriate methods on the grpc.Server.

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the xds prefix from the errors returned from here.

I didn't mean to pushback on the change you are suggesting here. I'm only saying that this is widespread and that we should talk about it and decide how we want to go about structuring error messages.

Copy link
Member

@dfawley dfawley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests in xds/server_test.go use a fakeGRPCServer to make sure that things like Serve(), Stop() etc on the xds.GRPCServer ends up calling the appropriate methods on the grpc.Server.

Okay, I get what's happening now, thanks.

How about if we do the type assertion in the xds code instead, since that's where the interface is used instead of a direct *grpc.Server? It seems like a minor change (it is), but I think it's a little cleaner if the grpc package and its (semi-)exported functions don't have to do type assertions like this.

Also, conceptually, it's more appropriate to determine what to do if the server isn't a *grpc.Server closer to the code that knows what else it might be. E.g., the fake could support this feature as well, but doing the type assertion in grpc makes that harder.

xds/server.go Outdated
// config and makes sure that it is acceptable to the plugin. Still, it
// is possible that the plugin parses the config successfully, but its
// Build() method errors out.
return nil, fmt.Errorf("xds: failed to get security plugin instance (%+v): %v", cfg, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all in favor of discussing and fixing the other areas! But I think we should not make things worse in the meantime.

@easwars
Copy link
Contributor Author

easwars commented Dec 16, 2020

Tests in xds/server_test.go use a fakeGRPCServer to make sure that things like Serve(), Stop() etc on the xds.GRPCServer ends up calling the appropriate methods on the grpc.Server.

Okay, I get what's happening now, thanks.

How about if we do the type assertion in the xds code instead, since that's where the interface is used instead of a direct *grpc.Server? It seems like a minor change (it is), but I think it's a little cleaner if the grpc package and its (semi-)exported functions don't have to do type assertions like this.

Also, conceptually, it's more appropriate to determine what to do if the server isn't a *grpc.Server closer to the code that knows what else it might be. E.g., the fake could support this feature as well, but doing the type assertion in grpc makes that harder.

Makes sense. Moved the type assertion to the xds code. Thanks. It does look cleaner now.

@easwars easwars removed their assignment Dec 16, 2020
Comment on lines +125 to +126
// provides the implementation for internal.GetServerCredentials, and allows
// us to use a fake gRPC server in tests.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future consideration: moving this to a function would allow it to be stubbed for testing:

var usesXDS = func(s *GRPCServer) bool { ... }

in tests:

usesXDS = func(s *GRPCServer) bool { return s.gs.(*fakeGRPCServer).whatever }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

@easwars easwars merged commit 2fad6bf into grpc:master Dec 16, 2020
@easwars easwars deleted the xds_server_creds branch December 16, 2020 18:27
@easwars easwars changed the title xds: Implement server-side security xds: server-side security: server integration Mar 4, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Type: Feature New features or improvements in behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants