@@ -162,6 +162,34 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP
162162 @ Nullable
163163 private final ApiFunction <ManagedChannelBuilder , ManagedChannelBuilder > channelConfigurator ;
164164
165+ // This is initialized once for the lifetime of the application. This enables re-using
166+ // channels to S2A.
167+ private static volatile ChannelCredentials s2aChannelCredentials ;
168+
169+ /**
170+ * Resets the s2aChannelCredentials of the {@link InstantiatingGrpcChannelProvider} class for
171+ * testing purposes.
172+ *
173+ * <p>This should only be called from tests.
174+ */
175+ @ VisibleForTesting
176+ static void resetS2AChannelCredentials () {
177+ synchronized (InstantiatingGrpcChannelProvider .class ) {
178+ s2aChannelCredentials = null ;
179+ }
180+ }
181+
182+ /**
183+ * Returns the s2aChannelCredentials of the {@link InstantiatingGrpcChannelProvider} class for
184+ * testing purposes.
185+ *
186+ * <p>This should only be called from tests.
187+ */
188+ @ VisibleForTesting
189+ static ChannelCredentials getS2AChannelCredentials () {
190+ return s2aChannelCredentials ;
191+ }
192+
165193 /*
166194 * Experimental feature
167195 *
@@ -609,43 +637,60 @@ ChannelCredentials createPlaintextToS2AChannelCredentials(String plaintextAddres
609637 * @return {@link ChannelCredentials} configured to use S2A to create mTLS connection.
610638 */
611639 ChannelCredentials createS2ASecuredChannelCredentials () {
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- return createPlaintextToS2AChannelCredentials (plaintextAddress );
621- }
622- // Currently, MTLS to MDS is only available on GCE. See:
623- // https://cloud.google.com/compute/docs/metadata/overview#https-mds
624- // Try to load MTLS-MDS creds.
625- File rootFile = new File (MTLS_MDS_ROOT_PATH );
626- File certKeyFile = new File (MTLS_MDS_CERT_CHAIN_AND_KEY_PATH );
627- if (rootFile .isFile () && certKeyFile .isFile ()) {
628- // Try to connect to S2A using mTLS.
629- ChannelCredentials mtlsToS2AChannelCredentials = null ;
630- try {
631- mtlsToS2AChannelCredentials =
632- createMtlsToS2AChannelCredentials (rootFile , certKeyFile , certKeyFile );
633- } catch (IOException ignore ) {
634- // Fallback to plaintext-to-S2A connection on error.
635- LOG .log (
636- Level .WARNING ,
637- "Cannot establish an mTLS connection to S2A due to error creating MTLS to MDS TlsChannelCredentials credentials, falling back to plaintext connection to S2A: "
638- + ignore .getMessage ());
639- return createPlaintextToS2AChannelCredentials (plaintextAddress );
640+ if (s2aChannelCredentials == null ) {
641+ // s2aChannelCredentials is initialized once and shared by all instances of the class.
642+ // To prevent a race on initialization, the object initialization is synchronized on the class
643+ // object.
644+ synchronized (InstantiatingGrpcChannelProvider .class ) {
645+ if (s2aChannelCredentials != null ) {
646+ return s2aChannelCredentials ;
647+ }
648+ SecureSessionAgentConfig config = s2aConfigProvider .getConfig ();
649+ String plaintextAddress = config .getPlaintextAddress ();
650+ String mtlsAddress = config .getMtlsAddress ();
651+ if (Strings .isNullOrEmpty (mtlsAddress )) {
652+ // Fallback to plaintext connection to S2A.
653+ LOG .log (
654+ Level .INFO ,
655+ "Cannot establish an mTLS connection to S2A because autoconfig endpoint did not return a mtls address to reach S2A." );
656+ s2aChannelCredentials = createPlaintextToS2AChannelCredentials (plaintextAddress );
657+ return s2aChannelCredentials ;
658+ }
659+ // Currently, MTLS to MDS is only available on GCE. See:
660+ // https://cloud.google.com/compute/docs/metadata/overview#https-mds
661+ // Try to load MTLS-MDS creds.
662+ File rootFile = new File (MTLS_MDS_ROOT_PATH );
663+ File certKeyFile = new File (MTLS_MDS_CERT_CHAIN_AND_KEY_PATH );
664+ if (rootFile .isFile () && certKeyFile .isFile ()) {
665+ // Try to connect to S2A using mTLS.
666+ ChannelCredentials mtlsToS2AChannelCredentials = null ;
667+ try {
668+ mtlsToS2AChannelCredentials =
669+ createMtlsToS2AChannelCredentials (rootFile , certKeyFile , certKeyFile );
670+ } catch (IOException ignore ) {
671+ // Fallback to plaintext-to-S2A connection on error.
672+ LOG .log (
673+ Level .WARNING ,
674+ "Cannot establish an mTLS connection to S2A due to error creating MTLS to MDS TlsChannelCredentials credentials, falling back to plaintext connection to S2A: "
675+ + ignore .getMessage ());
676+ s2aChannelCredentials = createPlaintextToS2AChannelCredentials (plaintextAddress );
677+ return s2aChannelCredentials ;
678+ }
679+ s2aChannelCredentials =
680+ buildS2AChannelCredentials (mtlsAddress , mtlsToS2AChannelCredentials );
681+ return s2aChannelCredentials ;
682+ } else {
683+ // Fallback to plaintext-to-S2A connection if MTLS-MDS creds do not exist.
684+ LOG .log (
685+ Level .INFO ,
686+ "Cannot establish an mTLS connection to S2A because MTLS to MDS credentials do not"
687+ + " exist on filesystem, falling back to plaintext connection to S2A" );
688+ s2aChannelCredentials = createPlaintextToS2AChannelCredentials (plaintextAddress );
689+ return s2aChannelCredentials ;
690+ }
640691 }
641- return buildS2AChannelCredentials (mtlsAddress , mtlsToS2AChannelCredentials );
642- } else {
643- // Fallback to plaintext-to-S2A connection if MTLS-MDS creds do not exist.
644- LOG .log (
645- Level .INFO ,
646- "Cannot establish an mTLS connection to S2A because MTLS to MDS credentials do not exist on filesystem, falling back to plaintext connection to S2A" );
647- return createPlaintextToS2AChannelCredentials (plaintextAddress );
648692 }
693+ return s2aChannelCredentials ;
649694 }
650695
651696 private ManagedChannel createSingleChannel () throws IOException {
0 commit comments