Skip to content

Commit

Permalink
feat(auth): auth library can talk to S2A over mTLS (#10634)
Browse files Browse the repository at this point in the history
xmenxk authored Aug 15, 2024
1 parent b02a9a1 commit 5250a13
Showing 6 changed files with 296 additions and 156 deletions.
82 changes: 70 additions & 12 deletions auth/internal/transport/cba.go
Original file line number Diff line number Diff line change
@@ -17,7 +17,9 @@ package transport
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"log"
"net"
"net/http"
"net/url"
@@ -44,10 +46,12 @@ const (
googleAPIUseMTLSOld = "GOOGLE_API_USE_MTLS"

universeDomainPlaceholder = "UNIVERSE_DOMAIN"

mtlsMDSRoot = "/run/google-mds-mtls/root.crt"
mtlsMDSKey = "/run/google-mds-mtls/client.key"
)

var (
mdsMTLSAutoConfigSource mtlsConfigSource
errUniverseNotSupportedMTLS = errors.New("mTLS is not supported in any universe other than googleapis.com")
)

@@ -120,7 +124,20 @@ func GetGRPCTransportCredsAndEndpoint(opts *Options) (credentials.TransportCrede
defaultTransportCreds := credentials.NewTLS(&tls.Config{
GetClientCertificate: config.clientCertSource,
})
if config.s2aAddress == "" {

var s2aAddr string
var transportCredsForS2A credentials.TransportCredentials

if config.mtlsS2AAddress != "" {
s2aAddr = config.mtlsS2AAddress
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
if err != nil {
log.Printf("Loading MTLS MDS credentials failed: %v", err)
return defaultTransportCreds, config.endpoint, nil
}
} else if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
} else {
return defaultTransportCreds, config.endpoint, nil
}

@@ -133,8 +150,9 @@ func GetGRPCTransportCredsAndEndpoint(opts *Options) (credentials.TransportCrede
}

s2aTransportCreds, err := s2a.NewClientCreds(&s2a.ClientOptions{
S2AAddress: config.s2aAddress,
FallbackOpts: fallbackOpts,
S2AAddress: s2aAddr,
TransportCreds: transportCredsForS2A,
FallbackOpts: fallbackOpts,
})
if err != nil {
// Use default if we cannot initialize S2A client transport credentials.
@@ -151,7 +169,19 @@ func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context,
return nil, nil, err
}

if config.s2aAddress == "" {
var s2aAddr string
var transportCredsForS2A credentials.TransportCredentials

if config.mtlsS2AAddress != "" {
s2aAddr = config.mtlsS2AAddress
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
if err != nil {
log.Printf("Loading MTLS MDS credentials failed: %v", err)
return config.clientCertSource, nil, nil
}
} else if config.s2aAddress != "" {
s2aAddr = config.s2aAddress
} else {
return config.clientCertSource, nil, nil
}

@@ -169,12 +199,38 @@ func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context,
}

dialTLSContextFunc := s2a.NewS2ADialTLSContextFunc(&s2a.ClientOptions{
S2AAddress: config.s2aAddress,
FallbackOpts: fallbackOpts,
S2AAddress: s2aAddr,
TransportCreds: transportCredsForS2A,
FallbackOpts: fallbackOpts,
})
return nil, dialTLSContextFunc, nil
}

func loadMTLSMDSTransportCreds(mtlsMDSRootFile, mtlsMDSKeyFile string) (credentials.TransportCredentials, error) {
rootPEM, err := os.ReadFile(mtlsMDSRootFile)
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(rootPEM)
if !ok {
return nil, errors.New("failed to load MTLS MDS root certificate")
}
// The mTLS MDS credentials are formatted as the concatenation of a PEM-encoded certificate chain
// followed by a PEM-encoded private key. For this reason, the concatenation is passed in to the
// tls.X509KeyPair function as both the certificate chain and private key arguments.
cert, err := tls.LoadX509KeyPair(mtlsMDSKeyFile, mtlsMDSKeyFile)
if err != nil {
return nil, err
}
tlsConfig := tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
}
return credentials.NewTLS(&tlsConfig), nil
}

func getTransportConfig(opts *Options) (*transportConfig, error) {
clientCertSource, err := GetClientCertificateProvider(opts)
if err != nil {
@@ -196,17 +252,17 @@ func getTransportConfig(opts *Options) (*transportConfig, error) {
return nil, errUniverseNotSupportedMTLS
}

s2aMTLSEndpoint := opts.DefaultMTLSEndpoint

s2aAddress := GetS2AAddress()
if s2aAddress == "" {
mtlsS2AAddress := GetMTLSS2AAddress()
if s2aAddress == "" && mtlsS2AAddress == "" {
return &defaultTransportConfig, nil
}
return &transportConfig{
clientCertSource: clientCertSource,
endpoint: endpoint,
s2aAddress: s2aAddress,
s2aMTLSEndpoint: s2aMTLSEndpoint,
mtlsS2AAddress: mtlsS2AAddress,
s2aMTLSEndpoint: opts.DefaultMTLSEndpoint,
}, nil
}

@@ -241,8 +297,10 @@ type transportConfig struct {
clientCertSource cert.Provider
// The corresponding endpoint to use based on client certificate source.
endpoint string
// The S2A address if it can be used, otherwise an empty string.
// The plaintext S2A address if it can be used, otherwise an empty string.
s2aAddress string
// The MTLS S2A address if it can be used, otherwise an empty string.
mtlsS2AAddress string
// The MTLS endpoint to use with S2A.
s2aMTLSEndpoint string
}
108 changes: 88 additions & 20 deletions auth/internal/transport/cba_test.go
Original file line number Diff line number Diff line change
@@ -20,7 +20,6 @@ import (
"fmt"
"net/http"
"testing"
"time"

"cloud.google.com/go/auth/internal"
"cloud.google.com/go/auth/internal/transport/cert"
@@ -50,6 +49,20 @@ var (
return string(configStr), nil
}

validConfigRespMTLSS2A = func() (string, error) {
validConfig := mtlsConfig{
S2A: &s2aAddresses{
PlaintextAddress: "",
MTLSAddress: testMTLSS2AAddr,
},
}
configStr, err := json.Marshal(validConfig)
if err != nil {
return "", err
}
return string(configStr), nil
}

errorConfigResp = func() (string, error) {
return "", fmt.Errorf("error getting config")
}
@@ -250,7 +263,7 @@ func TestGetEndpointWithClientCertSource(t *testing.T) {
}
}

func TestGetGRPCTransportConfigAndEndpoint(t *testing.T) {
func TestGetGRPCTransportConfigAndEndpoint_S2A(t *testing.T) {
testCases := []struct {
name string
opts *Options
@@ -324,11 +337,21 @@ func TestGetGRPCTransportConfigAndEndpoint(t *testing.T) {
validConfigResp,
testRegularEndpoint,
},
{
"no client cert, MTLS S2A address not empty, no MTLS MDS cert",
&Options{
DefaultMTLSEndpoint: testMTLSEndpoint,
DefaultEndpointTemplate: testEndpointTemplate,
},
validConfigRespMTLSS2A,
testRegularEndpoint,
},
}
defer setupTest(t)()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
httpGetMetadataMTLSConfig = tc.s2ARespFn
mtlsConfiguration, _ = queryConfig()
if tc.opts.ClientCertProvider != nil {
t.Setenv(googleAPIUseCertSource, "true")
} else {
@@ -338,17 +361,15 @@ func TestGetGRPCTransportConfigAndEndpoint(t *testing.T) {
if tc.want != endpoint {
t.Fatalf("want endpoint: %s, got %s", tc.want, endpoint)
}
// Let the cached MTLS config expire at the end of each test case.
time.Sleep(2 * time.Millisecond)
})
}
}

func TestGetHTTPTransportConfig_S2a(t *testing.T) {
func TestGetHTTPTransportConfig_S2A(t *testing.T) {
testCases := []struct {
name string
opts *Options
s2aFn func() (string, error)
s2ARespFn func() (string, error)
want string
isDialFnNil bool
}{
@@ -359,7 +380,7 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
DefaultEndpointTemplate: testEndpointTemplate,
ClientCertProvider: fakeClientCertSource,
},
s2aFn: validConfigResp,
s2ARespFn: validConfigResp,
want: testMTLSEndpoint,
isDialFnNil: true,
},
@@ -369,16 +390,16 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
DefaultMTLSEndpoint: testMTLSEndpoint,
DefaultEndpointTemplate: testEndpointTemplate,
},
s2aFn: validConfigResp,
want: testMTLSEndpoint,
s2ARespFn: validConfigResp,
want: testMTLSEndpoint,
},
{
name: "no client cert, S2A address empty",
opts: &Options{
DefaultMTLSEndpoint: testMTLSEndpoint,
DefaultEndpointTemplate: testEndpointTemplate,
},
s2aFn: invalidConfigResp,
s2ARespFn: invalidConfigResp,
want: testRegularEndpoint,
isDialFnNil: true,
},
@@ -389,7 +410,7 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
DefaultEndpointTemplate: testEndpointTemplate,
Endpoint: testOverrideEndpoint,
},
s2aFn: validConfigResp,
s2ARespFn: validConfigResp,
want: testOverrideEndpoint,
isDialFnNil: true,
},
@@ -399,7 +420,7 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
DefaultMTLSEndpoint: "",
DefaultEndpointTemplate: testEndpointTemplate,
},
s2aFn: validConfigResp,
s2ARespFn: validConfigResp,
want: testRegularEndpoint,
isDialFnNil: true,
},
@@ -410,15 +431,26 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
DefaultEndpointTemplate: testEndpointTemplate,
Client: http.DefaultClient,
},
s2aFn: validConfigResp,
s2ARespFn: validConfigResp,
want: testRegularEndpoint,
isDialFnNil: true,
},
{
name: "no client cert, MTLS S2A address not empty, no MTLS MDS cert",
opts: &Options{
DefaultMTLSEndpoint: testMTLSEndpoint,
DefaultEndpointTemplate: testEndpointTemplate,
},
s2ARespFn: validConfigRespMTLSS2A,
want: testRegularEndpoint,
isDialFnNil: true,
},
}
defer setupTest(t)()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
httpGetMetadataMTLSConfig = tc.s2aFn
httpGetMetadataMTLSConfig = tc.s2ARespFn
mtlsConfiguration, _ = queryConfig()
if tc.opts.ClientCertProvider != nil {
t.Setenv(googleAPIUseCertSource, "true")
} else {
@@ -431,22 +463,58 @@ func TestGetHTTPTransportConfig_S2a(t *testing.T) {
if want, got := tc.isDialFnNil, dialFunc == nil; want != got {
t.Errorf("expecting returned dialFunc is nil: [%v], got [%v]", tc.isDialFnNil, got)
}
// Let MTLS config expire at end of each test case.
time.Sleep(2 * time.Millisecond)
})
}
}

func TestLoadMTLSMDSTransportCreds(t *testing.T) {
testCases := []struct {
name string
rootFile string
keyFile string
wantErr bool
}{
{
name: "missing root file",
rootFile: "",
keyFile: "./testdata/mtls_mds_key.pem",
wantErr: true,
},
{
name: "missing key file",
rootFile: "./testdata/mtls_mds_root.pem",
keyFile: "",
wantErr: true,
},
{
name: "missing both root and key files",
rootFile: "",
keyFile: "",
wantErr: true,
},
{
name: "load credentials success",
rootFile: "./testdata/mtls_mds_root.pem",
keyFile: "./testdata/mtls_mds_key.pem",
wantErr: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := loadMTLSMDSTransportCreds(tc.rootFile, tc.keyFile)
if gotErr := err != nil; gotErr != tc.wantErr {
t.Errorf("loadMTLSMDSTransportCreds(%q, %q) got error: %v, want error: %v", tc.rootFile, tc.keyFile, gotErr, tc.wantErr)
}
})
}
}

func setupTest(t *testing.T) func() {
oldHTTPGet := httpGetMetadataMTLSConfig
oldExpiry := configExpiry

configExpiry = time.Millisecond
t.Setenv(googleAPIUseS2AEnv, "true")

return func() {
httpGetMetadataMTLSConfig = oldHTTPGet
configExpiry = oldExpiry
}
}

97 changes: 25 additions & 72 deletions auth/internal/transport/s2a.go
Original file line number Diff line number Diff line change
@@ -16,11 +16,11 @@ package transport

import (
"encoding/json"
"fmt"
"log"
"os"
"strconv"
"sync"
"time"

"cloud.google.com/go/auth/internal/transport/cert"
"cloud.google.com/go/compute/metadata"
@@ -31,41 +31,38 @@ const (
)

var (
// The period an MTLS config can be reused before needing refresh.
configExpiry = time.Hour
mtlsConfiguration *mtlsConfig

// mdsMTLSAutoConfigSource is an instance of reuseMTLSConfigSource, with metadataMTLSAutoConfig as its config source.
mtlsOnce sync.Once
)

// GetS2AAddress returns the S2A address to be reached via plaintext connection.
// Returns empty string if not set or invalid.
func GetS2AAddress() string {
c, err := getMetadataMTLSAutoConfig().Config()
if err != nil {
return ""
}
if !c.Valid() {
getMetadataMTLSAutoConfig()
if !mtlsConfiguration.valid() {
return ""
}
return c.S2A.PlaintextAddress
return mtlsConfiguration.S2A.PlaintextAddress
}

type mtlsConfigSource interface {
Config() (*mtlsConfig, error)
// GetMTLSS2AAddress returns the S2A address to be reached via MTLS connection.
// Returns empty string if not set or invalid.
func GetMTLSS2AAddress() string {
getMetadataMTLSAutoConfig()
if !mtlsConfiguration.valid() {
return ""
}
return mtlsConfiguration.S2A.MTLSAddress
}

// mtlsConfig contains the configuration for establishing MTLS connections with Google APIs.
type mtlsConfig struct {
S2A *s2aAddresses `json:"s2a"`
Expiry time.Time
S2A *s2aAddresses `json:"s2a"`
}

func (c *mtlsConfig) Valid() bool {
return c != nil && c.S2A != nil && !c.expired()
}
func (c *mtlsConfig) expired() bool {
return c.Expiry.Before(time.Now())
func (c *mtlsConfig) valid() bool {
return c != nil && c.S2A != nil
}

// s2aAddresses contains the plaintext and/or MTLS S2A addresses.
@@ -76,80 +73,36 @@ type s2aAddresses struct {
MTLSAddress string `json:"mtls_address"`
}

// getMetadataMTLSAutoConfig returns mdsMTLSAutoConfigSource, which is backed by config from MDS with auto-refresh.
func getMetadataMTLSAutoConfig() mtlsConfigSource {
func getMetadataMTLSAutoConfig() {
var err error
mtlsOnce.Do(func() {
mdsMTLSAutoConfigSource = &reuseMTLSConfigSource{
src: &metadataMTLSAutoConfig{},
mtlsConfiguration, err = queryConfig()
if err != nil {
log.Printf("Getting MTLS config failed: %v", err)
}
})
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) {
func queryConfig() (*mtlsConfig, error) {
resp, err := httpGetMetadataMTLSConfig()
if err != nil {
log.Printf("querying MTLS config from MDS endpoint failed: %v", err)
return defaultMTLSConfig(), nil
return nil, fmt.Errorf("querying MTLS config from MDS endpoint failed: %w", err)
}
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
return nil, fmt.Errorf("unmarshalling MTLS config from MDS endpoint failed: %w", err)
}

if config.S2A == nil {
log.Printf("returned MTLS config from MDS endpoint is invalid: %v", config)
return defaultMTLSConfig(), nil
return nil, fmt.Errorf("returned MTLS config from MDS endpoint is invalid: %v", config)
}

// 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),
}
}

func shouldUseS2A(clientCertSource cert.Provider, opts *Options) bool {
// If client cert is found, use that over S2A.
if clientCertSource != nil {
97 changes: 45 additions & 52 deletions auth/internal/transport/s2a_test.go
Original file line number Diff line number Diff line change
@@ -16,84 +16,77 @@ package transport

import (
"testing"
"time"
)

const (
testS2AAddr = "testS2AAddress:port"
testS2AAddr = "testS2AAddress:port"
testMTLSS2AAddr = "testMTLSS2AAddress:port"
)

func TestGetS2AAddress(t *testing.T) {
testCases := []struct {
name string
respFn func() (string, error)
want string
name string
respFn func() (string, error)
wantErr bool
wantS2AAddress string
wantMTLSS2AAddress string
}{
{
name: "test valid config",
respFn: validConfigResp,
want: testS2AAddr,
name: "test valid config with plaintext S2A address",
respFn: validConfigResp,
wantErr: false,
wantS2AAddress: testS2AAddr,
wantMTLSS2AAddress: "",
},
{
name: "test error when getting config",
respFn: errorConfigResp,
want: "",
name: "test valid config with MTLS S2A address",
respFn: validConfigRespMTLSS2A,
wantErr: false,
wantS2AAddress: "",
wantMTLSS2AAddress: testMTLSS2AAddr,
},
{
name: "test invalid config",
respFn: invalidConfigResp,
want: "",
name: "test error when getting config",
respFn: errorConfigResp,
wantErr: true,
wantS2AAddress: "",
wantMTLSS2AAddress: "",
},
{
name: "test invalid JSON response",
respFn: invalidJSONResp,
want: "",
name: "test invalid config",
respFn: invalidConfigResp,
wantErr: true,
wantS2AAddress: "",
wantMTLSS2AAddress: "",
},
{
name: "test invalid JSON response",
respFn: invalidJSONResp,
wantErr: true,
wantS2AAddress: "",
wantMTLSS2AAddress: "",
},
}

oldHTTPGet := httpGetMetadataMTLSConfig
oldExpiry := configExpiry
configExpiry = time.Millisecond
defer func() {
httpGetMetadataMTLSConfig = oldHTTPGet
configExpiry = oldExpiry
}()
defer setupTest(t)()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var err error
httpGetMetadataMTLSConfig = tc.respFn
if want, got := tc.want, GetS2AAddress(); got != want {
t.Errorf("want address [%s], got address [%s]", want, got)
mtlsConfiguration, err = queryConfig()
if gotErr := err != nil; gotErr != tc.wantErr {
t.Errorf("queryConfig() got error: %v, want error: %v", gotErr, tc.wantErr)
}
if want, got := tc.wantS2AAddress, GetS2AAddress(); got != want {
t.Errorf("want S2A address [%s], got address [%s]", want, got)
}
if want, got := tc.wantMTLSS2AAddress, GetMTLSS2AAddress(); got != want {
t.Errorf("want MTLS S2A address [%s], got address [%s]", 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)
}

func TestIsGoogleS2AEnabled(t *testing.T) {
testCases := []struct {
name string
47 changes: 47 additions & 0 deletions auth/internal/transport/testdata/mtls_mds_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
-----BEGIN CERTIFICATE-----
MIIDCDCCAfACFFlYsYCFit01ZpYmfjxpo7/6wMEbMA0GCSqGSIb3DQEBCwUAMEgx
CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UECgwGR29vZ2xlMRswGQYD
VQQDDBJ0ZXN0LXMyYS1tdGxzLXJvb3QwHhcNMjMwODIyMTY0NTE4WhcNNDMwODIy
MTY0NTE4WjA5MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExHTAbBgNVBAMMFHRl
c3QtczJhLW10bHMtY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAqrQQMyxNtmdCB+uY3szgRsfPrKC+TV9Fusnd8PfaCVuGTGcSBKM018nV2TDn
3IYFQ1HgLpGwGwOFDBb3y0o9i2/l2VJySriX1GSNX6nDmVasQlO1wuOLCP7/LRmO
7b6Kise5W0IFhYaptKyWnekn2pS0tAjimqpfn2w0U6FDGtQUqg/trQQmGtTSJHjb
A+OFd0EFC18KGP8Q+jOMaMkJRmpeEiAPyHPDoMhqQNT26RApv9j2Uzo4SuXzHH6T
cAdm1+zG+EXY/UZKX9oDkSbwIJvN+gCmNyORLalJ12gsGYOCjMd8K0mlXBqrmmbO
VHVbUm9062lhE7x59AA8DK4DoQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCPOvtL
dq2hxFHlIy0YUK8jp/DtwJZPwzx1id5FtWwd0CxBS1StIgmkHMxtkJGz1iyQLplI
je+Msd4sTsb5zZi/8kGKehi8Wj4lghp4oP30cpob41OvM68M9RC/wSOVk9igSww+
l3zof6wKRIswsi5VHrL16ruIVVoDlyFbKr8yk+cp9OPOV8hNNN7ewY9xC8OgnTt8
YtdaLe6uTplKBLW+j3GtshigRhyfkGJyPFYL4LAeDJCHlC1qmBnkyP0ijMp6vneM
E8TLavnMTMcpihWTWpyKeRkO6HDRsP4AofQAp7VAiAdSOplga+w2qgrVICV+m8MK
BTq2PBvc59T6OFLq
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqtBAzLE22Z0IH
65jezOBGx8+soL5NX0W6yd3w99oJW4ZMZxIEozTXydXZMOfchgVDUeAukbAbA4UM
FvfLSj2Lb+XZUnJKuJfUZI1fqcOZVqxCU7XC44sI/v8tGY7tvoqKx7lbQgWFhqm0
rJad6SfalLS0COKaql+fbDRToUMa1BSqD+2tBCYa1NIkeNsD44V3QQULXwoY/xD6
M4xoyQlGal4SIA/Ic8OgyGpA1PbpECm/2PZTOjhK5fMcfpNwB2bX7Mb4Rdj9Rkpf
2gORJvAgm836AKY3I5EtqUnXaCwZg4KMx3wrSaVcGquaZs5UdVtSb3TraWETvHn0
ADwMrgOhAgMBAAECggEAUccupZ1ZY4OHTi0PkNk8rpwFwTFGyeFVEf2ofkr24RnA
NnUAXEllxOUUNlcoFOz9s3kTeavg3qgqgpa0QmdAIb9LMXg+ec6CKkW7trMpGho8
LxBUWNfSoU4sKEqAvyPT0lWJVo9D/up6/avbAi6TIbOw+Djzel4ZrlHTpabxc3WT
EilXzn4q54b3MzxCQeQjcnzTieW4Q5semG2kLiXFToHIY2di01P/O8awUjgrD+uW
/Cb6H49MnHm9VPkqea1iwZeMQd6Gh5FrC7RezsBjdB1JBcfsv6PFt2ySInjB8SF+
XR5Gr3Cc5sh9s0LfprZ9Dq0rlSWmwasPMI1COK6SswKBgQDczgeWd3erQ1JX9LEI
wollawqC9y7uJhEsw1hrPqA3uqZYiLUc7Nmi4laZ12mcGoXNDS3R3XmD58qGmGaU
lxEVTb8KDVWBgw450VoBKzSMQnCP6zn4nZxTYxeqMKjDGf6TRB6TZc843qsG3eRC
k91yxrCQ/0HV6PT48C+lieDzLwKBgQDF6aNKiyrswr457undBnM1H8q/Y6xC5ZlK
UtiQdhuyBnicvz0U8WPxBY/8gha0OXWuSnBqq/z77iFVNv/zT6p9K7kM7nBGd8cB
8KO6FNbyaHWFrhCI5zNzRTH4oha0hfvUOoti09vqavCtWD4L+D/63ba1wNLKPO9o
4gWbCnUCLwKBgQC/vus372csgrnvR761LLrEJ8BpGt7WUJh5luoht7DKtHvgRleB
Vu1oVcV+s2Iy/ZVUDC3OIdZ0hcWKPK5YOxfKuEk+IXYvke+4peTTPwHTC59UW6Fs
FPK8N0FFuhvT0a8RlAY5WiAp8rPysp6WcnHMSl7qi8BQUozp4Sp/RsziYQKBgBXv
r4mzoy5a53rEYGd/L4XT4EUWZyGDEVqLlDVu4eL5lKTLDZokp08vrqXuRVX0iHap
CYzJQ2EpI8iuL/BoBB2bmwcz5n3pCMXORld5t9lmeqA2it6hwbIlGUTVsm6P6zm6
w3hQwy9YaxTLkxUAjxbfPEEo/jQsTNzzMGve3NlBAoGAbgJExpDyMDnaD2Vi5eyr
63b54BsqeLHqxJmADifyRCj7G1SJMm3zMKkNNOS0vsXgoiId973STFf1XQiojiv8
Slbxyv5rczcY0n3LOuQYcM5OzsjzpNFZsT2dDnMfNRUF3rx3Geu/FuJ9scF1b00r
fVMrcL3jSf/W1Xh4TgtyoU8=
-----END PRIVATE KEY-----
21 changes: 21 additions & 0 deletions auth/internal/transport/testdata/mtls_mds_root.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDcTCCAlmgAwIBAgIUDUkgI+2FZtuUHyUUi0ZBH7JvN00wDQYJKoZIhvcNAQEL
BQAwSDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQKDAZHb29nbGUx
GzAZBgNVBAMMEnRlc3QtczJhLW10bHMtcm9vdDAeFw0yMzA4MjEyMTI5MTVaFw00
MzA4MjEyMTI5MTVaMEgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UE
CgwGR29vZ2xlMRswGQYDVQQDDBJ0ZXN0LXMyYS1tdGxzLXJvb3QwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbFEQfpvla27bATedrN4BAWsI9GSwSnJLW
QWzXcnAk6cKxQBAhnaKHRxHY8ttLhNTtxQeub894CLzJvHE/0xDhuMzjtCCCZ7i2
r08tKZ1KcEzPJCPNlxlzAXPA45XU3LRlbGvju/PBPhm6n1hCEKTNI/KETJ5DEaYg
Cf2LcXVsl/zW20MwDZ+e2w/9a2a6n6DdpW1ekOR550hXAUOIxvmXRBeYeGLFvp1n
rQgZBhRaxP03UB+PQD2oMi/4mfsS96uGCXdzzX8qV46O8m132HUbnA/wagIwboEe
d7Bx237dERDyHw5GFnll7orgA0FOtoEufXdeQxWVvTjO0+PVPgsvAgMBAAGjUzBR
MB0GA1UdDgQWBBRyMtg/yutV8hw8vOq0i8x0eBQi7DAfBgNVHSMEGDAWgBRyMtg/
yutV8hw8vOq0i8x0eBQi7DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQArN/gdqWMxd5Rvq2eJMTp6I4RepJOT7Go4sMsRsy1caJqqcoS2EvREDZMN
XNEBcyQBB5kYd6TCcZGoLnEtWYXQ4jjEiXG1g7/+rWxyqw0ZYuP7FWzuHg3Uor/x
fApbEKwptP5ywVc+33h4qreGcqXkVCCn+sAcstGgrqubdGZW2T5gazUMyammOOuN
9IWL1PbvXmgEKD+80NUIrk09zanYyrElGdU/zw/kUbZ3Jf6WUBtJGhTzRQ1qZeKa
VnpCbLoG3vObEB8mxDUAlIzwAtfvw4U32BVIZA8xrocz6OOoAnSW1bTlo3EOIo/G
MTV7jmY9TBPtfhRuO/cG650+F+cw
-----END CERTIFICATE-----

0 comments on commit 5250a13

Please sign in to comment.