grpc-spring icon indicating copy to clipboard operation
grpc-spring copied to clipboard

How to listen on multiple grpc ports

Open alanyusonos opened this issue 3 years ago • 5 comments

The context I am exploring grpc-spring-boot-starter and like to find out how to support 2 ports. For example, I'd like to have 1 port running on 9090 as external port and 9091 as internal port, so that users can have different scope of access to my api. for spring restful, the underlying container, like tomcat or undertow, it can support such multiple ports within 1 spring process.

i searched your doc, but can't find such configuration to allow it. is it doable?

The question

Stacktraces and logs

The application's environment

Which versions do you use?

  • Spring (boot): latest
  • grpc-java:
  • grpc-spring-boot-starter: latest
  • java: version + architecture (64bit?) 1.8
  • Other relevant libraries...

Additional information

  • Did it ever work before?
  • How can we reproduce it?
  • Do you have a demo?

alanyusonos avatar May 12 '22 19:05 alanyusonos

Variant 1 - two ports same handler (both ports can connect to the same services, but they are separated by user/ip/port permissions):

First you need a GrpcServerConfigurer (Docs), there you can add the additional port. (Note: By the default variant is the shaded netty)

You will need something like this to get the actual port the user connected to (probably using a different key): https://github.com/yidongnan/grpc-spring-boot-starter/blob/7ce76713a562c4f8ad907c89d4239eabda32ee7f/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/authentication/SSLContextGrpcAuthenticationReader.java#L45 If your authentication reader does not add any details itself this library will attach the details by default: https://github.com/yidongnan/grpc-spring-boot-starter/blob/7ce76713a562c4f8ad907c89d4239eabda32ee7f/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/interceptors/DefaultAuthenticatingServerInterceptor.java#L104

Your Authenticationmanager/provider must convert these to actual permissions/roles though.

Variant 2 - two ports, separated handlers (the normal server doesn't know about the management services and vice versa):

You have to create two GrpcServerFactories and Lifecycle instances and somewhat control which service is added where. Basically this code just twice:

https://github.com/yidongnan/grpc-spring-boot-starter/blob/7ce76713a562c4f8ad907c89d4239eabda32ee7f/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/autoconfigure/GrpcServerFactoryAutoConfiguration.java#L56-L98

One of them probably with an overwritten port/address method: https://github.com/yidongnan/grpc-spring-boot-starter/blob/7ce76713a562c4f8ad907c89d4239eabda32ee7f/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/serverfactory/ShadedNettyGrpcServerFactory.java#L71

ST-DDT avatar May 12 '22 22:05 ST-DDT

Sorry, I was on vacation and also dragged to other project after back and hence the delay.

Thanks a lot for the response. I tried Variant 1 and able to setup 2 ports. However, I can't get the actual port that the request comes in. I have different apis that i wish to map to different port in order to control usage, like internal users vs external. If coming from a wrong port, i'd simply return an error. How do I prepare ServerCall? via interceptor?

alanyusonos avatar Jun 03 '22 22:06 alanyusonos

However, I can't get the actual port that the request comes in.

You can via: io.grpc.Grpc.TRANSPORT_ATTR_LOCAL_ADDR If you are lucky, these attributes are still available in your authentication instance: https://github.com/yidongnan/grpc-spring-boot-starter/blob/2cc8fa9d9b39dc1093dbcd2a0090b5ef6e075d67/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/interceptors/DefaultAuthenticatingServerInterceptor.java#L104 Then you can use the https://github.com/yidongnan/grpc-spring-boot-starter/blob/2cc8fa9d9b39dc1093dbcd2a0090b5ef6e075d67/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/check/ManualGrpcSecurityMetadataSource.java#L46 and configure the methods according to your needs e.g. set(x, auth -> auth.getUserDetails.get(TRANSPORT_ATTR_LOCAL_ADDR).toString().equals("xyz")) (Not tested)

I also might have found a way to add this feature to this library in the future, but that requires some changes to the AuthorizationCheckingServerInterceptor, AccessPredicates and GrpcSecurityMetadataSource and might take a while to be released. (Basically include the original server call/metadata in the access check)

If not, you have to write your own ServerInterceptor and compare the ServerCall.getAttributes/the actual port with the method descriptor.

ST-DDT avatar Jun 04 '22 00:06 ST-DDT

Hi there, thanks a lot for the suggestions. I took the ServerInterceptor approach and it works. Below is my code

@GrpcGlobalServerInterceptor public class MyInterceptor implements ServerInterceptor {

@Override public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata headers, ServerCallHandler<ReqT, RespT> next)

{ Context ctx = Context.current().; System.out.println("incoming port = " + (InetSocketAddress)serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR)).getPort()); return Contexts.interceptCall(ctx, serverCall, headers, next); } }

alanyusonos avatar Jun 13 '22 04:06 alanyusonos

FYI: I created a PR that grants the developer access to the ServerCall during authorization checks (e.g. the client address): https://github.com/yidongnan/grpc-spring-boot-starter/pull/742 This PR can be considered BREAKING if you use our grpc authorization classes for more than just configuration. If you just use it for simple configuration, then you don't have to change anything.

ST-DDT avatar Sep 13 '22 23:09 ST-DDT

The enhanced security support (for multiple server ports) was added in #742.

ST-DDT avatar Oct 07 '22 10:10 ST-DDT