mirror of https://github.com/grpc/grpc-java.git
SECURITY.md: Update/modernize docs
There's still plenty more that could be done, but I want to keep this on the simpler/less-invasive side and it'd just delay these changes for no real benefit.
This commit is contained in:
parent
3c89aa191b
commit
8aa25476e9
139
SECURITY.md
139
SECURITY.md
|
|
@ -1,10 +1,16 @@
|
||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).
|
For information on gRPC Security Policy and reporting potentional security
|
||||||
|
issues, please see [gRPC CVE Process][].
|
||||||
|
|
||||||
|
[gRPC CVE Process]: https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md
|
||||||
|
|
||||||
# Authentication
|
# Authentication
|
||||||
|
|
||||||
gRPC supports a number of different mechanisms for asserting identity between an client and server. This document provides code samples demonstrating how to provide SSL/TLS encryption support and identity assertions in Java, as well as passing OAuth2 tokens to services that support it.
|
gRPC supports a number of different mechanisms for asserting identity between an
|
||||||
|
client and server. This document provides code samples demonstrating how to
|
||||||
|
provide SSL/TLS encryption support and identity assertions in Java, as well as
|
||||||
|
passing OAuth2 tokens to services that support it.
|
||||||
|
|
||||||
# Transport Security (TLS)
|
# Transport Security (TLS)
|
||||||
|
|
||||||
|
|
@ -19,25 +25,28 @@ BoringSSL](#tls-with-netty-tcnative-on-boringssl).
|
||||||
## TLS on Android
|
## TLS on Android
|
||||||
|
|
||||||
On Android we recommend the use of the [Play Services Dynamic Security
|
On Android we recommend the use of the [Play Services Dynamic Security
|
||||||
Provider](https://www.appfoundry.be/blog/2014/11/18/Google-Play-Services-Dynamic-Security-Provider/)
|
Provider][] to ensure your application has an up-to-date OpenSSL library with
|
||||||
to ensure your application has an up-to-date OpenSSL library with the necessary
|
the necessary cipher-suites and a reliable ALPN implementation. This requires
|
||||||
cipher-suites and a reliable ALPN implementation. This requires [updating the
|
[updating the security provider at runtime][config-psdsp].
|
||||||
security provider at
|
|
||||||
runtime](https://developer.android.com/training/articles/security-gms-provider.html).
|
|
||||||
|
|
||||||
Although ALPN mostly works on newer Android releases (especially since 5.0),
|
Although ALPN mostly works on newer Android releases (especially since 5.0),
|
||||||
there are bugs and discovered security vulnerabilities that are only fixed by
|
there are bugs and discovered security vulnerabilities that are only fixed by
|
||||||
upgrading the security provider. Thus, we recommend using the Play Service
|
upgrading the security provider. Thus, we recommend using the Play Service
|
||||||
Dynamic Security Provider for all Android versions.
|
Dynamic Security Provider for all Android versions.
|
||||||
|
|
||||||
*Note: The Dynamic Security Provider must be installed **before** creating a gRPC OkHttp channel. gRPC's OkHttpProtocolNegotiator statically initializes the security protocol(s) available to gRPC, which means that changes to the security provider after the first channel is created will not be picked up by gRPC.*
|
*Note: The Dynamic Security Provider must be installed **before** creating a
|
||||||
|
gRPC OkHttp channel. gRPC statically initializes the security protocol(s)
|
||||||
|
available, which means that changes to the security provider after the first
|
||||||
|
channel is created will not be noticed by gRPC.*
|
||||||
|
|
||||||
|
[Play Services Dynamic Security Provider]: https://www.appfoundry.be/blog/2014/11/18/Google-Play-Services-Dynamic-Security-Provider/
|
||||||
|
[config-psdsp]: https://developer.android.com/training/articles/security-gms-provider.html
|
||||||
|
|
||||||
### Bundling Conscrypt
|
### Bundling Conscrypt
|
||||||
|
|
||||||
If depending on Play Services is not an option for your app, then you may bundle
|
If depending on Play Services is not an option for your app, then you may bundle
|
||||||
[Conscrypt](https://conscrypt.org) with your application. Binaries are available
|
[Conscrypt](https://conscrypt.org) with your application. Binaries are available
|
||||||
on [Maven
|
on [Maven Central][conscrypt-maven].
|
||||||
Central](https://search.maven.org/#search%7Cga%7C1%7Cg%3Aorg.conscrypt%20a%3Aconscrypt-android).
|
|
||||||
|
|
||||||
Like the Play Services Dynamic Security Provider, you must still "install"
|
Like the Play Services Dynamic Security Provider, you must still "install"
|
||||||
Conscrypt before use.
|
Conscrypt before use.
|
||||||
|
|
@ -50,10 +59,12 @@ import java.security.Security;
|
||||||
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[conscrypt-maven]: https://search.maven.org/#search%7Cga%7C1%7Cg%3Aorg.conscrypt%20a%3Aconscrypt-android
|
||||||
|
|
||||||
## TLS on non-Android
|
## TLS on non-Android
|
||||||
|
|
||||||
JDK versions prior to Java 9 do not support ALPN and are either missing AES GCM
|
OpenJDK versions prior to Java 8u252 do not support ALPN. Java 8 has 10% the
|
||||||
support or have 2% the performance of OpenSSL.
|
performance of OpenSSL.
|
||||||
|
|
||||||
We recommend most users use grpc-netty-shaded, which includes netty-tcnative on
|
We recommend most users use grpc-netty-shaded, which includes netty-tcnative on
|
||||||
BoringSSL. It includes pre-built libraries for 64 bit Windows, OS X, and 64 bit
|
BoringSSL. It includes pre-built libraries for 64 bit Windows, OS X, and 64 bit
|
||||||
|
|
@ -243,37 +254,6 @@ import java.security.Security;
|
||||||
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
Security.insertProviderAt(Conscrypt.newProvider(), 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
### TLS with Jetty ALPN
|
|
||||||
|
|
||||||
**Please do not use Jetty ALPN**
|
|
||||||
|
|
||||||
gRPC historically supported Jetty ALPN for ALPN on Java 8. While functional, it
|
|
||||||
suffers from poor performance and breakages when the JRE is upgraded.
|
|
||||||
When mis-matched to the JRE version, it can also produce unpredictable errors
|
|
||||||
that are hard to diagnose. When using it, it became common practice that any
|
|
||||||
time we saw a TLS failure that made no sense we would blame a Jetty ALPN/JRE
|
|
||||||
version mismatch and we were overwhelmingly correct. The Jetty ALPN agent makes
|
|
||||||
it much easier to use, but we still strongly discourage Jetty ALPN's use.
|
|
||||||
|
|
||||||
When using Jetty ALPN with Java 8, realize that performance will be 2-10% that
|
|
||||||
of the other options due to a slow AES GCM implementation in Java.
|
|
||||||
|
|
||||||
#### Configuring Jetty ALPN in Web Containers
|
|
||||||
|
|
||||||
Some web containers, such as [Jetty](https://www.eclipse.org/jetty/documentation/current/jetty-classloading.html) restrict access to server classes for web applications. A gRPC client running within such a container must be properly configured to allow access to the ALPN classes. In Jetty, this is done by including a `WEB-INF/jetty-env.xml` file containing the following:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
||||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
|
||||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
|
||||||
<!-- Must be done in jetty-env.xml, since jetty-web.xml is loaded too late. -->
|
|
||||||
<!-- Removing ALPN from the blacklisted server classes (using "-" to remove). -->
|
|
||||||
<!-- Must prepend to the blacklist since order matters. -->
|
|
||||||
<Call name="prependServerClass">
|
|
||||||
<Arg>-org.eclipse.jetty.alpn.</Arg>
|
|
||||||
</Call>
|
|
||||||
</Configure>
|
|
||||||
```
|
|
||||||
## Enabling TLS on a server
|
## Enabling TLS on a server
|
||||||
|
|
||||||
To use TLS on the server, a certificate chain and private key need to be
|
To use TLS on the server, a certificate chain and private key need to be
|
||||||
|
|
@ -281,35 +261,36 @@ specified in PEM format. The standard TLS port is 443, but we use 8443 below to
|
||||||
avoid needing extra permissions from the OS.
|
avoid needing extra permissions from the OS.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Server server = ServerBuilder.forPort(8443)
|
ServerCredentials creds = TlsServerCredentials.create(certChainFile, privateKeyFile);
|
||||||
// Enable TLS
|
Server server = Grpc.newServerBuilderForPort(8443, creds)
|
||||||
.useTransportSecurity(certChainFile, privateKeyFile)
|
|
||||||
.addService(serviceImplementation)
|
.addService(serviceImplementation)
|
||||||
.build();
|
.build()
|
||||||
server.start();
|
.start();
|
||||||
```
|
```
|
||||||
|
|
||||||
If the issuing certificate authority is not known to the client then a properly
|
If the issuing certificate authority is not known to the client then a properly
|
||||||
configured SslContext or SSLSocketFactory should be provided to the
|
configured trust manager should be provided to TlsChannelCredentials and used to
|
||||||
NettyChannelBuilder or OkHttpChannelBuilder, respectively.
|
construct the channel.
|
||||||
|
|
||||||
## Mutual TLS
|
## Mutual TLS
|
||||||
|
|
||||||
[Mutual authentication][] (or "client-side authentication") configuration is similar to the server by providing truststores, a client certificate and private key to the client channel. The server must also be configured to request a certificate from clients, as well as truststores for which client certificates it should allow.
|
[Mutual authentication][] (or "client-side authentication") configuration is similar to the server by providing truststores, a client certificate and private key to the client channel. The server must also be configured to request a certificate from clients, as well as truststores for which client certificates it should allow.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Server server = NettyServerBuilder.forPort(8443)
|
ServerCredentials creds = TlsServerCredentials.newBuilder()
|
||||||
.sslContext(GrpcSslContexts.forServer(certChainFile, privateKeyFile)
|
.keyManager(certChainFile, privateKeyFile)
|
||||||
.trustManager(clientCAsFile)
|
.trustManager(clientCAsFile)
|
||||||
.clientAuth(ClientAuth.REQUIRE)
|
.clientAuth(TlsServerCredentials.ClientAuth.REQUIRE)
|
||||||
.build());
|
.build();
|
||||||
```
|
```
|
||||||
|
|
||||||
Negotiated client certificates are available in the SSLSession, which is found in the `TRANSPORT_ATTR_SSL_SESSION` attribute of <a href="https://github.com/grpc/grpc-java/blob/master/core/src/main/java/io/grpc/Grpc.java">Grpc</a>. A server interceptor can provide details in the current Context.
|
Negotiated client certificates are available in the SSLSession, which is found
|
||||||
|
in the `Grpc.TRANSPORT_ATTR_SSL_SESSION` attribute of the call. A server
|
||||||
|
interceptor can provide details in the current Context.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// The application uses this in its handlers
|
// The application uses this in its handlers.
|
||||||
public final static Context.Key<SSLSession> SSL_SESSION_CONTEXT = Context.key("SSLSession");
|
public static final Context.Key<MySecurityInfo> SECURITY_INFO = Context.key("my.security.Info");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
|
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
|
||||||
|
|
@ -318,8 +299,12 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, Re
|
||||||
if (sslSession == null) {
|
if (sslSession == null) {
|
||||||
return next.startCall(call, headers);
|
return next.startCall(call, headers);
|
||||||
}
|
}
|
||||||
|
// This interceptor can provide a centralized policy to process the client's
|
||||||
|
// certificate. Avoid exposing low-level details (like SSLSession) and
|
||||||
|
// instead provide a higher-level concept like "authenticated user."
|
||||||
|
MySecurityInfo info = process(sslSession);
|
||||||
return Contexts.interceptCall(
|
return Contexts.interceptCall(
|
||||||
Context.current().withValue(SSL_SESSION_CONTEXT, sslSession), call, headers, next);
|
Context.current().withValue(SECURITY_INFO, info), call, headers, next);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -358,10 +343,6 @@ If on Fedora 30 or later and you see "libcrypt.so.1: cannot open shared object
|
||||||
file: No such file or directory". Run `dnf -y install libxcrypt-compat` to
|
file: No such file or directory". Run `dnf -y install libxcrypt-compat` to
|
||||||
install the necessary dependency.
|
install the necessary dependency.
|
||||||
|
|
||||||
If you are running inside of an embedded Tomcat runtime (e.g., Spring Boot),
|
|
||||||
then some versions of `netty-tcnative-boringssl-static` will have conflicts and
|
|
||||||
won't work. You must use gRPC 1.4.0 or later.
|
|
||||||
|
|
||||||
Most dependency versioning problems can be solved by using
|
Most dependency versioning problems can be solved by using
|
||||||
`io.grpc:grpc-netty-shaded` instead of `io.grpc:grpc-netty`, although this also
|
`io.grpc:grpc-netty-shaded` instead of `io.grpc:grpc-netty`, although this also
|
||||||
limits your usage of the Netty-specific APIs. `io.grpc:grpc-netty-shaded`
|
limits your usage of the Netty-specific APIs. `io.grpc:grpc-netty-shaded`
|
||||||
|
|
@ -418,19 +399,12 @@ grpc-netty version | netty-handler version | netty-tcnative-boringssl-static ver
|
||||||
_(grpc-netty-shaded avoids issues with keeping these versions in sync.)_
|
_(grpc-netty-shaded avoids issues with keeping these versions in sync.)_
|
||||||
|
|
||||||
### OkHttp
|
### OkHttp
|
||||||
If you are using gRPC on Android devices, you are most likely using `grpc-okhttp` transport.
|
If you are using gRPC on Android devices, you are most likely using
|
||||||
|
`grpc-okhttp` transport.
|
||||||
|
|
||||||
Find the dependency tree (e.g., `mvn dependency:tree`), and look for versions of:
|
Find the dependency tree (e.g., `mvn dependency:tree`), and look for
|
||||||
- `io.grpc:grpc-okhttp`
|
`io.grpc:grpc-okhttp`. If you don't have `grpc-okhttp`, you should add it as a
|
||||||
- `com.squareup.okhttp:okhttp`
|
dependency.
|
||||||
|
|
||||||
If you don't have `grpc-okhttp`, you should add it as a dependency.
|
|
||||||
|
|
||||||
If you have both `io.grpc:grpc-netty` and `io.grpc:grpc-okhttp`, you may also have issues. Remove `grpc-netty` if you are on Android.
|
|
||||||
|
|
||||||
If you have `okhttp` version below 2.5.0, then it may not work with gRPC.
|
|
||||||
|
|
||||||
It is OK to have both `okhttp` 2.x and 3.x since they have different group name and under different packages.
|
|
||||||
|
|
||||||
# gRPC over plaintext
|
# gRPC over plaintext
|
||||||
|
|
||||||
|
|
@ -441,17 +415,12 @@ An option is provided to use gRPC over plaintext without TLS. While this is conv
|
||||||
The following code snippet shows how you can call the Google Cloud PubSub API using gRPC with a service account. The credentials are loaded from a key stored in a well-known location or by detecting that the application is running in an environment that can provide one automatically, e.g. Google Compute Engine. While this example is specific to Google and it's services, similar patterns can be followed for other service providers.
|
The following code snippet shows how you can call the Google Cloud PubSub API using gRPC with a service account. The credentials are loaded from a key stored in a well-known location or by detecting that the application is running in an environment that can provide one automatically, e.g. Google Compute Engine. While this example is specific to Google and it's services, similar patterns can be followed for other service providers.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Create a channel to the test service.
|
// Use the default credentials from the environment
|
||||||
ManagedChannel channel = ManagedChannelBuilder.forTarget("dns:///pubsub.googleapis.com")
|
ChannelCredentials creds = GoogleDefaultChannelCredentials.create();
|
||||||
|
// Create a channel to the service
|
||||||
|
ManagedChannel channel = Grpc.newChannelBuilder("dns:///pubsub.googleapis.com", creds)
|
||||||
.build();
|
.build();
|
||||||
// Get the default credentials from the environment
|
// Create a stub and send an RPC
|
||||||
GoogleCredentials creds = GoogleCredentials.getApplicationDefault();
|
PublisherGrpc.PublisherBlockingStub publisherStub = PublisherGrpc.newBlockingStub(channel);
|
||||||
// Down-scope the credential to just the scopes required by the service
|
|
||||||
creds = creds.createScoped(Arrays.asList("https://www.googleapis.com/auth/pubsub"));
|
|
||||||
// Create an instance of {@link io.grpc.CallCredentials}
|
|
||||||
CallCredentials callCreds = MoreCallCredentials.from(creds);
|
|
||||||
// Create a stub with credential
|
|
||||||
PublisherGrpc.PublisherBlockingStub publisherStub =
|
|
||||||
PublisherGrpc.newBlockingStub(channel).withCallCredentials(callCreds);
|
|
||||||
publisherStub.publish(someMessage);
|
publisherStub.publish(someMessage);
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue