Julien,The gRFC process says that all discussion should happen in this thread, rather than in the PR. So I'll reply to your comments here.
I agree with you that the proxy mapper could set the HTTP CONNECT argument to a server name instead of to an IP address. However, that would not be enough to address the case where the servers' DNS information is not available, at least not in the general case, because the client still needs to know the set of server addresses in order to open the right set of connections to load-balance across.As you and I have discussed, in the specific case where the grpclb load balancing policy is in use, then you could in principle make this work, because the set of server addresses will actually come from the load balancers instead of from the name resolver. However, this would require a number of additional hacks:
- The name resolver would somehow have to know that when you request a load balanced name, it should return the address of the proxy but with the "is_balancer" bit set.
- The proxy mapper would need some way to differentiate between the connections to the load balancers and the connections to the backend servers, so that it could set the HTTP CONNECT argument to the server name for the load balancer connections and to the IP address for the backend server connections.
- The proxy itself would have to know how to resolve the internal name of the load balancers.
And even once all of those hacks are implemented, this approach still only works for the case where the grpclb load balancing policy is in use. If you want to use something like round_robin instead, it won't work at all.
I continue to believe that running a gRPC-level proxy is a better solution for this use-case.
+stubblefield since he expressed interest.Thanks Mark for the reply. Please see inline.Cheers,Julien.On Thu, Jan 19, 2017 at 8:08 AM, Mark D. Roth <ro...@google.com> wrote:Julien,The gRFC process says that all discussion should happen in this thread, rather than in the PR. So I'll reply to your comments here.Ack. Sorry about that.I agree with you that the proxy mapper could set the HTTP CONNECT argument to a server name instead of to an IP address. However, that would not be enough to address the case where the servers' DNS information is not available, at least not in the general case, because the client still needs to know the set of server addresses in order to open the right set of connections to load-balance across.As you and I have discussed, in the specific case where the grpclb load balancing policy is in use, then you could in principle make this work, because the set of server addresses will actually come from the load balancers instead of from the name resolver. However, this would require a number of additional hacks:
- The name resolver would somehow have to know that when you request a load balanced name, it should return the address of the proxy but with the "is_balancer" bit set.
Correct. This can be done using naming convention which is a reasonable thing to do.
- The proxy mapper would need some way to differentiate between the connections to the load balancers and the connections to the backend servers, so that it could set the HTTP CONNECT argument to the server name for the load balancer connections and to the IP address for the backend server connections.
Yes, that is correct. A way to do that is to work hand in hand with the resolver which would set a well known / invalid IP address in case of the balancer connection (e.g. link local address) so that it can be processed as a special case by the proxy mapper. It's not great but it would certainly work.
- The proxy itself would have to know how to resolve the internal name of the load balancers.
Yes, this is totally reasonable and is one of the benefits of using HTTP CONNECT. In fact, we are using that very feature for the http_proxy env var case today.And even once all of those hacks are implemented, this approach still only works for the case where the grpclb load balancing policy is in use. If you want to use something like round_robin instead, it won't work at all.IMO, it is OK. I don't believe that round robin is very useful if you have grpclb at your disposal. If your client is not able to properly resolve names, then round-robin is out of the equation to begin with.I continue to believe that running a gRPC-level proxy is a better solution for this use-case.I agree that this could work. However, this is no silver bullet. Here are some issues I have with this scheme.1. This requires the deployment of a full gRPC proxy in the path as opposed to a more standard HTTP CONNECT proxy.
2. More importantly, it requires the termination of the secure session at the proxy which means that the proxy has to be fully trusted.
3. Even if the proxy is fully trusted, you will need a way to:- carry the whole authentication information of the client from the proxy to the backend (e.g. attributes, restrictions etc...).- depending on your transport security protocol, you may or may not have access to something like Server Name Indication (SNI: https://en.wikipedia.org/wiki/Server_Name_Indication) which would be needed in this kind of deployment.
On Wed, Jan 18, 2017 at 2:18 PM, Julien Boeuf <jbo...@google.com> wrote:Thanks I saw this. I'll comment on the doc.BTW, i'm at an offsite today (and I was yesterday) but this is really high on my priority list.Cheers,Julien.On Wed, Jan 18, 2017 at 2:12 PM, Mark D. Roth <ro...@google.com> wrote:I've created a gRFC describing how HTTP CONNECT proxies will be supported in gRPC:https://github.com/grpc/proposal/pull/4Please keep discussion in this thread. Thanks!----
--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CAAvOVOd%3DXK0Mw1E9L0hnb7Tb5RaDESvVb%3D9S7GE99HfR4w1djg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
3. Even if the proxy is fully trusted, you will need a way to:- carry the whole authentication information of the client from the proxy to the backend (e.g. attributes, restrictions etc...).- depending on your transport security protocol, you may or may not have access to something like Server Name Indication (SNI: https://en.wikipedia.org/wiki/Server_Name_Indication) which would be needed in this kind of deployment.Won't having those capabilities be useful in other scenarios too?I certainly agree that there's some work that needs to be done for the gRPC-level proxy approach. However, it seems like that work would yield a set of tools that would be generally useful in other situations -- in effect, we'd be creating new building blocks that we could compose in different ways in the future to solve other problems. In contrast, the hacks described above that would be necessary to do the work on the gRPC client would only be useful in this particular scenario, and they would actually complicate the existing code instead of providing new building blocks that can be reused later.
I think we are in agreement that either approach could be made to work. However, I think the gRPC-level proxy approach is cleaner and provides more long-term benefit.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CAJgPXp5kLSpNgxx%2BpeSBQZR0fjWvBmFfh4Vre3GeEOM6uufnPA%40mail.gmail.com.
3. Even if the proxy is fully trusted, you will need a way to:- carry the whole authentication information of the client from the proxy to the backend (e.g. attributes, restrictions etc...).- depending on your transport security protocol, you may or may not have access to something like Server Name Indication (SNI: https://en.wikipedia.org/wiki/Server_Name_Indication) which would be needed in this kind of deployment.Won't having those capabilities be useful in other scenarios too?I certainly agree that there's some work that needs to be done for the gRPC-level proxy approach. However, it seems like that work would yield a set of tools that would be generally useful in other situations -- in effect, we'd be creating new building blocks that we could compose in different ways in the future to solve other problems. In contrast, the hacks described above that would be necessary to do the work on the gRPC client would only be useful in this particular scenario, and they would actually complicate the existing code instead of providing new building blocks that can be reused later.For me, the biggest 'hack' is the link-local IP address (or a marker that IP resolution did not work). For the rest, I don't believe that these are hacks. I also believe that the implications on the code are not that bad: the proxy mapper will have to return the parameters for the HTTP CONNECT (which it may have to do anyway if custom headers are needed in the CONNECT request) as opposed to return just a new IP address and let the framework do the HTTP CONNECT.
I think we are in agreement that either approach could be made to work. However, I think the gRPC-level proxy approach is cleaner and provides more long-term benefit.I don't think that these 2 approaches are equivalent in terms for security. While the gRPC-level proxy could be useful, it may not fulfill some security requirements as I tried to explain above. On the other hand, the trust that we put on a TCP-level proxy is much more tunable.
I think we are in agreement that either approach could be made to work. However, I think the gRPC-level proxy approach is cleaner and provides more long-term benefit.I don't think that these 2 approaches are equivalent in terms for security. While the gRPC-level proxy could be useful, it may not fulfill some security requirements as I tried to explain above. On the other hand, the trust that we put on a TCP-level proxy is much more tunable.You're right that there are trade-offs here. I will update the gRFC to document this once we figure out the details of the client-side approach.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CAJgPXp4QVp3Ln0EnWphdQ8cvg53OyUrAD8qBc-GxW%3DR%3DaQUnQA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CAAvOVOeiOz0qyGqY8Z_CnBETto2U%2BFE30Jdy8EuRLh-PuzpoyA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CAAvOVOcvAFuKs9Ua6mipGoM1BkkTVDB5mAakhVRhy6jdCiZvvQ%40mail.gmail.com.
Note that load-balancing within gRPC happens on a per-call basis, not a per-connection basis. Because of this, use of a TCP-level proxy may limit the ability to do load balancing in some environments.
Note that client-side load-balancing within gRPC requires knowing the addresses of the backends. Because of this, use of a TCP-level proxy may limit the ability to do load balacing in some environments.
- *All* requests must go through the proxy, both for internal and external servers.
such as the `http_proxy` environment variable or the Java registry
- For cases 2 and 3, in the subchannel, before we connect to the target address, we will call a new *proxy mapper* hook, which will allow selectively requesting the use of a proxy based on the address to which the subchannel is going to connect.
Note that in case 1, because the client cannot know the set of server addresses, it is impossible to use the normal gRPC per-call load balancing. It *is* possible to do load balancing on a per-connection basis, but that may not spread out the load evenly if different client impose a different amount of load.
In this case, there will be an external name service record for the server name that points to the IP address of the proxy and has the `is_balancer` bit set. (Note: We have not yet designed how that bit will be encoded in DNS, but that will be the subject of a separate gRFC.) The proxy mapper implementation will then have to detect two types of addresses:
- When it sees the proxy address, it will set the HTTP CONNECT argument to the original server name.
The Java implementation is going to have hurdles. I sort of expect issues adhering to the design as precisely as it is defined. I've got to figure out where ProxySelector fits into all of this.
Any references to "load balancing" should say "client-side load balancing".
nit: s/internet/Internet/ (is this really where I'm supposed to make comments like this?)
Note that load-balancing within gRPC happens on a per-call basis, not a per-connection basis. Because of this, use of a TCP-level proxy may limit the ability to do load balancing in some environments.What is that talking about? If the first sentence said "client-side load balancing" I could agree. But I don't understand what that has to do with the second sentence.It seems like this is getting at something different: we can't resolve the multiple backends. How about:Note that client-side load-balancing within gRPC requires knowing the addresses of the backends. Because of this, use of a TCP-level proxy may limit the ability to do load balacing in some environments.
- *All* requests must go through the proxy, both for internal and external servers.This is not true. It only applies to external servers. It directly contradicts the earlier "outbound to the internet." I could maybe agree with it if it said "may" instead of "must."
such as the `http_proxy` environment variable or the Java registryWhat is the Java registry? Do you mean Java system properties?
- For cases 2 and 3, in the subchannel, before we connect to the target address, we will call a new *proxy mapper* hook, which will allow selectively requesting the use of a proxy based on the address to which the subchannel is going to connect.Yeah... that's very C-specific.Could you instead define the requirements, like "before each connection is made, application code can dynamically choose whether to use CONNECT and to which proxy based on the address of the destination?" You then say, "In C core, this could be accomplished by..."
Note that in case 1, because the client cannot know the set of server addresses, it is impossible to use the normal gRPC per-call load balancing. It *is* possible to do load balancing on a per-connection basis, but that may not spread out the load evenly if different client impose a different amount of load.Note that it is possible to use multiple connections through the proxy. And I'm expecting we'll support such a feature for other use-cases. What can't happen is the client guaranteeing each connection goes to a different backend, or using a non-hard-coded number of connections.
In this case, there will be an external name service record for the server name that points to the IP address of the proxy and has the `is_balancer` bit set. (Note: We have not yet designed how that bit will be encoded in DNS, but that will be the subject of a separate gRFC.) The proxy mapper implementation will then have to detect two types of addresses:- When it sees the proxy address, it will set the HTTP CONNECT argument to the original server name.Eww... So it actually changes the end-host. Note that ability is not described earlier in the doc when proxy mapper is introduced. Nor is it made clear here it is an additional feature.
Why isn't the LB just made public? It can be behind some other type of load balancer. That's what I had expected when discussing earlier. Yes, that means there are more auth hurdles, but it seems more sound.
On Wed, Jan 18, 2017 at 2:12 PM, Mark D. Roth <ro...@google.com> wrote:I've created a gRFC describing how HTTP CONNECT proxies will be supported in gRPC:https://github.com/grpc/proposal/pull/4Please keep discussion in this thread. Thanks!--
--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CA%2B4M1oNAAHhp95%2BMwUsVd0rOVv-arQ7_pQsFdaUoHO9mSsTXQg%40mail.gmail.com.
The Java implementation is going to have hurdles. I sort of expect issues adhering to the design as precisely as it is defined. I've got to figure out where ProxySelector fits into all of this.Is this just the concern you've mentioned about how authentication fits in, or is there something more here?
Any references to "load balancing" should say "client-side load balancing".I think that "client-side load balancing" is misleading when talking about grpclb, since the actual load balancing code happens on the balancers instead of on the client. But I do take your point here. I've changed it to use the term "per-call load balancing".
- *All* requests must go through the proxy, both for internal and external servers.This is not true. It only applies to external servers. It directly contradicts the earlier "outbound to the internet." I could maybe agree with it if it said "may" instead of "must."My understanding is that if the http_proxy environment variable is set, then the proxy is used unconditionally for all servers, so I think this is accurate. I've updated the wording in the description of this case to make it clear that this is not just for outbound traffic.
In this case, there will be an external name service record for the server name that points to the IP address of the proxy and has the `is_balancer` bit set. (Note: We have not yet designed how that bit will be encoded in DNS, but that will be the subject of a separate gRFC.) The proxy mapper implementation will then have to detect two types of addresses:- When it sees the proxy address, it will set the HTTP CONNECT argument to the original server name.Eww... So it actually changes the end-host. Note that ability is not described earlier in the doc when proxy mapper is introduced. Nor is it made clear here it is an additional feature.I'm not sure that I completely understand this comment.It's definitely required that we be able to set the argument of the HTTP CONNECT request. Even without case 3, we needed that anyway, because in case 1 we want to use the server name and have the proxy do the name resolution for us, but in case 2 we want to use the IP addresses of the individual backends.
Why isn't the LB just made public? It can be behind some other type of load balancer. That's what I had expected when discussing earlier. Yes, that means there are more auth hurdles, but it seems more sound.If I'm understanding you right, that is essentially what is being proposed here. The idea is that the grpclb balancer is accessed via the HTTP CONNECT proxy.
Why isn't the LB just made public? It can be behind some other type of load balancer. That's what I had expected when discussing earlier. Yes, that means there are more auth hurdles, but it seems more sound.If I'm understanding you right, that is essentially what is being proposed here. The idea is that the grpclb balancer is accessed via the HTTP CONNECT proxy.No. I'm proposing that case 3 is the same as case 2, but with a different server configuration.Case 1 would use the hostname in CONNECT. Case 2 would use IP in CONNECT.If I want Case 2, but don't want to expose internal IP addresses to unauthenticated clients, I'd just make GRPCLB public and connect to it directly, without CONNECT. DNS returns public IPs, and the GRPCLB communication can be authenticated.
On Wed, Jan 25, 2017 at 2:00 PM, Mark D. Roth <ro...@google.com> wrote:The Java implementation is going to have hurdles. I sort of expect issues adhering to the design as precisely as it is defined. I've got to figure out where ProxySelector fits into all of this.Is this just the concern you've mentioned about how authentication fits in, or is there something more here?It wasn't an auth issue. It's more of an issue of needing to work with pre-existing APIs and expectations. We will, for example, be able to support a mixed CONNECT usage in case 1. I wouldn't be surprised if you need to eventually as well. That is what wpad.dat solves, after all.
Any references to "load balancing" should say "client-side load balancing".I think that "client-side load balancing" is misleading when talking about grpclb, since the actual load balancing code happens on the balancers instead of on the client. But I do take your point here. I've changed it to use the term "per-call load balancing".Moving discussion to PR.- *All* requests must go through the proxy, both for internal and external servers.This is not true. It only applies to external servers. It directly contradicts the earlier "outbound to the internet." I could maybe agree with it if it said "may" instead of "must."My understanding is that if the http_proxy environment variable is set, then the proxy is used unconditionally for all servers, so I think this is accurate. I've updated the wording in the description of this case to make it clear that this is not just for outbound traffic.That's conflating two things: the environment and the configuration. Your description of the environment is not true. When in this environment we expect the http_proxy environment variable as the form of configuration, but that has no impact on how the environment actually behaves.
In this case, there will be an external name service record for the server name that points to the IP address of the proxy and has the `is_balancer` bit set. (Note: We have not yet designed how that bit will be encoded in DNS, but that will be the subject of a separate gRFC.) The proxy mapper implementation will then have to detect two types of addresses:- When it sees the proxy address, it will set the HTTP CONNECT argument to the original server name.Eww... So it actually changes the end-host. Note that ability is not described earlier in the doc when proxy mapper is introduced. Nor is it made clear here it is an additional feature.I'm not sure that I completely understand this comment.It's definitely required that we be able to set the argument of the HTTP CONNECT request. Even without case 3, we needed that anyway, because in case 1 we want to use the server name and have the proxy do the name resolution for us, but in case 2 we want to use the IP addresses of the individual backends.I'm not certain there's a fundamental need for special behavior between case 1 and 2 concerning the CONNECT string, but in any case, I don't see why the proxy mapper must do it.
I'd expect the proxy mapper to return one of two things:- no proxy needed- use CONNECT with proxy IP x.x.x.xThat gives the mapper the control it needs without opening the ability to do outrageous things.I think "when it sees the proxy address" also has fundamental issues, like requiring the proxy to have a hard-coded stable IP. That means you couldn't add a new proxy to the rotation if experiencing too much load.More likely, in your scheme, I'd expect the "proxy address" to become 100% fake. "Oh! It's 1.1.1.1! That's our secret code for proxy address."
Why isn't the LB just made public? It can be behind some other type of load balancer. That's what I had expected when discussing earlier. Yes, that means there are more auth hurdles, but it seems more sound.If I'm understanding you right, that is essentially what is being proposed here. The idea is that the grpclb balancer is accessed via the HTTP CONNECT proxy.No. I'm proposing that case 3 is the same as case 2, but with a different server configuration.Case 1 would use the hostname in CONNECT. Case 2 would use IP in CONNECT.If I want Case 2, but don't want to expose internal IP addresses to unauthenticated clients, I'd just make GRPCLB public and connect to it directly, without CONNECT. DNS returns public IPs, and the GRPCLB communication can be authenticated.
--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/CA%2B4M1oN%3DqjqQx9sXWEmwRYjTyw1Z3ZLMfLa%2B_NFRLFof8Jgnxw%40mail.gmail.com.
- *All* requests must go through the proxy, both for internal and external servers.This is not true. It only applies to external servers. It directly contradicts the earlier "outbound to the internet." I could maybe agree with it if it said "may" instead of "must."My understanding is that if the http_proxy environment variable is set, then the proxy is used unconditionally for all servers, so I think this is accurate. I've updated the wording in the description of this case to make it clear that this is not just for outbound traffic.That's conflating two things: the environment and the configuration. Your description of the environment is not true. When in this environment we expect the http_proxy environment variable as the form of configuration, but that has no impact on how the environment actually behaves.What we actually care about here is the configuration, which is that all connections go through the proxy.
but our code doesn't actually care about that; it just cares about what configuration we need to support.
I'm not certain there's a fundamental need for special behavior between case 1 and 2 concerning the CONNECT string, but in any case, I don't see why the proxy mapper must do it.Can you say more about why you think we could use the same CONNECT argument in both cases 1 and 2?
Case 2 is triggered from the proxy mapper, which is why the proxy mapper needs to use this mechanism.
In addition, this allows the proxy mapper to set the CONNECT argument differently for the different situations in case 3.
And more generally, I also think it's a more flexible approach that may allow users to write proxy mappers in the future to do things that we're not thinking of right now.
I'd expect the proxy mapper to return one of two things:- no proxy needed- use CONNECT with proxy IP x.x.x.xThat gives the mapper the control it needs without opening the ability to do outrageous things.I think "when it sees the proxy address" also has fundamental issues, like requiring the proxy to have a hard-coded stable IP. That means you couldn't add a new proxy to the rotation if experiencing too much load.More likely, in your scheme, I'd expect the "proxy address" to become 100% fake. "Oh! It's 1.1.1.1! That's our secret code for proxy address."We discussed the possibility of using a sentinel address value like this, but I think that's really ugly. Using the proxy address seems cleaner, especially since the client needs to know what proxy address to use anyway in order to return that value from the proxy mapper.
I think "when it sees the proxy address" also has fundamental issues, like requiring the proxy to have a hard-coded stable IP. That means you couldn't add a new proxy to the rotation if experiencing too much load.More likely, in your scheme, I'd expect the "proxy address" to become 100% fake. "Oh! It's 1.1.1.1! That's our secret code for proxy address."The main issue here I think, as you pointed out, is that naming and the mapper need to agree on something (e.g. the proxy address or a sentinel address as in your example) and this is not great. On the other hand, it allows us to support cases where the name of the LB (or direct backend connection in non-LB case) cannot be really resolved on the client but can be resolved on the proxy. This is a really nice feature of HTTP CONNECT so I'm willing to live with it.
If I want Case 2, but don't want to expose internal IP addresses to unauthenticated clients, I'd just make GRPCLB public and connect to it directly, without CONNECT. DNS returns public IPs, and the GRPCLB communication can be authenticated.I don't think that this would pass some security/deployment requirements (certainly not ours) as it would force the load balancer to run within the client's security zone boundary.
On Thu, Jan 26, 2017 at 8:42 AM, 'Mark D. Roth' via grpc.io <grp...@googlegroups.com> wrote:- *All* requests must go through the proxy, both for internal and external servers.This is not true. It only applies to external servers. It directly contradicts the earlier "outbound to the internet." I could maybe agree with it if it said "may" instead of "must."My understanding is that if the http_proxy environment variable is set, then the proxy is used unconditionally for all servers, so I think this is accurate. I've updated the wording in the description of this case to make it clear that this is not just for outbound traffic.That's conflating two things: the environment and the configuration. Your description of the environment is not true. When in this environment we expect the http_proxy environment variable as the form of configuration, but that has no impact on how the environment actually behaves.What we actually care about here is the configuration, which is that all connections go through the proxy.But... that's not what it says. It says, "We are aware of the following use-cases for TCP-level proxying with gRPC" and then follows with "A corp environment where all traffic (especially traffic outbound to the Internet) must go through a proxy." I'm not aware of that use-case/environment.As I said though, if you soften "must" to "may", I could get behind it. Otherwise I'm not aware of Case 1 existing at all in the world, so let's not support it.Really though, I'm not sure how often the proxies are unable to load internal resources. And even if they are able to, the solution isn't probably going to be satisfactory for users, because performance. If it were me I'd frame it where some application only needs to access external resources. http_proxy doesn't solve the mixed case, so let's just call that out up-front.but our code doesn't actually care about that; it just cares about what configuration we need to support.Then delete the use cases and just describe the configuration, if that's all that matters. That is to say, the use cases are important for people, not the code. And the document is for people.I'm harping on this a bit hard because many people don't already understand the use cases.
I'm not certain there's a fundamental need for special behavior between case 1 and 2 concerning the CONNECT string, but in any case, I don't see why the proxy mapper must do it.Can you say more about why you think we could use the same CONNECT argument in both cases 1 and 2?Use a string of what to connect to for CONNECT. Sometimes it contains an IP, sometimes it contains a hostname.
Case 2 is triggered from the proxy mapper, which is why the proxy mapper needs to use this mechanism.I'm not concerned about it using any mechanism. I wanted to reduce its power, which I don't think there should be any argument about whether that is possible.In addition, this allows the proxy mapper to set the CONNECT argument differently for the different situations in case 3.And only case 3 benefits. There is no need application-provided overriding of the CONNECT string in cases 1 and 2. So that's why I was trying to figure out an alternative solution for case 3.
And more generally, I also think it's a more flexible approach that may allow users to write proxy mappers in the future to do things that we're not thinking of right now."more flexible approach" != "better". Does it not concern you that the proxy mapper may completely replace the decision of the name resolver? That could make for a painful debugging session. I'm fine with it tweaking the results, but in no way do I see complete overriding to be a good thing inherently. If we have to do it, so be it, but it's an anti-feature if we support it unnecessarily.
I'd expect the proxy mapper to return one of two things:- no proxy needed- use CONNECT with proxy IP x.x.x.xThat gives the mapper the control it needs without opening the ability to do outrageous things.I think "when it sees the proxy address" also has fundamental issues, like requiring the proxy to have a hard-coded stable IP. That means you couldn't add a new proxy to the rotation if experiencing too much load.More likely, in your scheme, I'd expect the "proxy address" to become 100% fake. "Oh! It's 1.1.1.1! That's our secret code for proxy address."We discussed the possibility of using a sentinel address value like this, but I think that's really ugly. Using the proxy address seems cleaner, especially since the client needs to know what proxy address to use anyway in order to return that value from the proxy mapper.But you didn't address my concerns that the mapping code doesn't actually know the proxy addresses, unless it never changes. But if it never changes then you have stability issues.
I've attempted to modify the language in the doc to make it clear that the intent is for outbound traffic to go through the proxy, but that this is often implemented by having all traffic go through the proxy. Please let me know if this addresses your concern.
Let me try to make sure I'm understanding you right here. It sounds like you're suggesting that instead of giving the proxy mapper the ability to control whether the CONNECT argument is a hostname or an IP address, we instead always assume that we should use the IP address in the CONNECT request whenever use of a proxy is indicated by a proxy mapper. In other words, we would determine the CONNECT argument based on where the use of the proxy was triggered (i.e., from the client channel code vs. from a proxy mapper) instead of having the proxy mapper explicitly control it. Is that right?
But that philosophical debate aside, I think that we should focus on case 3, because that's a concrete case that we do want to support. So far, at least, I have not heard a workable proposal that does not require the proxy mapper to control the CONNECT argument (although I'm certainly still open to new proposals).
I can think of one possible middle-ground approach here, which is that instead of having the proxy mapper specify the CONNECT argument string, it just indicates whether the argument should be the original hostname or the IP address returned by the resolver. That way, it can control what it needs to but can't completely override the results of the resolver. I'm not super enthusiastic about this approach, since it seems like it actually makes the interface a bit harder to understand, but I'm curious what you think of it.
But you didn't address my concerns that the mapping code doesn't actually know the proxy addresses, unless it never changes. But if it never changes then you have stability issues.
The whole point of the proxy mapper is to provide a hook for the logic that knows what proxy address to use. It has to have some source of that data, whether it be hard-coded or read from a file or something else entirely.
On Thu, Jan 26, 2017 at 12:46 PM, Mark D. Roth <ro...@google.com> wrote:I've attempted to modify the language in the doc to make it clear that the intent is for outbound traffic to go through the proxy, but that this is often implemented by having all traffic go through the proxy. Please let me know if this addresses your concern.The modification looks great.Let me try to make sure I'm understanding you right here. It sounds like you're suggesting that instead of giving the proxy mapper the ability to control whether the CONNECT argument is a hostname or an IP address, we instead always assume that we should use the IP address in the CONNECT request whenever use of a proxy is indicated by a proxy mapper. In other words, we would determine the CONNECT argument based on where the use of the proxy was triggered (i.e., from the client channel code vs. from a proxy mapper) instead of having the proxy mapper explicitly control it. Is that right?Yes. And that seems to agree with how the different proxy choosing logic will work; the first primarily consumes hostnames and returns proxy hostnames (which is http_proxy in C) and the second one primarily consumes IPs and returns proxy IPs.
But that philosophical debate aside, I think that we should focus on case 3, because that's a concrete case that we do want to support. So far, at least, I have not heard a workable proposal that does not require the proxy mapper to control the CONNECT argument (although I'm certainly still open to new proposals).I've provided two proposals. Neither of which seem debunked as of yet. I could totally agree they may be worse than what you are proposing, but the discussion hasn't gotten to that point. The mentioned security issue of the first proposal seemed to ignore the fact that a reverse proxy could be used to "protect" the LB, in an identical fashion to any forward proxy.
I can think of one possible middle-ground approach here, which is that instead of having the proxy mapper specify the CONNECT argument string, it just indicates whether the argument should be the original hostname or the IP address returned by the resolver. That way, it can control what it needs to but can't completely override the results of the resolver. I'm not super enthusiastic about this approach, since it seems like it actually makes the interface a bit harder to understand, but I'm curious what you think of it.Meh. It still requires coupling the proxy mapper with other parts of the system. And I'm not convinced that coupling works. It does make me feel a bit better about the predictability of the system though. And that is important to have an orthogonal system which helps as you try to add more features/refactor.
But you didn't address my concerns that the mapping code doesn't actually know the proxy addresses, unless it never changes. But if it never changes then you have stability issues.
The whole point of the proxy mapper is to provide a hook for the logic that knows what proxy address to use. It has to have some source of that data, whether it be hard-coded or read from a file or something else entirely.It has to provide an address. It doesn't have to have global knowledge of all possible addresses, which are even coming from a separate system. Will the two different systems be updated in concert, which may need to be simultaneously/atomically? Seems unlikely, in part because it is non-obvious they need to be. But let's say they do.
Then we also have to deal with configuration changes during the time the name resolver runs and the proxy mapper runs. This is asking for bugs. The design is brittle and feels like it requires different parts of the system to be tied together with duct tape.
If you assume "one proxy" which has "one static IP" and everything is hard-coded, then the design is fine. But that seems unlikely to describe a productionized system. And that's why I would feel forced to use the "magic IP" that it seems you have previously rejected.
Yes. And that seems to agree with how the different proxy choosing logic will work; the first primarily consumes hostnames and returns proxy hostnames (which is http_proxy in C) and the second one primarily consumes IPs and returns proxy IPs.I don't think that's actually entirely correct. The first case doesn't consume anything; it unconditionally sets the hostname to be resolved.
And the second case can consume either the hostname or the IP.
This is more philosophical than practical,
But that philosophical debate aside, I think that we should focus on case 3, because that's a concrete case that we do want to support. So far, at least, I have not heard a workable proposal that does not require the proxy mapper to control the CONNECT argument (although I'm certainly still open to new proposals).I've provided two proposals. Neither of which seem debunked as of yet. I could totally agree they may be worse than what you are proposing, but the discussion hasn't gotten to that point. The mentioned security issue of the first proposal seemed to ignore the fact that a reverse proxy could be used to "protect" the LB, in an identical fashion to any forward proxy.I don't quite understand the proposed reverse proxy approach. Can you explain how that would work in more detail?
I agree that case 3 requires different parts of the system to be coordinated. For example, assuming that your proxy mapper implementation is getting the list of proxy addresses from a local file, you would need to first push an updated list that contains the new proxy address to all clients. Then, once all clients have been updated, you can add the new proxy to DNS.
I agree that this is cumbersome, but I think it's an inherent problem with case 3, because you need some way to configure the clients.
If you assume "one proxy" which has "one static IP" and everything is hard-coded, then the design is fine. But that seems unlikely to describe a productionized system. And that's why I would feel forced to use the "magic IP" that it seems you have previously rejected.
There are a couple of reasons that I don't like the "magic IP" approach. First, it requires writing a custom resolver in addition to a custom proxy mapper,
I'm not a big fan of "sentinel" values, since it's often hard to find a value that will never be used in real life.
On Fri, Jan 27, 2017 at 12:16 PM, 'Mark D. Roth' via grpc.io <grp...@googlegroups.com> wrote:Yes. And that seems to agree with how the different proxy choosing logic will work; the first primarily consumes hostnames and returns proxy hostnames (which is http_proxy in C) and the second one primarily consumes IPs and returns proxy IPs.I don't think that's actually entirely correct. The first case doesn't consume anything; it unconditionally sets the hostname to be resolved.The first case will consume a hostname in Java. Observing the hostname is necessary to fix the mixed internal/external in an expanded view of case 1. Since the Java APIs support that mixed case, Java ends up needing to support them. And if C ever needed to support the mixed case (which seems likely to me), then it would also need to use the hostname.And the second case can consume either the hostname or the IP.And I wouldn't be surprised if only IP were used. We're not aware of a user of it.This is more philosophical than practical,My further explanation there was meant to be more philosophical, as an explanation that this "special case" is pretty normal and sort of agrees with the rest of the design.But that philosophical debate aside, I think that we should focus on case 3, because that's a concrete case that we do want to support. So far, at least, I have not heard a workable proposal that does not require the proxy mapper to control the CONNECT argument (although I'm certainly still open to new proposals).I've provided two proposals. Neither of which seem debunked as of yet. I could totally agree they may be worse than what you are proposing, but the discussion hasn't gotten to that point. The mentioned security issue of the first proposal seemed to ignore the fact that a reverse proxy could be used to "protect" the LB, in an identical fashion to any forward proxy.I don't quite understand the proposed reverse proxy approach. Can you explain how that would work in more detail?Case 3 as stated today (for contrasting)
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do a DNS resolution for lb.example.com, get IP 1.2.3.4
- ask the proxy mapper about IP 1.2.3.4, it recognizes the IP as the proxy and says to use "CONNECT service.example.com" via proxy IP 1.2.3.4
- connect to proxy 1.2.3.4, it performs internal resolution of service.example.com and connects to one of the hosts
Case 3 using reverse proxy for LB
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do a DNS resolution for lb.example.com, get IP 1.2.3.4
- (different starting here) connect to 1.2.3.4, which is a transparent reverse proxy
- Perform an RPC to 1.2.3.4. Host header is lb.example.com. The proxy performs internal mapping of lb.example.com to internal addresses and connects to one of the hosts, forwarding the RPC.
I agree that case 3 requires different parts of the system to be coordinated. For example, assuming that your proxy mapper implementation is getting the list of proxy addresses from a local file, you would need to first push an updated list that contains the new proxy address to all clients. Then, once all clients have been updated, you can add the new proxy to DNS.And the file needs to contain old proxy addresses that should be used for detection but not be used.Okay. So we're on the same page there.I agree that this is cumbersome, but I think it's an inherent problem with case 3, because you need some way to configure the clients.I agree you need to be able to configure the clients. I understand that something needs to tell the client what to do. My concern was the pain of updating the proxy mapping list in concert with name resolution. And because of that I would recommend implementors to use the magic IP, because it has less operational overhead and less likelihood of failing.If you assume "one proxy" which has "one static IP" and everything is hard-coded, then the design is fine. But that seems unlikely to describe a productionized system. And that's why I would feel forced to use the "magic IP" that it seems you have previously rejected.
There are a couple of reasons that I don't like the "magic IP" approach. First, it requires writing a custom resolver in addition to a custom proxy mapper,No, I'd just have DNS return the trash IP.
I'm not a big fan of "sentinel" values, since it's often hard to find a value that will never be used in real life.I would gladly accept a magic value instead of needing to make sure two systems stay in sync and rollouts happen properly. And I would quickly recommend that to others. And if I started explaining the gotchas of the alternative, I'd expect them to quickly be thankful for the recommendation since it is less code to write and less operational complexity.
On Fri, Jan 27, 2017 at 1:31 PM, Eric Anderson <ej...@google.com> wrote:Case 3 as stated today (for contrasting)
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do a DNS resolution for lb.example.com, get IP 1.2.3.4
- ask the proxy mapper about IP 1.2.3.4, it recognizes the IP as the proxy and says to use "CONNECT service.example.com" via proxy IP 1.2.3.4
- connect to proxy 1.2.3.4, it performs internal resolution of service.example.com and connects to one of the hosts
That's not actually an accurate representation of how case 3 is proposed to work in the current document.
Just thinking out loud here about whether there's another alternative -- this is a purely brainstorming-level idea, so please feel free to shoot holes in it. What if we had another type of SRV record specifically for HTTP CONNECT proxy use?
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do DNS SRV resolution for _grpc_proxy._tcp.lb.example.com; you find it is a proxy with name proxy.example.com
On Fri, Jan 27, 2017 at 3:41 PM, Mark D. Roth <ro...@google.com> wrote:On Fri, Jan 27, 2017 at 1:31 PM, Eric Anderson <ej...@google.com> wrote:Case 3 as stated today (for contrasting)
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do a DNS resolution for lb.example.com, get IP 1.2.3.4
- ask the proxy mapper about IP 1.2.3.4, it recognizes the IP as the proxy and says to use "CONNECT service.example.com" via proxy IP 1.2.3.4
- connect to proxy 1.2.3.4, it performs internal resolution of service.example.com and connects to one of the hosts
That's not actually an accurate representation of how case 3 is proposed to work in the current document.Oh, sorry. #4 and 5 should have used lb.example.com instead of service.example.com. That seems to be the only changes you made.
Just thinking out loud here about whether there's another alternative -- this is a purely brainstorming-level idea, so please feel free to shoot holes in it. What if we had another type of SRV record specifically for HTTP CONNECT proxy use?I considered something of that ilk, but wasn't very excited. I do agree it could work. I don't think we want a separate SRV for it, because that means another lookup for all clients for this one rare case.But maybe we could shoe-horn it somewhere. Like service config. Probably icky.This does have the advantage that it can be rolled out seemlessly, without an update to the client.
- client wants to connect to service.example.com
- do DNS SRV resolution for _grpclb._tcp.service.example.com; you find it is a LB with name lb.example.com
- do DNS SRV resolution for _grpc_proxy._tcp.lb.example.com; you find it is a proxy with name proxy.example.com
Whoa. So do a SRV for the LB. I didn't quite expect that as it goes a bit against normal SRV, but it makes sense. It's interesting. Again, for reasons above, I don't think we want to go with this, but it does seem like it could work.
Keep in mind that in case 3, the grpclb load balancers and the server backends are in the same internal domain, with the same access restrictions. If we can't use a reverse proxy to access the server backends, I don't think we'll be able to do that for the grpclb balancers either.That having been said, as a security issue, Julien can address this directly.I agree: we don't want clients to be able to hit the load balancers (or the backends) before the proxy has a chance to filter things like source IP address and/or traffic inspection. You could argue that the transparent proxy could perform these functions, however this would mean that:- we have now 2 proxies that perform the same function.
- it is not possible to signal anything with regards to the shape of the traffic from the client to the transparent reverse proxy since there is no HTTP CONNECT request. This makes traffic inspection very difficult as it has to rely on heuristics as opposed to clear and unambiguous signalling.
So I think this leaves us with the current design.
Do we know that there are cases where we'll need to support this? I don't doubt that there are cases where only connections to external servers should go through the proxy, but I wonder how many cases there are where users will need to use both internal and external servers with gRPC.
If/when we do support this, do we have some idea how this would be configured? Is there some standard way of configuring which server names are internal vs. which are external, or would it be custom code for each environment?
I've created a gRFC describing how HTTP CONNECT proxies will be supported in gRPC:https://github.com/grpc/proposal/pull/4
Please keep discussion in this thread. Thanks!
--
--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+unsubscribe@googlegroups.com.
To post to this group, send email to grp...@googlegroups.com.
Visit this group at https://groups.google.com/group/grpc-io.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/7140d6ee-cfbb-4238-8844-889d2af19e4a%40googlegroups.com.