Skip to content

Commit

Permalink
[#8128] TLS for grpc client
Browse files Browse the repository at this point in the history
  • Loading branch information
koo-taejin committed Sep 2, 2021
1 parent 73a97c9 commit 3ed757c
Show file tree
Hide file tree
Showing 16 changed files with 500 additions and 24 deletions.
14 changes: 13 additions & 1 deletion agent/src/main/resources/pinpoint-root.config
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ profiler.transport.grpc.collector.ip=127.0.0.1
# Agent
profiler.transport.grpc.agent.collector.ip=${profiler.transport.grpc.collector.ip}
profiler.transport.grpc.agent.collector.port=9991
profiler.transport.grpc.agent.ssl.enable=false
profiler.transport.grpc.agent.sender.channel.executor.queue.size=1000
profiler.transport.grpc.agent.sender.request.timeout.millis=6000
profiler.transport.grpc.agent.sender.keepalive.time.millis=30000
Expand All @@ -40,6 +41,7 @@ profiler.transport.grpc.agent.sender.maxtraceevent=0
# Metadata
profiler.transport.grpc.metadata.collector.ip=${profiler.transport.grpc.collector.ip}
profiler.transport.grpc.metadata.collector.port=9991
profiler.transport.grpc.metadata.ssl.enable=false
profiler.transport.grpc.metadata.sender.executor.queue.size=1000
profiler.transport.grpc.metadata.sender.channel.executor.queue.size=1000
profiler.transport.grpc.metadata.sender.request.timeout.millis=6000
Expand All @@ -60,6 +62,7 @@ profiler.transport.grpc.metadata.sender.maxtraceevent=0
# Stat
profiler.transport.grpc.stat.collector.ip=${profiler.transport.grpc.collector.ip}
profiler.transport.grpc.stat.collector.port=9992
profiler.transport.grpc.stat.ssl.enable=false
profiler.transport.grpc.stat.sender.executor.queue.size=1000
profiler.transport.grpc.stat.sender.channel.executor.queue.size=1000
profiler.transport.grpc.stat.sender.request.timeout.millis=6000
Expand All @@ -78,6 +81,7 @@ profiler.transport.grpc.stat.sender.maxtraceevent=0
# Span
profiler.transport.grpc.span.collector.ip=${profiler.transport.grpc.collector.ip}
profiler.transport.grpc.span.collector.port=9993
profiler.transport.grpc.span.ssl.enable=false
profiler.transport.grpc.span.sender.executor.queue.size=1000
profiler.transport.grpc.span.sender.channel.executor.queue.size=1000
profiler.transport.grpc.span.sender.request.timeout.millis=6000
Expand All @@ -99,6 +103,14 @@ profiler.transport.grpc.span.sender.maxtraceevent=8
profiler.transport.grpc.span.sender.limitcount=100
profiler.transport.grpc.span.sender.limittime=60000

# Grpc Tls
profiler.transport.grpc.ssl.enable=false
# openssl or jdk (jdk requires 1.9 or above)
profiler.transport.grpc.ssl.provider.type=jdk
# please insert .crt file path (If empty, default Root CA certificates will be used.(generally, from JAVA_HOME/lib/cacerts))
# (prefix for claspath = claspath:, prefix for absoulute path = file:)
profiler.transport.grpc.ssl.trust.cert.file.path=

# This configuration enable some function of netty
# Functions are available without the this configuration when using jdk8 and below,
profiler.system.property.io.netty.tryReflectionSetAccessible=true
Expand All @@ -123,7 +135,7 @@ profiler.collector.tcp.ip=${profiler.collector.ip}
profiler.collector.tcp.port=9994

###########################################################
# Profiler Global Configuration #
# Profiler Global Configuration #
###########################################################
profiler.enable=true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ collector.receiver.grpc.ssl.enable=false
# please choose openssl/jdk
collector.receiver.grpc.ssl.provider_type=jdk
# please insert .pem file path
# (prefix for claspath = claspath:, prefix for absoulute path = file:)
collector.receiver.grpc.ssl.key_file_path=
# please insert .crt file path
# (prefix for claspath = claspath:, prefix for absoulute path = file:)
collector.receiver.grpc.ssl.key_cert_file_path=

# Agent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ collector.receiver.grpc.ssl.enable=false
# please choose openssl/jdk
collector.receiver.grpc.ssl.provider_type=jdk
# please insert .pem file path
# (prefix for claspath = claspath:, prefix for absoulute path = file:)
collector.receiver.grpc.ssl.key_file_path=
# please insert .crt file path
# (prefix for claspath = claspath:, prefix for absoulute path = file:)
collector.receiver.grpc.ssl.key_cert_file_path=

# Agent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.navercorp.pinpoint.grpc.client;

import com.navercorp.pinpoint.grpc.client.config.ClientOption;
import com.navercorp.pinpoint.grpc.client.config.SslOption;

import io.grpc.ClientInterceptor;
import io.grpc.NameResolverProvider;

Expand All @@ -37,6 +39,8 @@ public interface ChannelFactoryBuilder {

void setClientOption(ClientOption clientOption);

void setSslOption(SslOption sslOption);

void setNameResolverProvider(NameResolverProvider nameResolverProvider);

ChannelFactory build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,28 @@
import com.navercorp.pinpoint.grpc.ChannelTypeEnum;
import com.navercorp.pinpoint.grpc.ExecutorUtils;
import com.navercorp.pinpoint.grpc.client.config.ClientOption;
import com.navercorp.pinpoint.grpc.security.SslClientConfig;
import com.navercorp.pinpoint.grpc.security.SslContextFactory;

import io.grpc.ClientInterceptor;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.NameResolverProvider;
import io.grpc.internal.GrpcUtil;
import io.grpc.netty.InternalNettyChannelBuilder;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.stub.MetadataUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.handler.ssl.SslContext;
import io.netty.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
Expand All @@ -59,6 +65,7 @@ public class DefaultChannelFactory implements ChannelFactory {
private final HeaderFactory headerFactory;

private final ClientOption clientOption;
private final SslClientConfig sslClientConfig;

private final List<ClientInterceptor> clientInterceptorList;
private final NameResolverProvider nameResolverProvider;
Expand All @@ -69,19 +76,20 @@ public class DefaultChannelFactory implements ChannelFactory {
private final ExecutorService executorService;
private final Class<? extends Channel> channelType;


DefaultChannelFactory(String factoryName,
int executorQueueSize,
HeaderFactory headerFactory,
NameResolverProvider nameResolverProvider,
ClientOption clientOption,
SslClientConfig sslClientConfig,
List<ClientInterceptor> clientInterceptorList) {
this.factoryName = Objects.requireNonNull(factoryName, "factoryName");
this.executorQueueSize = executorQueueSize;
this.headerFactory = Objects.requireNonNull(headerFactory, "headerFactory");
// @Nullable
this.nameResolverProvider = nameResolverProvider;
this.clientOption = Objects.requireNonNull(clientOption, "clientOption");
this.sslClientConfig = Objects.requireNonNull(sslClientConfig, "sslClientConfig");

Objects.requireNonNull(clientInterceptorList, "clientInterceptorList");
this.clientInterceptorList = new ArrayList<>(clientInterceptorList);
Expand Down Expand Up @@ -146,6 +154,17 @@ public ManagedChannel build(String channelName, String host, int port) {
}
setupClientOption(channelBuilder);

if (sslClientConfig.isEnable()) {
SslContext sslContext = null;
try {
sslContext = SslContextFactory.create(sslClientConfig);
} catch (SSLException e) {
throw new SecurityException(e);
}
channelBuilder.sslContext(sslContext);
channelBuilder.negotiationType(NegotiationType.TLS);
}

channelBuilder.maxTraceEvents(clientOption.getMaxTraceEvent());

final ManagedChannel channel = channelBuilder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

import com.navercorp.pinpoint.common.util.Assert;
import com.navercorp.pinpoint.grpc.client.config.ClientOption;
import com.navercorp.pinpoint.grpc.client.config.SslOption;
import com.navercorp.pinpoint.grpc.security.SslClientConfig;
import com.navercorp.pinpoint.grpc.util.Resource;

import io.grpc.ClientInterceptor;
import io.grpc.NameResolverProvider;
import org.slf4j.Logger;
Expand All @@ -39,6 +43,7 @@ public class DefaultChannelFactoryBuilder implements ChannelFactoryBuilder {
private HeaderFactory headerFactory;

private ClientOption clientOption;
private SslOption sslOption;

private final LinkedList<ClientInterceptor> clientInterceptorList = new LinkedList<>();
private NameResolverProvider nameResolverProvider;
Expand Down Expand Up @@ -75,6 +80,12 @@ public void setClientOption(ClientOption clientOption) {
this.clientOption = Objects.requireNonNull(clientOption, "clientOption");
}

@Override
public void setSslOption(SslOption sslOption) {
// nullable
this.sslOption = sslOption;
}

@Override
public void setNameResolverProvider(NameResolverProvider nameResolverProvider) {
this.nameResolverProvider = Objects.requireNonNull(nameResolverProvider, "nameResolverProvider");
Expand All @@ -86,8 +97,15 @@ public ChannelFactory build() {
Objects.requireNonNull(headerFactory, "headerFactory");
Objects.requireNonNull(clientOption, "clientOption");

SslClientConfig sslClientConfig = SslClientConfig.DISABLED_CONFIG;
if (sslOption != null && sslOption.isEnable()) {
String providerType = sslOption.getProviderType();
Resource trustCertResource = sslOption.getTrustCertResource();
sslClientConfig = new SslClientConfig(true, providerType, trustCertResource);
}

return new DefaultChannelFactory(factoryName, executorQueueSize,
headerFactory, nameResolverProvider,
clientOption, clientInterceptorList);
clientOption, sslClientConfig, clientInterceptorList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright 2021 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.grpc.client.config;

import com.navercorp.pinpoint.bootstrap.config.Value;
import com.navercorp.pinpoint.common.util.StringUtils;
import com.navercorp.pinpoint.grpc.util.FileSystemResource;
import com.navercorp.pinpoint.grpc.util.Resource;

import java.net.URL;
import java.util.Objects;

/**
* @author Taejin Koo
*/
public class SslOption {

public static final boolean DISABLE = Boolean.FALSE;
public static final String DEFAULT_PROVIDER_TYPE = "jdk"; // jdk
public static final Resource DEFAULT_TRUST_CERT_RESOURCE = null; // `null` is load from (JAVA_HOME/lib/cacerts)

private final boolean enable;
private final String providerType;
private final Resource trustCertResource;

private SslOption(boolean enable, String providerType, Resource trustCertResource) {
this.enable = enable;
this.providerType = providerType;
this.trustCertResource = trustCertResource;
}

public boolean isEnable() {
return enable;
}

public String getProviderType() {
return providerType;
}

public Resource getTrustCertResource() {
return trustCertResource;
}

public static class Builder {

private final String basePath;

@Value("${enable}")
private boolean enable;
@Value("${provider.type}")
private String providerType;
@Value("${trust.cert.file.path}")
private String trustCertFilePath;

public Builder(String basePath) {
this.basePath = basePath;
}

public String getBasePath() {
return basePath;
}

public boolean isEnable() {
return enable;
}

public void setEnable(boolean enable) {
this.enable = enable;
}

public String getProviderType() {
return providerType;
}

public void setProviderType(String providerType) {
this.providerType = providerType;
}

public String getTrustCertFilePath() {
return trustCertFilePath;
}

public void setTrustCertFilePath(String trustCertFilePath) {
this.trustCertFilePath = trustCertFilePath;
}

public SslOption build() {
if (enable) {
Objects.requireNonNull(providerType);
Resource trustCertResource = toResource(trustCertFilePath);
return new SslOption(true, this.providerType, trustCertResource);
} else {
return new SslOption(this.enable, DEFAULT_PROVIDER_TYPE, DEFAULT_TRUST_CERT_RESOURCE);
}
}

private static final String CLASSPATH_URL_PREFIX = "classpath:";
private static final String FILE_URL_PREFIX = "file:";

private Resource toResource(String filePath) {
if (!StringUtils.hasText(filePath)) {
return null;
}

Resource resource = null;
if (filePath.startsWith(CLASSPATH_URL_PREFIX)) {
String path = filePath.substring(CLASSPATH_URL_PREFIX.length());
resource = FileSystemResource.createResource(basePath, path);
} else if (filePath.startsWith(FILE_URL_PREFIX)) {
String path = filePath.substring(FILE_URL_PREFIX.length());
resource = FileSystemResource.createResource(path);
}

if (resource != null && resource.exists()) {
return resource;
}
throw new IllegalArgumentException("Could not find file.(path:" + filePath + ")");
}

}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("SslOption{");
sb.append("enable=").append(enable);
sb.append(", providerType='").append(providerType).append('\'');
sb.append(", trustCertResource=").append(trustCertResource);
sb.append('}');
return sb.toString();
}
}
Loading

0 comments on commit 3ed757c

Please sign in to comment.