Skip to content

Commit

Permalink
Rearranging the SECURITY doc
Browse files Browse the repository at this point in the history
  • Loading branch information
nmittler committed Sep 10, 2015
1 parent 18b919d commit fe56a2a
Showing 1 changed file with 150 additions and 41 deletions.
191 changes: 150 additions & 41 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,155 @@

As outlined in <a href="https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md">gRPC Authentication Support</a>, 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.

# Java 7, HTTP2 & Crypto
# Transport Security (TLS)

## Cipher-Suites
Java 7 does not support the <a href="https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-9.2.2">the cipher suites recommended</a> by the HTTP2 specification. To address this we suggest servers use Java 8 where possible or use an alternative JCE implementation such as <a href="https://www.bouncycastle.org/java.html">Bouncy Castle</a>. If this is not practical it is possible to use other ciphers but you need to ensure that the services you intend to call have <a href="https://github.com/grpc/grpc/issues/681">allowed out-of-spec ciphers</a> and have evaluated the security risks of doing so. On Android we recommend the use of the <a href="http://appfoundry.be/blog/2014/11/18/Google-Play-Services-Dynamic-Security-Provider/">Play Services Dynamic Security Provider</a> to ensure your application has an up-to-date OpenSSL library with the necessary ciper-suites and a reliable ALPN implementation.
HTTP/2 over TLS mandates the use of [ALPN](https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05) to negotiate the use of the h2 protocol. ALPN is a fairly new standard and (where possible) gRPC also supports protocol negotiation via [NPN](https://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04) for systems that do not yet support ALPN.

Users should be aware that GCM is [_very_ slow (1 MB/s)](https://bugzilla.redhat.com/show_bug.cgi?id=1135504) in JDK 8. GCM cipher suites are the only suites available that comply with HTTP2's cipher requirements. When using the Netty transport, it is recommended to use OpenSSL (described below) which has a GCM implementation that does not suffer from the same performance issues.
## TLS on Android

## Protocol Negotiation (TLS-ALPN)
HTTP2 mandates the use of <a href="https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-05">ALPN</a> to negotiate the use of the protocol over SSL. No standard Java release has built-in support for ALPN today (<a href="https://bugs.openjdk.java.net/browse/JDK-8051498">there is a tracking issue</a> so go upvote it!).
On Android we recommend the use of the [Play Services Dynamic Security Provider](http://appfoundry.be/blog/2014/11/18/Google-Play-Services-Dynamic-Security-Provider) to ensure your application has an up-to-date OpenSSL library with the necessary ciper-suites and a reliable ALPN implementation.

To support ALPN, gRPC provides a few alternatives:
You may need to [update the security provider](https://developer.android.com/training/articles/security-gms-provider.html) to enable ALPN support, especially for Android versions < 5.0. If the provider fails to update, ALPN may not work.

### TLS-ALPN with OpenSSL
## TLS with OpenSSL

This is currently the recommended approach for using gRPC over TLS-ALPN. In local testing, we've seen performance improvements of 3x over the JDK. Also, the GCM codec in OpenSSL does not suffer from the performance problems in Java 8.
This is currently the recommended approach for using gRPC over TLS-ALPN (on non-Android systems).

Requirements:
### Benefits of using OpenSSL

1. Netty transport.
2. [OpenSSL](https://www.openssl.org/) version 1.0.2 (or greater) installed (ALPN support was introduced in 1.0.2).
3. [netty-tcnative](https://github.com/netty/netty-tcnative) version 1.1.33.Fork7 (or greater) on classpath (Earlier versions only support NPN).
4. Supported platforms (for `netty-tcnative`): linux-x86_64, mac-x86_64, windows-x86_64. Supporting other platforms will require manually building `netty-tcnative`.
1. Speed. In local testing, we've seen performance improvements of 3x over the JDK.
2. Ciphers. OpenSSL has its own ciphers and is not dependent on the limitations of the JDK (see section on TLS with JDK). Also, the GCM codec (the main codec recommended by the HTTP/2 spec) in OpenSSL does not suffer from the performance problems in Java 8.
3. Supports fallback to NPN if the remote endpoint doesn't support ALPN.

### Requirements for using OpenSSL

1. Currently only supported by the Netty transport (via netty-tcnative).
2. [OpenSSL](https://www.openssl.org/) version >= 1.0.2 for ALPN support, or version >= 1.0.0g for NPN.
3. [netty-tcnative](https://github.com/netty/netty-tcnative) must be on classpath. Use version >= 1.1.33.Fork7 for ALPN (prior versions only support NPN).
4. Supported platforms (for netty-tcnative): `linux-x86_64`, `mac-x86_64`, `windows-x86_64`. Supporting other platforms will require manually building netty-tcnative.

If the above requirements met, the Netty transport will automatically select OpenSSL as the default TLS provider.

### TLS-ALPN with Jetty ALPN
If not using the Netty transport (or you are unable to use OpenSSL for some reason) another alternative is to use the [Jetty-ALPN](https://github.com/jetty-project/jetty-alpn) bootclasspath extension for OpenJDK. To do this, add a `Xbootclasspath` JVM option referencing the path to the Jetty `alpn-boot` jar.
### Configuring netty-tcnative

[Netty-tcnative](https://github.com/netty/netty-tcnative) is a fork of [Apache Tomcat's tcnative](http://tomcat.apache.org/native-doc/), a JNI wrapper around OpenSSL.

Netty uses classifiers when deploying to [Maven Central](http://repo1.maven.org/maven2/io/netty/netty-tcnative/) to provide distributions for the various platforms. On Linux it should be noted that OpenSSL uses a different soname for Fedora derivatives than other Linux releases. To work around this limitation, netty-tcnative deploys two separate versions for linux.

Maven Classifier | Description
---------------- | -----------
windows-x86_64 | Windows distribution
osx-x86_64 | Mac distribution
linux-x86_64 | Used for non-Fedora derivatives of Linux
linux-x86_64-fedora | Used for Fedora derivatives

#### Getting netty-tcnative from Maven

In Maven, you can use the [os-maven-plugin](https://github.com/trustin/os-maven-plugin) to help simplify the dependency.

```xml
<project>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative</artifactId>
<version>1.1.33.Fork7</version>
<classifier>${tcnative.classifier}</classifier>
</dependency>
</dependencies>
<build>
<extensions>
<!-- Use os-maven-plugin to initialize the "os.detected" properties -->
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.2.3.Final</version>
</extension>
</extensions>
<plugins>
<!-- Use Ant to configure the appropriate "tcnative.classifier" property -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>initialize</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<condition property="tcnative.classifier"
value="${os.detected.classifier}-fedora"
else="${os.detected.classifier}">
<isset property="os.detected.release.fedora"/>
</condition>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
```

#### Getting netty-tcnative from Gradle

Gradle you can use the [osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin)) which is a wrapper around the os-maven-plugin.

```
buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath 'com.google.gradle:osdetector-gradle-plugin:1.3.0'
}
}
// Use the osdetector-gradle-plugin
apply plugin: "osdetector"
repositories {
mavenCentral()
mavenLocal()
}
// Use the appropriate artifact for Fedora vs non-Fedora.
def netty_tcnative = 'io.netty:netty-tcnative:1.1.33.Fork6:' + osdetector.classifier
if (osdetector.os == "linux" && osdetector.release.isLike("fedora")) {
netty_tcnative += "-fedora";
}
dependencies {
compile netty_tcnative
}
```

## TLS with JDK (Jetty ALPN/NPN)

If not using the Netty transport (or you are unable to use OpenSSL for some reason) another alternative is to use the JDK for TLS.

No standard Java release has built-in support for ALPN today ([there is a tracking issue](https://bugs.openjdk.java.net/browse/JDK-8051498) so go upvote it!) so we need to use the [Jetty-ALPN](https://github.com/jetty-project/jetty-alpn") (or [Jetty-NPN](https://github.com/jetty-project/jetty-npn) if on Java < 8) bootclasspath extension for OpenJDK. To do this, add a `Xbootclasspath` JVM option referencing the path to the Jetty `alpn-boot` jar.

```sh
java -Xbootclasspath/p:/path/to/jetty/alpn/extension.jar ...
```

Note that you must use the release of the Jetty-ALPN jar specific to the version of Java you are using.
Note that you must use the [release of the Jetty-ALPN jar](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-versions) specific to the version of Java you are using.

### JDK Ciphers

Java 7 does not support [the cipher suites recommended](https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-9.2.2) by the HTTP2 specification. To address this we suggest servers use Java 8 where possible or use an alternative JCE implementation such as [Bouncy Castle](https://www.bouncycastle.org/java.html). If this is not practical it is possible to use other ciphers but you need to ensure that the services you intend to call have [allowed out-of-spec ciphers](https://github.com/grpc/grpc/issues/681) and have evaluated the security risks of doing so.

Users should be aware that GCM is [_very_ slow (1 MB/s)](https://bugzilla.redhat.com/show_bug.cgi?id=1135504) in Java 8. GCM cipher suites are the only suites available that comply with HTTP2's cipher requirements.

Some web containers, such as <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty</a> 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:
### Configuring Jetty ALPN in Web Containers

Some web containers, such as [Jetty](http://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"?>
Expand All @@ -50,12 +164,26 @@ Some web containers, such as <a href="http://www.eclipse.org/jetty/documentation
</Call>
</Configure>
```
## Enabling TLS on a server

### TLS-ALPN on Android
On Android, it is needed to <a href="https://developer.android.com/training/articles/security-gms-provider.html">update your security provider</a> to enable ALPN support, especially for Android versions < 5.0. If the provider fails to update, ALPN may not work.
In this example the service owner provides a certificate chain and private key to create an SslContext. This is then bound to the server which is started on a specific port, in this case 443 which is the standard SSL port. Note that the service implementation is also bound while creating the server.

### gRPC over plaintext
An option is provided to use gRPC over plaintext without TLS. This is convenient for testing environments, however users must be aware of the security risks of doing so for real production systems.
```java
// Load certificate chain and key for SSL server into a Netty SslContext
SslContext sslContext = GrpcSslContexts.forServer(certChainFile, privateKeyFile);
// Create a server, bound to port 443 and exposing a service implementation
ServerImpl server = NettyServerBuilder.forPort(443)
.sslContext(sslContext)
.addService(TestServiceGrpc.bindService(serviceImplementation))
.build();
server.start();
```

If the issuing certificate authority for a server is not known to the client then a similar process should be followed on the client to load it so that it may validate the certificate issued to the server. If <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake">mutual authentication</a> is desired this can also be supported by creating the appropriate SslContext.

# gRPC over plaintext

An option is provided to use gRPC over plaintext without TLS. While this is convenient for testing environments, users must be aware of the security risks of doing so for real production systems.

# Using OAuth2

Expand All @@ -77,22 +205,3 @@ Channel channel = ClientInterceptors.intercept(channelImpl, interceptor);
PublisherGrpc.PublisherBlockingStub publisherStub = PublisherGrpc.newBlockingStub(channel);
publisherStub.publish(someMessage);
```


# Enabling TLS on a server

In this example the service owner provides a certificate chain and private key to create an SslContext. This is then bound to the server which is started on a specific port, in this case 443 which is the standard SSL port. Note that the service implementation is also bound while creating the server.


```java
// Load certificate chain and key for SSL server into a Netty SslContext
SslContext sslContext = GrpcSslContexts.forServer(certChainFile, privateKeyFile);
// Create a server, bound to port 443 and exposing a service implementation
ServerImpl server = NettyServerBuilder.forPort(443)
.sslContext(sslContext)
.addService(TestServiceGrpc.bindService(serviceImplementation))
.build();
server.start();
```

If the issuing certificate authority for a server is not known to the client then a similar process should be followed on the client to load it so that it may validate the certificate issued to the server. If <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake">mutual authentication</a> is desired this can also be supported by creating the appropriate SslContext.

0 comments on commit fe56a2a

Please sign in to comment.