To simplify this process, we will use CFSSL - CloudFlare's PKI/TLS toolkit
brew install cfssl
The ./regen-ca-certs.sh
script will create the the self-signed ca certificate for each environment and application. If a csr
and/or
.pem
already exists, it will NOT be overwritten.
./regen-ca-certs.sh <app_name>
Here <app_name>
is the name of the application for which the ssl certs need to be generated.
./regen-ssl-certs.sh
This scripts generates the server and client certificates for each environment. The csr for each certificate is stored
in the config/
directory under each environment. The certificates are created with a 8760h (1 year) expiration and
should be refreshed before expiry.
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.
SslContext sslContext = GrpcSslContexts
.forServer(certChainFile, privateKeyFile) // path to the environment specific server certificate and corresponding key
.trustManager(caCertFile) // path to the environment specific CA certificate
.build();
NettyServerBuilder.forPort(8443)
.addService(new ServiceImpl())
.sslContext(sslContext)
.build();
SslContext sslContext = GrpcSslContexts.forClient()
.trustManager(caCertFile) // path to the environment specific CA certificate
.keyManager(clientCertFile, clientKeyFile) // path to the environment specific client certificate and corresponding key
.build();
NettyChannelBuilder.forAddress(serverHost, serverPort)
.negotiationType(NegotiationType.TLS)
.sslContext(sslContext)
.build();
Negotiated client certificates are available in the SSLSession, which is found in the SSL_SESSION_KEY attribute of ServerCall. A server interceptor can provide details in the current Context.
public final static Context.Key<SSLSession> SSL_SESSION_CONTEXT = Context.key("SSLSession");
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(MethodDescriptor<ReqT, RespT> method,
ServerCall<RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
SSLSession sslSession = call.attributes().get(ServerCall.SSL_SESSION_KEY);
if (sslSession == null) {
return next.startCall(method, call, headers)
}
return Contexts.interceptCall(
Context.current().withValue(SSL_SESSION_CONTEXT, clientContext),
method, call, headers, next);
}