diff --git a/docs/tls.adoc b/docs/tls.adoc new file mode 100644 index 00000000..a9c2d7b6 --- /dev/null +++ b/docs/tls.adoc @@ -0,0 +1,53 @@ +== Setting Up TLS/SSL Security + +=== Server Authentication + +.Example generating of server certificate +---- +SERVER_CA="ca.myhost.dev" +SERVER_IP="127.0.0.1" +ORG="My Company" +ORG_UNIT="Blockchain" + +certstrap init --common-name "$SERVER_CA" --passphrase "" -o "$ORG" -ou "$ORG_UNIT CA" +certstrap request-cert -ip $SERVER_IP --passphrase "" -o "$ORG" -ou "$ORG_UNIT Server" +certstrap sign $SERVER_IP --CA $SERVER_CA + +openssl pkcs8 -topk8 -inform PEM -outform PEM -in out/$SERVER_IP.key -out out/$SERVER_IP.p8.key -nocrypt +---- + +.Setup application.properties +---- +ssl=true +ssl.cert=out/127.0.0.1.crt +ssl.key=out/127.0.0.1.p8.key +---- + +.Verify server certificate +---- +openssl s_client -alpn h2 -connect 127.0.0.1:8090 -CAfile out/ca.myhost.dev.crt +---- + +=== Client Authentication (optional) + +.Example generating of client certifiacte +---- +CLIENT_CA="client-ca.myhost.dev" +CLIENT_ID="client_1" +ORG="My Company" +ORG_UNIT="Client" + +certstrap init --common-name "$CLIENT_CA" --passphrase "" -o "$ORG" -ou "$ORG_UNIT CA" +certstrap request-cert --common-name "$CLIENT_ID" --passphrase "" +certstrap sign "$CLIENT_ID" --CA $CLIENT_CA +---- + +.Setup application.properties +---- +ssl.client.cert=out/client-ca.myhost.dev.crt +---- + +.Vetify connection with client certificate +---- +openssl s_client -alpn h2 -connect 127.0.0.1:8090 -CAfile out/ca.myhost.dev.crt -cert out/client_1.crt -key out/client_1.key +---- diff --git a/src/main/kotlin/io/emeraldpay/dshackle/GrpcServer.kt b/src/main/kotlin/io/emeraldpay/dshackle/GrpcServer.kt index 1fbbfcbf..41bf2220 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/GrpcServer.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/GrpcServer.kt @@ -1,7 +1,9 @@ package io.emeraldpay.dshackle import io.grpc.Server -import io.grpc.ServerBuilder +import io.grpc.netty.GrpcSslContexts +import io.grpc.netty.NettyServerBuilder +import io.netty.handler.ssl.ClientAuth import org.apache.commons.lang3.StringUtils import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -28,7 +30,7 @@ open class GrpcServer( log.info("Starting GRPC Server...") val port = env.getProperty("port", "8090").toInt() log.info("Listening on 0.0.0.0:$port") - val serverBuilder = ServerBuilder.forPort(port) + val serverBuilder = NettyServerBuilder.forPort(port) rpcs.forEach { serverBuilder.addService(it) } @@ -47,11 +49,19 @@ open class GrpcServer( } if (secure) { log.info("Using TLS") - serverBuilder - .useTransportSecurity( - File(env.getProperty("ssl.cert")!!), - File(env.getProperty("ssl.key")!!) - ) + val sslContextBuilder = GrpcSslContexts.forServer( + File(env.getProperty("ssl.cert")!!), + File(env.getProperty("ssl.key")!!) + ) + if (StringUtils.isNotEmpty(env.getProperty("ssl.client.cert"))) { + log.info("Using TLS for client authentication") + sslContextBuilder.trustManager( + File(env.getProperty("ssl.client.cert")!!) + ).clientAuth(ClientAuth.REQUIRE) + } else { + log.warn("Trust all clients") + } + serverBuilder.sslContext(sslContextBuilder.build()) } else { log.warn("Using insecure transport") }