From 983292e92e05f27a2a4432a26c3ea7c9ecedd404 Mon Sep 17 00:00:00 2001
From: Kui Xu <xmenxk@google.com>
Date: Thu, 23 Feb 2023 21:10:02 +0000
Subject: [PATCH] feat(all): s2a-go integration

---
 go.mod                        |   2 +
 go.sum                        |  44 +++++
 internal/{dca.go => cba.go}   | 123 ++++++++++++-
 internal/cba_test.go          | 320 ++++++++++++++++++++++++++++++++++
 internal/cert/default_cert.go |   2 +-
 internal/creds.go             |   2 +-
 internal/dca_test.go          | 124 -------------
 internal/s2a.go               | 136 +++++++++++++++
 internal/s2a_test.go          | 109 ++++++++++++
 transport/grpc/dial.go        |   9 +-
 transport/http/dial.go        |  11 +-
 11 files changed, 742 insertions(+), 140 deletions(-)
 rename internal/{dca.go => cba.go} (54%)
 create mode 100644 internal/cba_test.go
 delete mode 100644 internal/dca_test.go
 create mode 100644 internal/s2a.go
 create mode 100644 internal/s2a_test.go

diff --git a/go.mod b/go.mod
index f414f2f4bb8..5b17b6ba4c8 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.19
 require (
 	cloud.google.com/go/compute/metadata v0.2.3
 	github.com/google/go-cmp v0.5.9
+	github.com/google/s2a-go v0.1.0
 	github.com/google/uuid v1.3.0
 	github.com/googleapis/enterprise-certificate-proxy v0.2.3
 	github.com/googleapis/gax-go/v2 v2.7.1
@@ -22,6 +23,7 @@ require (
 	cloud.google.com/go/compute v1.18.0 // indirect
 	github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
+	golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
 	golang.org/x/sys v0.6.0 // indirect
 	golang.org/x/text v0.8.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 37b49359e8d..ae26628d4aa 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,5 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys=
 cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
 cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
@@ -6,15 +7,25 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
 cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -22,12 +33,14 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@@ -41,6 +54,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/s2a-go v0.1.0 h1:3Qm0liEiCErViKERO2Su5wp+9PfMRiuS6XB5FvpKnYQ=
+github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -48,48 +63,70 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9
 github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
 github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A=
 github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
 golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
 golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
 golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -98,12 +135,14 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
 google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
@@ -111,7 +150,10 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
 google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -128,6 +170,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
 google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/dca.go b/internal/cba.go
similarity index 54%
rename from internal/dca.go
rename to internal/cba.go
index 204a3fd2f3f..f3515f912a7 100644
--- a/internal/dca.go
+++ b/internal/cba.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package dca contains utils for implementing Device Certificate
+// cba.go (certificate-based access) contains utils for implementing Device Certificate
 // Authentication according to https://google.aip.dev/auth/4114
 //
 // The overall logic for DCA is as follows:
@@ -18,6 +18,10 @@
 //  2. If the user specifies an mTLS endpoint override but client certificate is not
 //     available, we will not fail-fast, but let backend throw error when connecting.
 //
+// If no DCA is specified, the code will try mTLS as default with credentials
+// held by the Secure Session Agent, which is part of Google's cloud infrastructure.
+// https://google.aip.dev/auth/4115
+//
 // We would like to avoid introducing client-side logic that parses whether the
 // endpoint override is an mTLS url, since the url pattern may change at anytime.
 //
@@ -28,11 +32,18 @@
 package internal
 
 import (
+	"context"
+	"crypto/tls"
+	"flag"
+	"net"
 	"net/url"
 	"os"
 	"strings"
 
+	"github.com/google/s2a-go"
+	"github.com/google/s2a-go/fallback"
 	"google.golang.org/api/internal/cert"
+	"google.golang.org/grpc/credentials"
 )
 
 const (
@@ -41,10 +52,12 @@ const (
 	mTLSModeAuto   = "auto"
 )
 
-// GetClientCertificateSourceAndEndpoint is a convenience function that invokes
+var useS2A = flag.Bool("use_s2a", false, "Experimental: if true, the code will try MTLS with S2A as the default for transport security.")
+
+// getClientCertificateSourceAndEndpoint is a convenience function that invokes
 // getClientCertificateSource and getEndpoint sequentially and returns the client
 // cert source and endpoint as a tuple.
-func GetClientCertificateSourceAndEndpoint(settings *DialSettings) (cert.Source, string, error) {
+func getClientCertificateSourceAndEndpoint(settings *DialSettings) (cert.Source, string, error) {
 	clientCertSource, err := getClientCertificateSource(settings)
 	if err != nil {
 		return nil, "", err
@@ -56,6 +69,39 @@ func GetClientCertificateSourceAndEndpoint(settings *DialSettings) (cert.Source,
 	return clientCertSource, endpoint, nil
 }
 
+// configureTransportSecurity returns four values:
+//
+//	the client certificate source,
+//	the corresponding endpoint to use based on client certificate source,
+//	the S2A address if it can be used, otherwise returns empty string,
+//	the endpoint to use with S2A.
+func configureTransportSecurity(settings *DialSettings) (cert.Source, string, string, string, error) {
+	clientCertSource, endpoint, err := getClientCertificateSourceAndEndpoint(settings)
+	if err != nil {
+		return nil, "", "", "", err
+	}
+
+	// Check the global flag to determine whether to use S2A.
+	if !*useS2A {
+		return clientCertSource, endpoint, "", "", nil
+	}
+
+	// If client cert is found, use that over S2A.
+	if clientCertSource != nil {
+		return clientCertSource, endpoint, "", "", nil
+	}
+	s2aMTLSEndpoint := settings.DefaultMTLSEndpoint
+	// If there is endpoint override, honor it.
+	if settings.Endpoint != "" {
+		s2aMTLSEndpoint = endpoint
+	}
+	s2aAddress := GetS2AAddress()
+	if s2aAddress == "" || !mtlsEndpointEnabled() {
+		return clientCertSource, endpoint, "", "", nil
+	}
+	return clientCertSource, endpoint, s2aAddress, s2aMTLSEndpoint, nil
+}
+
 // getClientCertificateSource returns a default client certificate source, if
 // not provided by the user.
 //
@@ -142,3 +188,74 @@ func fixScheme(baseURL string) string {
 	}
 	return baseURL
 }
+
+// ConfigureGRPCTransportSecurityAndEndpoint returns an instance of credentials.TransportCredentials, and the
+// corresponding endpoint to use for GRPC client.
+func ConfigureGRPCTransportSecurityAndEndpoint(settings *DialSettings) (credentials.TransportCredentials, string, error) {
+	clientCertSource, endpoint, s2aAddress, s2aEndpoint, err := configureTransportSecurity(settings)
+	if err != nil {
+		return nil, "", err
+	}
+
+	defaultTransportCreds := credentials.NewTLS(&tls.Config{
+		GetClientCertificate: clientCertSource,
+	})
+	if s2aAddress == "" {
+		return defaultTransportCreds, endpoint, nil
+	}
+
+	var fallbackOpts *s2a.FallbackOptions
+	// In case of S2A failure, fall back to the endpoint that would've been used without S2A.
+	if fallbackHandshake, err := fallback.DefaultFallbackClientHandshakeFunc(endpoint); err == nil {
+		fallbackOpts = &s2a.FallbackOptions{
+			FallbackClientHandshakeFunc: fallbackHandshake,
+		}
+	}
+
+	s2aTransportCreds, err := s2a.NewClientCreds(&s2a.ClientOptions{
+		S2AAddress:   s2aAddress,
+		FallbackOpts: fallbackOpts,
+	})
+	if err != nil {
+		// Use default if we cannot initialize S2A client transport credentials.
+		return defaultTransportCreds, endpoint, nil
+	}
+	return s2aTransportCreds, s2aEndpoint, nil
+}
+
+// ConfigureHTTPTransportSecurityAndEndpoint returns a client certificate source, a function for dialing MTLS with S2A,
+// and the endpoint to use for HTTP client.
+func ConfigureHTTPTransportSecurityAndEndpoint(settings *DialSettings) (cert.Source, func(context.Context, string, string) (net.Conn, error), string, error) {
+	clientCertSource, endpoint, s2aAddress, s2aEndpoint, err := configureTransportSecurity(settings)
+	if err != nil {
+		return nil, nil, "", err
+	}
+
+	if s2aAddress == "" {
+		return clientCertSource, nil, endpoint, nil
+	}
+
+	var fallbackOpts *s2a.FallbackOptions
+	// In case of S2A failure, fall back to the endpoint that would've been used without S2A.
+	if fallbackUrl, err := url.Parse(endpoint); err == nil {
+		if fallbackDialer, fallbackServerAddr, err := fallback.DefaultFallbackDialerAndAddress(fallbackUrl.Hostname()); err == nil {
+			fallbackOpts = &s2a.FallbackOptions{
+				FallbackDialer: &s2a.FallbackDialer{
+					Dialer:     fallbackDialer,
+					ServerAddr: fallbackServerAddr,
+				},
+			}
+		}
+	}
+
+	dialTLSContextFunc := s2a.NewS2ADialTLSContextFunc(&s2a.ClientOptions{
+		S2AAddress:   s2aAddress,
+		FallbackOpts: fallbackOpts,
+	})
+	return nil, dialTLSContextFunc, s2aEndpoint, nil
+}
+
+var mtlsEndpointEnabled = func() bool {
+	// TODO(xmenxk): determine this via discovery config.
+	return true
+}
diff --git a/internal/cba_test.go b/internal/cba_test.go
new file mode 100644
index 00000000000..6e6dbd18455
--- /dev/null
+++ b/internal/cba_test.go
@@ -0,0 +1,320 @@
+// Copyright 2020 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+	"crypto/tls"
+	"os"
+	"testing"
+	"time"
+
+	"google.golang.org/api/internal/cert"
+)
+
+const (
+	testMTLSEndpoint     = "test.mtls.endpoint"
+	testRegularEndpoint  = "test.endpoint"
+	testOverrideEndpoint = "test.override.endpoint"
+)
+
+var dummyClientCertSource = func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { return nil, nil }
+var testDefaultCertSource = func() (cert.Source, error) { return nil, nil }
+
+func TestGetEndpoint(t *testing.T) {
+	testCases := []struct {
+		UserEndpoint    string
+		DefaultEndpoint string
+		Want            string
+		WantErr         bool
+	}{
+		{
+			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
+			Want:            "https://foo.googleapis.com/bar/baz",
+		},
+		{
+			UserEndpoint:    "myhost:3999",
+			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
+			Want:            "https://myhost:3999/bar/baz",
+		},
+		{
+			UserEndpoint:    "https://host/path/to/bar",
+			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
+			Want:            "https://host/path/to/bar",
+		},
+		{
+			UserEndpoint:    "host:123",
+			DefaultEndpoint: "",
+			Want:            "host:123",
+		},
+		{
+			UserEndpoint:    "host:123",
+			DefaultEndpoint: "default:443",
+			Want:            "host:123",
+		},
+		{
+			UserEndpoint:    "host:123",
+			DefaultEndpoint: "default:443/bar/baz",
+			Want:            "host:123/bar/baz",
+		},
+	}
+
+	for _, tc := range testCases {
+		got, err := getEndpoint(&DialSettings{
+			Endpoint:        tc.UserEndpoint,
+			DefaultEndpoint: tc.DefaultEndpoint,
+		}, nil)
+		if tc.WantErr && err == nil {
+			t.Errorf("want err, got nil err")
+			continue
+		}
+		if !tc.WantErr && err != nil {
+			t.Errorf("want nil err, got %v", err)
+			continue
+		}
+		if tc.Want != got {
+			t.Errorf("getEndpoint(%q, %q): got %v; want %v", tc.UserEndpoint, tc.DefaultEndpoint, got, tc.Want)
+		}
+	}
+}
+
+func TestGetEndpointWithClientCertSource(t *testing.T) {
+
+	testCases := []struct {
+		UserEndpoint        string
+		DefaultEndpoint     string
+		DefaultMTLSEndpoint string
+		Want                string
+		WantErr             bool
+	}{
+		{
+			DefaultEndpoint:     "https://foo.googleapis.com/bar/baz",
+			DefaultMTLSEndpoint: "https://foo.mtls.googleapis.com/bar/baz",
+			Want:                "https://foo.mtls.googleapis.com/bar/baz",
+		},
+		{
+			DefaultEndpoint:     "https://staging-foo.sandbox.googleapis.com/bar/baz",
+			DefaultMTLSEndpoint: "https://staging-foo.mtls.sandbox.googleapis.com/bar/baz",
+			Want:                "https://staging-foo.mtls.sandbox.googleapis.com/bar/baz",
+		},
+		{
+			UserEndpoint:    "myhost:3999",
+			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
+			Want:            "https://myhost:3999/bar/baz",
+		},
+		{
+			UserEndpoint:    "https://host/path/to/bar",
+			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
+			Want:            "https://host/path/to/bar",
+		},
+		{
+			UserEndpoint:    "host:port",
+			DefaultEndpoint: "",
+			Want:            "host:port",
+		},
+	}
+
+	for _, tc := range testCases {
+		got, err := getEndpoint(&DialSettings{
+			Endpoint:            tc.UserEndpoint,
+			DefaultEndpoint:     tc.DefaultEndpoint,
+			DefaultMTLSEndpoint: tc.DefaultMTLSEndpoint,
+		}, dummyClientCertSource)
+		if tc.WantErr && err == nil {
+			t.Errorf("want err, got nil err")
+			continue
+		}
+		if !tc.WantErr && err != nil {
+			t.Errorf("want nil err, got %v", err)
+			continue
+		}
+		if tc.Want != got {
+			t.Errorf("getEndpoint(%q, %q): got %v; want %v", tc.UserEndpoint, tc.DefaultEndpoint, got, tc.Want)
+		}
+	}
+}
+
+func TestConfigureGRPCTransportSecurityAndEndpoint(t *testing.T) {
+	testCases := []struct {
+		Desc          string
+		InputSettings *DialSettings
+		S2ARespFunc   func() (string, error)
+		MTLSEnabled   func() bool
+		WantEndpoint  string
+	}{
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address not empty",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testMTLSEndpoint,
+		},
+		{
+			"has client cert",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+				ClientCertSource:    dummyClientCertSource,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testMTLSEndpoint,
+		},
+		{
+			"no client cert, endpoint is not MTLS enabled",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			validConfigResp,
+			func() bool { return false },
+			testRegularEndpoint,
+		},
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address empty",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			invalidConfigResp,
+			func() bool { return true },
+			testRegularEndpoint,
+		},
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address not empty, override endpoint",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+				Endpoint:            testOverrideEndpoint,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testOverrideEndpoint,
+		},
+	}
+	defer setupTest()()
+
+	for _, tc := range testCases {
+		httpGetMetadataMTLSConfig = tc.S2ARespFunc
+		mtlsEndpointEnabled = tc.MTLSEnabled
+		_, endpoint, _ := ConfigureGRPCTransportSecurityAndEndpoint(tc.InputSettings)
+		if tc.WantEndpoint != endpoint {
+			t.Errorf("%s: want endpoint: [%s], got [%s]", tc.Desc, tc.WantEndpoint, endpoint)
+		}
+		// Let the cached MTLS config expire at the end of each test case.
+		time.Sleep(2 * time.Millisecond)
+	}
+}
+
+func TestConfigureHTTPTransportSecurityAndEndpoint(t *testing.T) {
+	cert.DefaultSource = func() (cert.Source, error) { return nil, nil }
+	testCases := []struct {
+		Desc          string
+		InputSettings *DialSettings
+		S2ARespFunc   func() (string, error)
+		MTLSEnabled   func() bool
+		WantEndpoint  string
+		DialFuncNil   bool
+	}{
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address not empty",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testMTLSEndpoint,
+			false,
+		},
+		{
+			"has client cert",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+				ClientCertSource:    dummyClientCertSource,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testMTLSEndpoint,
+			true,
+		},
+		{
+			"no client cert, endpoint is not MTLS enabled",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			validConfigResp,
+			func() bool { return false },
+			testRegularEndpoint,
+			true,
+		},
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address empty",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+			},
+			invalidConfigResp,
+			func() bool { return true },
+			testRegularEndpoint,
+			true,
+		},
+		{
+			"no client cert, endpoint is MTLS enabled, S2A address not empty, override endpoint",
+			&DialSettings{
+				DefaultMTLSEndpoint: testMTLSEndpoint,
+				DefaultEndpoint:     testRegularEndpoint,
+				Endpoint:            testOverrideEndpoint,
+			},
+			validConfigResp,
+			func() bool { return true },
+			testOverrideEndpoint,
+			false,
+		},
+	}
+
+	defer setupTest()()
+
+	for _, tc := range testCases {
+		httpGetMetadataMTLSConfig = tc.S2ARespFunc
+		mtlsEndpointEnabled = tc.MTLSEnabled
+		_, dialFunc, endpoint, _ := ConfigureHTTPTransportSecurityAndEndpoint(tc.InputSettings)
+		if tc.WantEndpoint != endpoint {
+			t.Errorf("%s: want endpoint: [%s], got [%s]", tc.Desc, tc.WantEndpoint, endpoint)
+		}
+		if want, got := tc.DialFuncNil, dialFunc == nil; want != got {
+			t.Errorf("%s: expecting returned dialFunc is nil: [%v], got [%v]", tc.Desc, tc.DialFuncNil, got)
+		}
+		// Let MTLS config expire at end of each test case.
+		time.Sleep(2 * time.Millisecond)
+	}
+}
+
+func setupTest() func() {
+	oldDefaultMTLSEnabled := mtlsEndpointEnabled
+	oldHTTPGet := httpGetMetadataMTLSConfig
+	oldExpiry := configExpiry
+	oldUseS2A := *useS2A
+	oldUseClientCert := os.Getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE")
+	oldCertDefaultSource := cert.DefaultSource
+
+	configExpiry = time.Millisecond
+	*useS2A = true
+	os.Setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "true")
+	cert.DefaultSource = testDefaultCertSource
+
+	return func() {
+		httpGetMetadataMTLSConfig = oldHTTPGet
+		mtlsEndpointEnabled = oldDefaultMTLSEnabled
+		configExpiry = oldExpiry
+		*useS2A = oldUseS2A
+		os.Setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", oldUseClientCert)
+		cert.DefaultSource = oldCertDefaultSource
+	}
+}
diff --git a/internal/cert/default_cert.go b/internal/cert/default_cert.go
index 21d0251531c..3666aad60fa 100644
--- a/internal/cert/default_cert.go
+++ b/internal/cert/default_cert.go
@@ -44,7 +44,7 @@ var errSourceUnavailable = errors.New("certificate source is unavailable")
 //
 // If neither source is available (due to missing configurations), a nil Source and a nil Error are
 // returned to indicate that a default certificate source is unavailable.
-func DefaultSource() (Source, error) {
+var DefaultSource = func() (Source, error) {
 	defaultCert.once.Do(func() {
 		defaultCert.source, defaultCert.err = NewEnterpriseCertificateProxySource("")
 		if errors.Is(defaultCert.err, errSourceUnavailable) {
diff --git a/internal/creds.go b/internal/creds.go
index 63c66092203..fd89a2785fd 100644
--- a/internal/creds.go
+++ b/internal/creds.go
@@ -92,7 +92,7 @@ func credentialsFromJSON(ctx context.Context, data []byte, ds *DialSettings) (*g
 
 	// Determine configurations for the OAuth2 transport, which is separate from the API transport.
 	// The OAuth2 transport and endpoint will be configured for mTLS if applicable.
-	clientCertSource, oauth2Endpoint, err := GetClientCertificateSourceAndEndpoint(oauth2DialSettings(ds))
+	clientCertSource, oauth2Endpoint, err := getClientCertificateSourceAndEndpoint(oauth2DialSettings(ds))
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/dca_test.go b/internal/dca_test.go
deleted file mode 100644
index 6ff7ad91531..00000000000
--- a/internal/dca_test.go
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2020 Google LLC.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package internal
-
-import (
-	"testing"
-
-	"crypto/tls"
-)
-
-func TestGetEndpoint(t *testing.T) {
-	testCases := []struct {
-		UserEndpoint    string
-		DefaultEndpoint string
-		Want            string
-		WantErr         bool
-	}{
-		{
-			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
-			Want:            "https://foo.googleapis.com/bar/baz",
-		},
-		{
-			UserEndpoint:    "myhost:3999",
-			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
-			Want:            "https://myhost:3999/bar/baz",
-		},
-		{
-			UserEndpoint:    "https://host/path/to/bar",
-			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
-			Want:            "https://host/path/to/bar",
-		},
-		{
-			UserEndpoint:    "host:123",
-			DefaultEndpoint: "",
-			Want:            "host:123",
-		},
-		{
-			UserEndpoint:    "host:123",
-			DefaultEndpoint: "default:443",
-			Want:            "host:123",
-		},
-		{
-			UserEndpoint:    "host:123",
-			DefaultEndpoint: "default:443/bar/baz",
-			Want:            "host:123/bar/baz",
-		},
-	}
-
-	for _, tc := range testCases {
-		got, err := getEndpoint(&DialSettings{
-			Endpoint:        tc.UserEndpoint,
-			DefaultEndpoint: tc.DefaultEndpoint,
-		}, nil)
-		if tc.WantErr && err == nil {
-			t.Errorf("want err, got nil err")
-			continue
-		}
-		if !tc.WantErr && err != nil {
-			t.Errorf("want nil err, got %v", err)
-			continue
-		}
-		if tc.Want != got {
-			t.Errorf("getEndpoint(%q, %q): got %v; want %v", tc.UserEndpoint, tc.DefaultEndpoint, got, tc.Want)
-		}
-	}
-}
-
-func TestGetEndpointWithClientCertSource(t *testing.T) {
-	dummyClientCertSource := func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { return nil, nil }
-	testCases := []struct {
-		UserEndpoint        string
-		DefaultEndpoint     string
-		DefaultMTLSEndpoint string
-		Want                string
-		WantErr             bool
-	}{
-		{
-			DefaultEndpoint:     "https://foo.googleapis.com/bar/baz",
-			DefaultMTLSEndpoint: "https://foo.mtls.googleapis.com/bar/baz",
-			Want:                "https://foo.mtls.googleapis.com/bar/baz",
-		},
-		{
-			DefaultEndpoint:     "https://staging-foo.sandbox.googleapis.com/bar/baz",
-			DefaultMTLSEndpoint: "https://staging-foo.mtls.sandbox.googleapis.com/bar/baz",
-			Want:                "https://staging-foo.mtls.sandbox.googleapis.com/bar/baz",
-		},
-		{
-			UserEndpoint:    "myhost:3999",
-			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
-			Want:            "https://myhost:3999/bar/baz",
-		},
-		{
-			UserEndpoint:    "https://host/path/to/bar",
-			DefaultEndpoint: "https://foo.googleapis.com/bar/baz",
-			Want:            "https://host/path/to/bar",
-		},
-		{
-			UserEndpoint:    "host:port",
-			DefaultEndpoint: "",
-			Want:            "host:port",
-		},
-	}
-
-	for _, tc := range testCases {
-		got, err := getEndpoint(&DialSettings{
-			Endpoint:            tc.UserEndpoint,
-			DefaultEndpoint:     tc.DefaultEndpoint,
-			DefaultMTLSEndpoint: tc.DefaultMTLSEndpoint,
-		}, dummyClientCertSource)
-		if tc.WantErr && err == nil {
-			t.Errorf("want err, got nil err")
-			continue
-		}
-		if !tc.WantErr && err != nil {
-			t.Errorf("want nil err, got %v", err)
-			continue
-		}
-		if tc.Want != got {
-			t.Errorf("getEndpoint(%q, %q): got %v; want %v", tc.UserEndpoint, tc.DefaultEndpoint, got, tc.Want)
-		}
-	}
-}
diff --git a/internal/s2a.go b/internal/s2a.go
new file mode 100644
index 00000000000..c5b421f5544
--- /dev/null
+++ b/internal/s2a.go
@@ -0,0 +1,136 @@
+// Copyright 2023 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+	"encoding/json"
+	"log"
+	"sync"
+	"time"
+
+	"cloud.google.com/go/compute/metadata"
+)
+
+const configEndpointSuffix = "googleAutoMtlsConfiguration"
+
+// The period an MTLS config can be reused before needing refresh.
+var configExpiry = time.Hour
+
+// GetS2AAddress returns the S2A address to be reached via plaintext connection.
+func GetS2AAddress() string {
+	c, err := getMetadataMTLSAutoConfig().Config()
+	if err != nil {
+		return ""
+	}
+	if !c.Valid() {
+		return ""
+	}
+	return c.S2A.PlaintextAddress
+}
+
+type mtlsConfigSource interface {
+	Config() (*mtlsConfig, error)
+}
+
+// mdsMTLSAutoConfigSource is an instance of reuseMTLSConfigSource, with metadataMTLSAutoConfig as its config source.
+var (
+	mdsMTLSAutoConfigSource mtlsConfigSource
+	once                    sync.Once
+)
+
+// getMetadataMTLSAutoConfig returns mdsMTLSAutoConfigSource, which is backed by config from MDS with auto-refresh.
+func getMetadataMTLSAutoConfig() mtlsConfigSource {
+	once.Do(func() {
+		mdsMTLSAutoConfigSource = &reuseMTLSConfigSource{
+			src: &metadataMTLSAutoConfig{},
+		}
+	})
+	return mdsMTLSAutoConfigSource
+}
+
+// reuseMTLSConfigSource caches a valid version of mtlsConfig, and uses `src` to refresh upon config expiry.
+// It implements the mtlsConfigSource interface, so calling Config() on it returns an mtlsConfig.
+type reuseMTLSConfigSource struct {
+	src    mtlsConfigSource // src.Config() is called when config is expired
+	mu     sync.Mutex       // mutex guards config
+	config *mtlsConfig      // cached config
+}
+
+func (cs *reuseMTLSConfigSource) Config() (*mtlsConfig, error) {
+	cs.mu.Lock()
+	defer cs.mu.Unlock()
+
+	if cs.config.Valid() {
+		return cs.config, nil
+	}
+	c, err := cs.src.Config()
+	if err != nil {
+		return nil, err
+	}
+	cs.config = c
+	return c, nil
+}
+
+// metadataMTLSAutoConfig is an implementation of the interface mtlsConfigSource
+// It has the logic to query MDS and return an mtlsConfig
+type metadataMTLSAutoConfig struct{}
+
+var httpGetMetadataMTLSConfig = func() (string, error) {
+	return metadata.Get(configEndpointSuffix)
+}
+
+func (cs *metadataMTLSAutoConfig) Config() (*mtlsConfig, error) {
+	resp, err := httpGetMetadataMTLSConfig()
+	if err != nil {
+		log.Printf("querying MTLS config from MDS endpoint failed: %v", err)
+		return defaultMTLSConfig(), nil
+	}
+	var config mtlsConfig
+	err = json.Unmarshal([]byte(resp), &config)
+	if err != nil {
+		log.Printf("unmarshalling MTLS config from MDS endpoint failed: %v", err)
+		return defaultMTLSConfig(), nil
+	}
+
+	if config.S2A == nil {
+		log.Printf("returned MTLS config from MDS endpoint is invalid: %v", config)
+		return defaultMTLSConfig(), nil
+	}
+
+	// set new expiry
+	config.Expiry = time.Now().Add(configExpiry)
+	return &config, nil
+}
+
+func defaultMTLSConfig() *mtlsConfig {
+	return &mtlsConfig{
+		S2A: &s2aAddresses{
+			PlaintextAddress: "",
+			MTLSAddress:      "",
+		},
+		Expiry: time.Now().Add(configExpiry),
+	}
+}
+
+// s2aAddresses contains the plaintext and/or MTLS S2A addresses.
+type s2aAddresses struct {
+	// PlaintextAddress is the plaintext address to reach S2A
+	PlaintextAddress string `json:"plaintext_address"`
+	// MTLSAddress is the MTLS address to reach S2A
+	MTLSAddress string `json:"mtls_address"`
+}
+
+// mtlsConfig contains the configuration for establishing MTLS connections with Google APIs.
+type mtlsConfig struct {
+	S2A    *s2aAddresses `json:"s2a"`
+	Expiry time.Time
+}
+
+func (c *mtlsConfig) Valid() bool {
+	return c != nil && c.S2A != nil && !c.expired()
+}
+func (c *mtlsConfig) expired() bool {
+	return c.Expiry.Before(time.Now())
+}
diff --git a/internal/s2a_test.go b/internal/s2a_test.go
new file mode 100644
index 00000000000..811eabb55f8
--- /dev/null
+++ b/internal/s2a_test.go
@@ -0,0 +1,109 @@
+// Copyright 2023 Google LLC.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+	"encoding/json"
+	"fmt"
+	"testing"
+	"time"
+)
+
+const testS2AAddr = "testS2AAddress:port"
+
+var validConfigResp = func() (string, error) {
+	validConfig := mtlsConfig{
+		S2A: &s2aAddresses{
+			PlaintextAddress: testS2AAddr,
+			MTLSAddress:      "",
+		},
+	}
+	configStr, err := json.Marshal(validConfig)
+	if err != nil {
+		return "", err
+	}
+	return string(configStr), nil
+}
+
+var errorConfigResp = func() (string, error) {
+	return "", fmt.Errorf("error getting config")
+}
+
+var invalidConfigResp = func() (string, error) {
+	return "{}", nil
+}
+
+var invalidJSONResp = func() (string, error) {
+	return "test", nil
+}
+
+func TestGetS2AAddress(t *testing.T) {
+	testCases := []struct {
+		Desc     string
+		RespFunc func() (string, error)
+		Want     string
+	}{
+		{
+			Desc:     "test valid config",
+			RespFunc: validConfigResp,
+			Want:     testS2AAddr,
+		},
+		{
+			Desc:     "test error when getting config",
+			RespFunc: errorConfigResp,
+			Want:     "",
+		},
+		{
+			Desc:     "test invalid config",
+			RespFunc: invalidConfigResp,
+			Want:     "",
+		},
+		{
+			Desc:     "test invalid JSON response",
+			RespFunc: invalidJSONResp,
+			Want:     "",
+		},
+	}
+
+	oldHTTPGet := httpGetMetadataMTLSConfig
+	oldExpiry := configExpiry
+	configExpiry = time.Millisecond
+	defer func() {
+		httpGetMetadataMTLSConfig = oldHTTPGet
+		configExpiry = oldExpiry
+	}()
+	for _, tc := range testCases {
+		httpGetMetadataMTLSConfig = tc.RespFunc
+		if want, got := tc.Want, GetS2AAddress(); got != want {
+			t.Errorf("%s: want address [%s], got address [%s]", tc.Desc, want, got)
+		}
+		// Let the MTLS config expire at the end of each test case.
+		time.Sleep(2 * time.Millisecond)
+	}
+}
+
+func TestMTLSConfigExpiry(t *testing.T) {
+	oldHTTPGet := httpGetMetadataMTLSConfig
+	oldExpiry := configExpiry
+	configExpiry = 1 * time.Second
+	defer func() {
+		httpGetMetadataMTLSConfig = oldHTTPGet
+		configExpiry = oldExpiry
+	}()
+	httpGetMetadataMTLSConfig = validConfigResp
+	if got, want := GetS2AAddress(), testS2AAddr; got != want {
+		t.Errorf("expected address: [%s], got [%s]", want, got)
+	}
+	httpGetMetadataMTLSConfig = invalidConfigResp
+	if got, want := GetS2AAddress(), testS2AAddr; got != want {
+		t.Errorf("cached config should still be valid, expected address: [%s], got [%s]", want, got)
+	}
+	time.Sleep(1 * time.Second)
+	if got, want := GetS2AAddress(), ""; got != want {
+		t.Errorf("config should be refreshed, expected address: [%s], got [%s]", want, got)
+	}
+	// Let the MTLS config expire before running other tests.
+	time.Sleep(1 * time.Second)
+}
diff --git a/transport/grpc/dial.go b/transport/grpc/dial.go
index 20c94fa640b..597d8e9c364 100644
--- a/transport/grpc/dial.go
+++ b/transport/grpc/dial.go
@@ -9,7 +9,6 @@ package grpc
 
 import (
 	"context"
-	"crypto/tls"
 	"errors"
 	"log"
 	"net"
@@ -22,7 +21,6 @@ import (
 	"google.golang.org/api/internal"
 	"google.golang.org/api/option"
 	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials"
 	grpcgoogle "google.golang.org/grpc/credentials/google"
 	grpcinsecure "google.golang.org/grpc/credentials/insecure"
 	"google.golang.org/grpc/credentials/oauth"
@@ -122,18 +120,13 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C
 	if o.GRPCConn != nil {
 		return o.GRPCConn, nil
 	}
-	clientCertSource, endpoint, err := internal.GetClientCertificateSourceAndEndpoint(o)
+	transportCreds, endpoint, err := internal.ConfigureGRPCTransportSecurityAndEndpoint(o)
 	if err != nil {
 		return nil, err
 	}
 
-	var transportCreds credentials.TransportCredentials
 	if insecure {
 		transportCreds = grpcinsecure.NewCredentials()
-	} else {
-		transportCreds = credentials.NewTLS(&tls.Config{
-			GetClientCertificate: clientCertSource,
-		})
 	}
 
 	// Initialize gRPC dial options with transport-level security options.
diff --git a/transport/http/dial.go b/transport/http/dial.go
index 403509d08f6..f3f72e0e717 100644
--- a/transport/http/dial.go
+++ b/transport/http/dial.go
@@ -33,7 +33,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*http.Client,
 	if err != nil {
 		return nil, "", err
 	}
-	clientCertSource, endpoint, err := internal.GetClientCertificateSourceAndEndpoint(settings)
+	clientCertSource, dialTLSContext, endpoint, err := internal.ConfigureHTTPTransportSecurityAndEndpoint(settings)
 	if err != nil {
 		return nil, "", err
 	}
@@ -41,7 +41,8 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*http.Client,
 	if settings.HTTPClient != nil {
 		return settings.HTTPClient, endpoint, nil
 	}
-	trans, err := newTransport(ctx, defaultBaseTransport(ctx, clientCertSource), settings)
+
+	trans, err := newTransport(ctx, defaultBaseTransport(ctx, clientCertSource, dialTLSContext), settings)
 	if err != nil {
 		return nil, "", err
 	}
@@ -152,7 +153,7 @@ var appengineUrlfetchHook func(context.Context) http.RoundTripper
 // Otherwise, use a default transport, taking most defaults from
 // http.DefaultTransport.
 // If TLSCertificate is available, set TLSClientConfig as well.
-func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source) http.RoundTripper {
+func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source, dialTLSContext func(context.Context, string, string) (net.Conn, error)) http.RoundTripper {
 	if appengineUrlfetchHook != nil {
 		return appengineUrlfetchHook(ctx)
 	}
@@ -171,6 +172,10 @@ func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source) htt
 			GetClientCertificate: clientCertSource,
 		}
 	}
+	if dialTLSContext != nil {
+		// If DialTLSContext is set, TLSClientConfig wil be ignored
+		trans.DialTLSContext = dialTLSContext
+	}
 
 	configureHTTP2(trans)