Open zamnuts opened 4 years ago
Most of these HTTP CONNECT proxies seem to be used on localhost
. Is that also true of these HTTPS proxies, and if so, how should certificate validation be handled?
A proxy hosted on localhost
sounds like testing. In practice, a proxy will be on a different server.
Certificate validation will be handled using the typical means around root of trust (root certificate in the chain of trust). This root certificate will either be a well-known CA present in the operating system or default truststore, or it will be an internal CA where the root certificate is distributed to the application by augmenting the truststore or included as an override (see tls.createSecureContext
's options.ca
property).
Intermediate certificates should be provided by the endpoint. For example, in a certificate chain with 4 certificates, one will the the leaf, one will be the root, and the other two will be intermediates. The proxy, in this case, will supply at least the leaf and the two intermediates, and optionally the root. If the root is supplied, this must match that which is present in the truststore.
Single certificate chains, i.e. self-signed, may be used during testing, but is insecure in a production environment.
So, in the case where the root certificate is distributed to the application, how should the application provide it to the proxy code? Is there a standard environment variable for doing that?
how should the application provide it to the proxy code?
tls.createSecureContext
's options.ca
property; how it gets it to this library's proxy config is up to the application.SSL_CERT_DIR
or SSL_CERT_FILE
, but requires node be started with the --use-openssl-ca
option; requires the user specify this uncommon option, but nothing special needs to be done in the proxy libI don't think you understand my question. Currently, gRPC's proxy feature is controlled using environment variables. I am asking how this part of the feature should be controlled from a similar perspective. Of course gRPC will have to use that information by passing that argument to tls.createSecureContext
, the question is how gRPC gets the information in the first place. And SSL_CERT_DIR
and SSL_CERT_FILE
are not useful here, because gRPC will still need to be able to establish TLS connections to outside servers through the tunnels established by the proxy servers, so it will still need to use the normal CA file by default.
I understand, but there's no good answer here given the current implementation. There is no conventional CA override for certificates via environment variables, especially in the proxy context. The closest is SSL_CERT_{DIR,FILE}
as mentioned in previous. The only thing I can find on the web that's close is HTTPS_PROXY_CERT
and REQUESTS_CA_BUNDLE
, but this doesn't say whether its a path or the actual PEM-formatted (DER?) contents.
Dependency injection/inversion is the typical route (which is what I was alluding to via tls.createSecureContext
).
By means of the ChannelOptions
in gRPC, see https://github.com/grpc/grpc-node/blob/4db637e543bf69ce7012e34e4aa8fbd623b4e785/packages/grpc-js/src/channel-options.ts#L21-L36
...perhaps the desired signature would yield something similar to:
new routeguide.RouteGuide('localhost:50051', grpc.credentials.createInsecure(), {
proxy: {
proto: 'https',
host: 'proxyhost',
port: 8585,
ca: 'path/to/bundle.crt'
}
});
If there is no standard way of doing that, we can do what we want. Perhaps grpc_proxy_ssl_ca_path
, possibly with an uppercase variant.
@bcoe had mentioned possible prior art with npm
itself in very old versions. I checked 1.x, 2.x and 3.x, as well as its dependencies npm-registry-client
and npmconf
, and couldn't find anything related to a proxy certificate.
I advocate for: grpc_proxy_ca_file
and GRPC_PROXY_CA_FILE
.
This tells us its A) for the proxy, 2) should be a certificate, and 3) a file containing the ca bundle (opposed to a directory) and not the ca contents itself.
I take it you don't want to also support proxy configuration in ChannelOptions
, right?
That environment variable name looks good to me.
I'm not opposed to configuring the proxy with ChannelOptions
, but I'm not yet sure how I want to modify ChannelOptions
in general moving forward. I'd like to have a plan for that before we start diverging from the C core so that we can maintain some level of consistency.
PR #1243 introduced proxy support allowing for gRPC-over-HTTP, i.e. an unencrypted proxy. While gRPC is encrypted by means of HTTP/2, and remains so when tunneled, the initial connection to the proxy is not. See https://github.com/grpc/grpc-node/blob/%40grpc/grpc-js%400.7.0/packages/grpc-js/src/http_proxy.ts#L133-L145
The initial HTTP
CONNECT
call contains two pieces of potentially private/secret data:For these reasons it may be desirable to encrypt the
CONNECT
traffic via HTTPS.Additionally, the current implementation ignores the protocol defined in the proxy configuration (only
PROXY_INFO.address
is used). Whenhttps
is defined, this client will still attempt to connect overhttp
. If the proxy is expecting to negotiate TLS on the defined port (URL.host
), it will error unexpectedly.Solution
Detect the presence of HTTP or HTTPS via
URL.protocol
and make theCONNECT
request accordingly:Alternative
Be explicit about the lack of HTTPS support by both documenting, and detecting the usage of HTTPS and subsequently throwing an informative error.