Skip to content

feat(mtls): Add support for X.509-based mTLS-transport in Java GAX lib #3852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@
import com.google.api.gax.rpc.TransportChannel;
import com.google.api.gax.rpc.TransportChannelProvider;
import com.google.api.gax.rpc.internal.EnvironmentProvider;
import com.google.api.gax.rpc.mtls.MtlsProvider;
import com.google.api.gax.rpc.mtls.CertificateBasedAccess;
import com.google.auth.ApiKeyCredentials;
import com.google.auth.Credentials;
import com.google.auth.mtls.CertificateSourceUnavailableException;
import com.google.auth.mtls.DefaultMtlsProviderFactory;
import com.google.auth.mtls.MtlsProvider;
import com.google.auth.oauth2.ComputeEngineCredentials;
import com.google.auth.oauth2.SecureSessionAgent;
import com.google.auth.oauth2.SecureSessionAgentConfig;
Expand Down Expand Up @@ -150,6 +153,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP
@Nullable private final Boolean allowNonDefaultServiceAccount;
@VisibleForTesting final ImmutableMap<String, ?> directPathServiceConfig;
@Nullable private final MtlsProvider mtlsProvider;
@Nullable private final CertificateBasedAccess certificateBasedAccess;
@Nullable private final SecureSessionAgent s2aConfigProvider;
private final List<HardBoundTokenTypes> allowedHardBoundTokenTypes;
@VisibleForTesting final Map<String, String> headersWithDuplicatesRemoved = new HashMap<>();
Expand Down Expand Up @@ -183,6 +187,7 @@ private InstantiatingGrpcChannelProvider(Builder builder) {
this.mtlsEndpoint = builder.mtlsEndpoint;
this.allowedHardBoundTokenTypes = builder.allowedHardBoundTokenTypes;
this.mtlsProvider = builder.mtlsProvider;
this.certificateBasedAccess = builder.certificateBasedAccess;
this.s2aConfigProvider = builder.s2aConfigProvider;
this.envProvider = builder.envProvider;
this.interceptorProvider = builder.interceptorProvider;
Expand Down Expand Up @@ -484,13 +489,15 @@ boolean canUseDirectPathWithUniverseDomain() {

@VisibleForTesting
ChannelCredentials createMtlsChannelCredentials() throws IOException, GeneralSecurityException {
if (mtlsProvider.useMtlsClientCertificate()) {
KeyStore mtlsKeyStore = mtlsProvider.getKeyStore();
if (mtlsKeyStore != null) {
KeyManagerFactory factory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
factory.init(mtlsKeyStore, new char[] {});
return TlsChannelCredentials.newBuilder().keyManager(factory.getKeyManagers()).build();
if (certificateBasedAccess != null && certificateBasedAccess.useMtlsClientCertificate()) {
if (mtlsProvider != null) {
KeyStore mtlsKeyStore = mtlsProvider.getKeyStore();
if (mtlsKeyStore != null) {
KeyManagerFactory factory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
factory.init(mtlsKeyStore, new char[] {});
return TlsChannelCredentials.newBuilder().keyManager(factory.getKeyManagers()).build();
}
}
}
return null;
Expand Down Expand Up @@ -853,7 +860,8 @@ public static final class Builder {
private boolean useS2A;
private EnvironmentProvider envProvider;
private SecureSessionAgent s2aConfigProvider = SecureSessionAgent.create();
private MtlsProvider mtlsProvider = new MtlsProvider();
private MtlsProvider mtlsProvider;
private CertificateBasedAccess certificateBasedAccess;
@Nullable private GrpcInterceptorProvider interceptorProvider;
@Nullable private Integer maxInboundMessageSize;
@Nullable private Integer maxInboundMetadataSize;
Expand Down Expand Up @@ -904,6 +912,7 @@ private Builder(InstantiatingGrpcChannelProvider provider) {
this.allowedHardBoundTokenTypes = provider.allowedHardBoundTokenTypes;
this.directPathServiceConfig = provider.directPathServiceConfig;
this.mtlsProvider = provider.mtlsProvider;
this.certificateBasedAccess = provider.certificateBasedAccess;
this.s2aConfigProvider = provider.s2aConfigProvider;
}

Expand Down Expand Up @@ -994,6 +1003,12 @@ Builder setMtlsProvider(MtlsProvider mtlsProvider) {
return this;
}

@VisibleForTesting
Builder setCertificateBasedAccess(CertificateBasedAccess certificateBasedAccess) {
this.certificateBasedAccess = certificateBasedAccess;
return this;
}

@VisibleForTesting
Builder setS2AConfigProvider(SecureSessionAgent s2aConfigProvider) {
this.s2aConfigProvider = s2aConfigProvider;
Expand Down Expand Up @@ -1269,6 +1284,24 @@ CallCredentials createHardBoundTokensCallCredentials(
}

public InstantiatingGrpcChannelProvider build() {
if (certificateBasedAccess == null) {
certificateBasedAccess = CertificateBasedAccess.createWithSystemEnv();
}
if (certificateBasedAccess.useMtlsClientCertificate()) {
if (mtlsProvider == null) {
// Attempt to create default MtlsProvider from environment.
try {
mtlsProvider = DefaultMtlsProviderFactory.create();
} catch (CertificateSourceUnavailableException e) {
// This is okay. Leave mtlsProvider as null;
} catch (IOException e) {
LOG.log(
Level.WARNING,
"DefaultMtlsProviderFactory encountered unexpected IOException: " + e.getMessage());
}
}
}

if (isMtlsS2AHardBoundTokensEnabled()) {
// Set a {@code ComputeEngineCredentials} instance to be per-RPC call credentials,
// which will be used to fetch MTLS_S2A hard bound tokens from the metdata server.
Expand Down
Loading
Loading