|
67 | 67 | import io.grpc.TlsChannelCredentials; |
68 | 68 | import io.grpc.alts.GoogleDefaultChannelCredentials; |
69 | 69 | import io.grpc.auth.MoreCallCredentials; |
| 70 | +import io.grpc.util.AdvancedTlsX509KeyManager; |
| 71 | +import io.grpc.util.AdvancedTlsX509TrustManager; |
70 | 72 | import java.io.File; |
71 | 73 | import java.io.IOException; |
72 | 74 | import java.lang.reflect.Method; |
|
78 | 80 | import java.util.List; |
79 | 81 | import java.util.Map; |
80 | 82 | import java.util.concurrent.Executor; |
| 83 | +import java.util.concurrent.Executors; |
81 | 84 | import java.util.concurrent.ScheduledExecutorService; |
82 | 85 | import java.util.concurrent.TimeUnit; |
83 | 86 | import java.util.logging.Level; |
@@ -161,6 +164,8 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP |
161 | 164 | @Nullable |
162 | 165 | private final ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder> channelConfigurator; |
163 | 166 |
|
| 167 | + private static volatile ChannelCredentials s2aChannelCredentialsObject; |
| 168 | + |
164 | 169 | /* |
165 | 170 | * Experimental feature |
166 | 171 | * |
@@ -556,13 +561,19 @@ ChannelCredentials buildS2AChannelCredentials( |
556 | 561 | */ |
557 | 562 | @VisibleForTesting |
558 | 563 | ChannelCredentials createMtlsToS2AChannelCredentials( |
559 | | - File trustBundle, File privateKey, File certChain) throws IOException { |
| 564 | + File trustBundle, File privateKey, File certChain) |
| 565 | + throws IOException, GeneralSecurityException { |
560 | 566 | if (trustBundle == null || privateKey == null || certChain == null) { |
561 | 567 | return null; |
562 | 568 | } |
| 569 | + AdvancedTlsX509KeyManager keyManager = new AdvancedTlsX509KeyManager(); |
| 570 | + keyManager.updateIdentityCredentials(certChain, privateKey); |
| 571 | + AdvancedTlsX509TrustManager trustManager = AdvancedTlsX509TrustManager.newBuilder().build(); |
| 572 | + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); |
| 573 | + trustManager.updateTrustCredentials(trustBundle, 1, TimeUnit.HOURS, executor); |
563 | 574 | return TlsChannelCredentials.newBuilder() |
564 | | - .keyManager(privateKey, certChain) |
565 | | - .trustManager(trustBundle) |
| 575 | + .keyManager(keyManager) |
| 576 | + .trustManager(trustManager) |
566 | 577 | .build(); |
567 | 578 | } |
568 | 579 |
|
@@ -595,43 +606,57 @@ ChannelCredentials createPlaintextToS2AChannelCredentials(String plaintextAddres |
595 | 606 | * @return {@link ChannelCredentials} configured to use S2A to create mTLS connection. |
596 | 607 | */ |
597 | 608 | ChannelCredentials createS2ASecuredChannelCredentials() { |
598 | | - SecureSessionAgentConfig config = s2aConfigProvider.getConfig(); |
599 | | - String plaintextAddress = config.getPlaintextAddress(); |
600 | | - String mtlsAddress = config.getMtlsAddress(); |
601 | | - if (Strings.isNullOrEmpty(mtlsAddress)) { |
602 | | - // Fallback to plaintext connection to S2A. |
603 | | - LOG.log( |
604 | | - Level.INFO, |
605 | | - "Cannot establish an mTLS connection to S2A because autoconfig endpoint did not return a mtls address to reach S2A."); |
606 | | - return createPlaintextToS2AChannelCredentials(plaintextAddress); |
607 | | - } |
608 | | - // Currently, MTLS to MDS is only available on GCE. See: |
609 | | - // https://cloud.google.com/compute/docs/metadata/overview#https-mds |
610 | | - // Try to load MTLS-MDS creds. |
611 | | - File rootFile = new File(MTLS_MDS_ROOT_PATH); |
612 | | - File certKeyFile = new File(MTLS_MDS_CERT_CHAIN_AND_KEY_PATH); |
613 | | - if (rootFile.isFile() && certKeyFile.isFile()) { |
614 | | - // Try to connect to S2A using mTLS. |
615 | | - ChannelCredentials mtlsToS2AChannelCredentials = null; |
616 | | - try { |
617 | | - mtlsToS2AChannelCredentials = |
618 | | - createMtlsToS2AChannelCredentials(rootFile, certKeyFile, certKeyFile); |
619 | | - } catch (IOException ignore) { |
620 | | - // Fallback to plaintext-to-S2A connection on error. |
621 | | - LOG.log( |
622 | | - Level.WARNING, |
623 | | - "Cannot establish an mTLS connection to S2A due to error creating MTLS to MDS TlsChannelCredentials credentials, falling back to plaintext connection to S2A: " |
624 | | - + ignore.getMessage()); |
625 | | - return createPlaintextToS2AChannelCredentials(plaintextAddress); |
| 609 | + if (s2aChannelCredentialsObject == null) { |
| 610 | + synchronized (InstantiatingGrpcChannelProvider.class) { |
| 611 | + if (s2aChannelCredentialsObject == null) { |
| 612 | + SecureSessionAgentConfig config = s2aConfigProvider.getConfig(); |
| 613 | + String plaintextAddress = config.getPlaintextAddress(); |
| 614 | + String mtlsAddress = config.getMtlsAddress(); |
| 615 | + if (Strings.isNullOrEmpty(mtlsAddress)) { |
| 616 | + // Fallback to plaintext connection to S2A. |
| 617 | + LOG.log( |
| 618 | + Level.INFO, |
| 619 | + "Cannot establish an mTLS connection to S2A because autoconfig endpoint did not return a mtls address to reach S2A."); |
| 620 | + s2aChannelCredentialsObject = createPlaintextToS2AChannelCredentials(plaintextAddress); |
| 621 | + return s2aChannelCredentialsObject; |
| 622 | + } |
| 623 | + // Currently, MTLS to MDS is only available on GCE. See: |
| 624 | + // https://cloud.google.com/compute/docs/metadata/overview#https-mds |
| 625 | + // Try to load MTLS-MDS creds. |
| 626 | + File rootFile = new File(MTLS_MDS_ROOT_PATH); |
| 627 | + File certKeyFile = new File(MTLS_MDS_CERT_CHAIN_AND_KEY_PATH); |
| 628 | + if (rootFile.isFile() && certKeyFile.isFile()) { |
| 629 | + // Try to connect to S2A using mTLS. |
| 630 | + ChannelCredentials mtlsToS2AChannelCredentials = null; |
| 631 | + try { |
| 632 | + mtlsToS2AChannelCredentials = |
| 633 | + createMtlsToS2AChannelCredentials(rootFile, certKeyFile, certKeyFile); |
| 634 | + } catch (IOException | GeneralSecurityException ignore) { |
| 635 | + // Fallback to plaintext-to-S2A connection on error. |
| 636 | + LOG.log( |
| 637 | + Level.WARNING, |
| 638 | + "Cannot establish an mTLS connection to S2A due to error creating MTLS to MDS TlsChannelCredentials credentials, falling back to plaintext connection to S2A: " |
| 639 | + + ignore.getMessage()); |
| 640 | + s2aChannelCredentialsObject = |
| 641 | + createPlaintextToS2AChannelCredentials(plaintextAddress); |
| 642 | + return s2aChannelCredentialsObject; |
| 643 | + } |
| 644 | + s2aChannelCredentialsObject = |
| 645 | + buildS2AChannelCredentials(mtlsAddress, mtlsToS2AChannelCredentials); |
| 646 | + return s2aChannelCredentialsObject; |
| 647 | + } else { |
| 648 | + // Fallback to plaintext-to-S2A connection if MTLS-MDS creds do not exist. |
| 649 | + LOG.log( |
| 650 | + Level.INFO, |
| 651 | + "Cannot establish an mTLS connection to S2A because MTLS to MDS credentials do not" |
| 652 | + + " exist on filesystem, falling back to plaintext connection to S2A"); |
| 653 | + s2aChannelCredentialsObject = createPlaintextToS2AChannelCredentials(plaintextAddress); |
| 654 | + return s2aChannelCredentialsObject; |
| 655 | + } |
| 656 | + } |
626 | 657 | } |
627 | | - return buildS2AChannelCredentials(mtlsAddress, mtlsToS2AChannelCredentials); |
628 | | - } else { |
629 | | - // Fallback to plaintext-to-S2A connection if MTLS-MDS creds do not exist. |
630 | | - LOG.log( |
631 | | - Level.INFO, |
632 | | - "Cannot establish an mTLS connection to S2A because MTLS to MDS credentials do not exist on filesystem, falling back to plaintext connection to S2A"); |
633 | | - return createPlaintextToS2AChannelCredentials(plaintextAddress); |
634 | 658 | } |
| 659 | + return s2aChannelCredentialsObject; |
635 | 660 | } |
636 | 661 |
|
637 | 662 | private ManagedChannel createSingleChannel() throws IOException { |
|
0 commit comments