diff --git a/config/http_config.go b/config/http_config.go index 80502585..d6806c4f 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -18,10 +18,10 @@ package config import ( "bytes" "context" - "crypto/sha256" "crypto/tls" "crypto/x509" "encoding/json" + "errors" "fmt" "io/ioutil" "net" @@ -424,12 +424,14 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT return nil, err } - if len(cfg.TLSConfig.CAFile) == 0 { + if len(cfg.TLSConfig.getCAName()) == 0 { // No need for a RoundTripper that reloads the CA file automatically. return newRT(tlsConfig) } - return NewTLSRoundTripper(tlsConfig, cfg.TLSConfig.CAFile, newRT) + certStore, _ := newCertStore(string(cfg.TLSConfig.CA), cfg.TLSConfig.CAFile) + + return NewTLSRoundTripper(tlsConfig, certStore, newRT) } type authorizationCredentialsRoundTripper struct { @@ -626,13 +628,11 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { // If a CA cert is provided then let's read it in so we can validate the // scrape target's certificate properly. - if len(cfg.CAFile) > 0 { - b, err := readCAFile(cfg.CAFile) - if err != nil { - return nil, err - } - if !updateRootCA(tlsConfig, b) { - return nil, fmt.Errorf("unable to use specified CA cert %s", cfg.CAFile) + if ca, err := cfg.getCA(); err != nil { + return nil, fmt.Errorf("unable to get specified CA %s: %w", cfg.getCAName(), err) + } else if ca != nil { + if !updateRootCA(tlsConfig, ca) { + return nil, fmt.Errorf("unable to use specified CA %s", cfg.getCAName()) } } @@ -640,11 +640,11 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { tlsConfig.ServerName = cfg.ServerName } // If a client cert & key is provided then configure TLS config accordingly. - if len(cfg.CertFile) > 0 && len(cfg.KeyFile) == 0 { - return nil, fmt.Errorf("client cert file %q specified without client key file", cfg.CertFile) - } else if len(cfg.KeyFile) > 0 && len(cfg.CertFile) == 0 { - return nil, fmt.Errorf("client key file %q specified without client cert file", cfg.KeyFile) - } else if len(cfg.CertFile) > 0 && len(cfg.KeyFile) > 0 { + if certName, keyName := cfg.getCertName(), cfg.getKeyName(); len(certName) > 0 && len(keyName) == 0 { + return nil, fmt.Errorf("client cert file %q specified without client key file", certName) + } else if len(keyName) > 0 && len(certName) == 0 { + return nil, fmt.Errorf("client key file %q specified without client cert file", keyName) + } else if len(certName) > 0 && len(keyName) > 0 { // Verify that client cert and key are valid. if _, err := cfg.getClientCertificate(nil); err != nil { return nil, err @@ -658,9 +658,15 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) { // TLSConfig configures the options for TLS connections. type TLSConfig struct { // The CA cert to use for the targets. + CA Secret `yaml:"ca,omitempty" json:"ca,omitempty"` + // The CA cert file to use for the targets. CAFile string `yaml:"ca_file,omitempty" json:"ca_file,omitempty"` + // The client cert for the targets. + Cert Secret `yaml:"cert,omitempty" json:"cert,omitempty"` // The client cert file for the targets. CertFile string `yaml:"cert_file,omitempty" json:"cert_file,omitempty"` + // The client key for the targets. + Key Secret `yaml:"key,omitempty" json:"key,omitempty"` // The client key file for the targets. KeyFile string `yaml:"key_file,omitempty" json:"key_file,omitempty"` // Used to verify the hostname for the targets. @@ -674,9 +680,15 @@ func (c *TLSConfig) SetDirectory(dir string) { if c == nil { return } - c.CAFile = JoinDir(dir, c.CAFile) - c.CertFile = JoinDir(dir, c.CertFile) - c.KeyFile = JoinDir(dir, c.KeyFile) + if len(c.CAFile) > 0 { + c.CAFile = JoinDir(dir, c.CAFile) + } + if len(c.CertFile) > 0 { + c.CertFile = JoinDir(dir, c.CertFile) + } + if len(c.KeyFile) > 0 { + c.KeyFile = JoinDir(dir, c.KeyFile) + } } // UnmarshalYAML implements the yaml.Unmarshaler interface. @@ -685,20 +697,81 @@ func (c *TLSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { return unmarshal((*plain)(c)) } +func getCertificate(inline Secret, filename string) ([]byte, error) { + if len(inline) != 0 { + return []byte(inline), nil + } + + if len(filename) != 0 { + return readCertificateFile(filename) + } + + return nil, nil +} + +func getCertificateName(inline Secret, filename string) string { + if len(inline) > 0 { + return "" + } else if len(filename) > 0 { + return filename + } + + return "" +} + +func (c *TLSConfig) getCA() ([]byte, error) { + return getCertificate(c.CA, c.CAFile) +} + +func (c *TLSConfig) getCAName() string { + return getCertificateName(c.CA, c.CAFile) +} + +func (c *TLSConfig) getCert() ([]byte, error) { + return getCertificate(c.Cert, c.CertFile) +} + +func (c *TLSConfig) getCertName() string { + return getCertificateName(c.Cert, c.CertFile) +} + +func (c *TLSConfig) getKey() ([]byte, error) { + return getCertificate(c.Key, c.KeyFile) +} + +func (c *TLSConfig) getKeyName() string { + return getCertificateName(c.Key, c.KeyFile) +} + // getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate. func (c *TLSConfig) getClientCertificate(*tls.CertificateRequestInfo) (*tls.Certificate, error) { - cert, err := tls.LoadX509KeyPair(c.CertFile, c.KeyFile) + var ( + certBlob, keyBlob []byte + err error + ) + + certBlob, err = c.getCert() + if err != nil { + return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.getCertName(), c.getKeyName(), err) + } + + keyBlob, err = c.getKey() if err != nil { - return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.CertFile, c.KeyFile, err) + return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.getCertName(), c.getKeyName(), err) + } + + cert, err := tls.X509KeyPair(certBlob, keyBlob) + if err != nil { + return nil, fmt.Errorf("unable to use specified client cert (%s) & key (%s): %s", c.getCertName(), c.getKeyName(), err) } return &cert, nil } -// readCAFile reads the CA cert file from disk. -func readCAFile(f string) ([]byte, error) { +// readCertificateFile reads the CA cert file from disk. +func readCertificateFile(f string) ([]byte, error) { data, err := ioutil.ReadFile(f) if err != nil { - return nil, fmt.Errorf("unable to load specified CA cert %s: %s", f, err) + return nil, fmt.Errorf("unable to load specified certificate file %s: %s", f, err) } return data, nil } @@ -713,26 +786,80 @@ func updateRootCA(cfg *tls.Config, b []byte) bool { return true } +// CertGetter defines how to access certificates. +type CertGetter interface { + // GetCert returns the corresponding certificate, whether or not + // it's been updated, or an error if it's not possible to + // retrieve the certificate. + GetCert() (cert []byte, updated bool, err error) +} + +// newCertStore creates a CertGetter that provides access to the +// certificate stored in the specified filename or the inline +// certificate cert. +func newCertStore(cert, filename string) (CertGetter, error) { + if len(filename) > 0 { + return &fileCertStore{filename: filename}, nil + } else if len(cert) > 0 { + return inlineCertStore{cert: []byte(cert)}, nil + } else { + return nil, errors.New("invalid certificate inputs") + } +} + +// inlineCertStore implements a CertGetter that never changes. +type inlineCertStore struct { + cert []byte +} + +func (s inlineCertStore) GetCert() ([]byte, bool, error) { + return s.cert, false, nil +} + +// fileCertStore loads a certificate from a filename each time the +// certificate is requested. +type fileCertStore struct { + filename string + mtx sync.Mutex // mtx protects accesses to cert + cert []byte +} + +func (s *fileCertStore) GetCert() ([]byte, bool, error) { + updated := false + newCert, err := readCertificateFile(s.filename) + if err != nil { + return nil, false, err + } + + s.mtx.Lock() + if !bytes.Equal(s.cert, newCert) { + s.cert = newCert + updated = true + } + s.mtx.Unlock() + + return newCert, updated, nil +} + // tlsRoundTripper is a RoundTripper that updates automatically its TLS // configuration whenever the content of the CA file changes. type tlsRoundTripper struct { - caFile string + certStore CertGetter // newRT returns a new RoundTripper. newRT func(*tls.Config) (http.RoundTripper, error) - mtx sync.RWMutex - rt http.RoundTripper - hashCAFile []byte - tlsConfig *tls.Config + mtx sync.RWMutex + rt http.RoundTripper + tlsConfig *tls.Config } func NewTLSRoundTripper( cfg *tls.Config, - caFile string, + certStore CertGetter, newRT func(*tls.Config) (http.RoundTripper, error), ) (http.RoundTripper, error) { t := &tlsRoundTripper{ - caFile: caFile, + certStore: certStore, newRT: newRT, tlsConfig: cfg, } @@ -743,7 +870,7 @@ func NewTLSRoundTripper( } t.rt = rt - _, t.hashCAFile, err = t.getCAWithHash() + _, _, err = t.certStore.GetCert() if err != nil { return nil, err } @@ -751,28 +878,17 @@ func NewTLSRoundTripper( return t, nil } -func (t *tlsRoundTripper) getCAWithHash() ([]byte, []byte, error) { - b, err := readCAFile(t.caFile) - if err != nil { - return nil, nil, err - } - h := sha256.Sum256(b) - return b, h[:], nil - -} - // RoundTrip implements the http.RoundTrip interface. func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - b, h, err := t.getCAWithHash() + b, updated, err := t.certStore.GetCert() if err != nil { return nil, err } t.mtx.RLock() - equal := bytes.Equal(h[:], t.hashCAFile) rt := t.rt t.mtx.RUnlock() - if equal { + if !updated { // The CA cert hasn't changed, use the existing RoundTripper. return rt.RoundTrip(req) } @@ -780,7 +896,7 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // Create a new RoundTripper. tlsConfig := t.tlsConfig.Clone() if !updateRootCA(tlsConfig, b) { - return nil, fmt.Errorf("unable to use specified CA cert %s", t.caFile) + return nil, errors.New("unable to use specified CA cert") } rt, err = t.newRT(tlsConfig) if err != nil { @@ -790,7 +906,6 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { t.mtx.Lock() t.rt = rt - t.hashCAFile = h[:] t.mtx.Unlock() return rt.RoundTrip(req) diff --git a/config/http_config_test.go b/config/http_config_test.go index 49b0aa36..1c534323 100644 --- a/config/http_config_test.go +++ b/config/http_config_test.go @@ -16,6 +16,7 @@ package config import ( + "bytes" "context" "crypto/tls" "crypto/x509" @@ -46,7 +47,7 @@ const ( ServerKeyPath = "testdata/server.key" ClientCertificatePath = "testdata/client.crt" ClientKeyNoPassPath = "testdata/client-no-pass.key" - InvalidCA = "testdata/client-no-pass.key" + InvalidCAPath = "testdata/client-no-pass.key" WrongClientCertPath = "testdata/self-signed-client.crt" WrongClientKeyPath = "testdata/self-signed-client.key" EmptyFile = "testdata/empty" @@ -68,6 +69,13 @@ const ( ExpectedPassword = "42" ) +var ( + TLSCAChain = mustLoadTestSecretFromFile("testdata/tls-ca-chain.pem") + ClientCertificate = mustLoadTestSecretFromFile("testdata/client.crt") + ClientKeyNoPass = mustLoadTestSecretFromFile("testdata/client-no-pass.key") + InvalidCA = mustLoadTestSecretFromFile("testdata/client-no-pass.key") +) + var invalidHTTPClientConfigs = []struct { httpClientConfigFile string errMsg string @@ -154,7 +162,7 @@ func TestNewClientFromConfig(t *testing.T) { clientConfig HTTPClientConfig handler func(w http.ResponseWriter, r *http.Request) }{ - { + { // cert file, key file clientConfig: HTTPClientConfig{ TLSConfig: TLSConfig{ CAFile: "", @@ -166,7 +174,43 @@ func TestNewClientFromConfig(t *testing.T) { handler: func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, ExpectedMessage) }, - }, { + }, { // inline cert, key file + clientConfig: HTTPClientConfig{ + TLSConfig: TLSConfig{ + CAFile: "", + Cert: ClientCertificate, + KeyFile: ClientKeyNoPassPath, + ServerName: "", + InsecureSkipVerify: true}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, ExpectedMessage) + }, + }, { // cert file, inline key + clientConfig: HTTPClientConfig{ + TLSConfig: TLSConfig{ + CAFile: "", + CertFile: ClientCertificatePath, + Key: ClientKeyNoPass, + ServerName: "", + InsecureSkipVerify: true}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, ExpectedMessage) + }, + }, { // inline cert, inline key + clientConfig: HTTPClientConfig{ + TLSConfig: TLSConfig{ + CAFile: "", + Cert: ClientCertificate, + Key: ClientKeyNoPass, + ServerName: "", + InsecureSkipVerify: true}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, ExpectedMessage) + }, + }, { // CA file clientConfig: HTTPClientConfig{ TLSConfig: TLSConfig{ CAFile: TLSCAChainPath, @@ -178,6 +222,18 @@ func TestNewClientFromConfig(t *testing.T) { handler: func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, ExpectedMessage) }, + }, { // inline CA + clientConfig: HTTPClientConfig{ + TLSConfig: TLSConfig{ + CA: TLSCAChain, + CertFile: ClientCertificatePath, + KeyFile: ClientKeyNoPassPath, + ServerName: "", + InsecureSkipVerify: false}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, ExpectedMessage) + }, }, { clientConfig: HTTPClientConfig{ BearerToken: BearerToken, @@ -413,15 +469,23 @@ func TestNewClientFromInvalidConfig(t *testing.T) { CAFile: MissingCA, InsecureSkipVerify: true}, }, - errorMsg: fmt.Sprintf("unable to load specified CA cert %s:", MissingCA), + errorMsg: fmt.Sprintf("unable to load specified certificate file %s:", MissingCA), }, { clientConfig: HTTPClientConfig{ TLSConfig: TLSConfig{ - CAFile: InvalidCA, + CAFile: InvalidCAPath, InsecureSkipVerify: true}, }, - errorMsg: fmt.Sprintf("unable to use specified CA cert %s", InvalidCA), + errorMsg: "unable to use specified CA", + }, + { + clientConfig: HTTPClientConfig{ + TLSConfig: TLSConfig{ + CA: InvalidCA, + InsecureSkipVerify: true}, + }, + errorMsg: "unable to use specified CA", }, } @@ -577,57 +641,71 @@ func TestBearerAuthFileRoundTripper(t *testing.T) { } func TestTLSConfig(t *testing.T) { - configTLSConfig := TLSConfig{ - CAFile: TLSCAChainPath, - CertFile: ClientCertificatePath, - KeyFile: ClientKeyNoPassPath, - ServerName: "localhost", - InsecureSkipVerify: false} - - tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath) - if err != nil { - t.Fatalf("Can't read the CA certificate chain (%s)", - TLSCAChainPath) + testcases := map[string]TLSConfig{ + "filesystem": { + CAFile: TLSCAChainPath, + CertFile: ClientCertificatePath, + KeyFile: ClientKeyNoPassPath, + ServerName: "localhost", + InsecureSkipVerify: false, + }, + "inline": { + CA: mustLoadTestSecretFromFile(TLSCAChainPath), + Cert: mustLoadTestSecretFromFile(ClientCertificatePath), + Key: mustLoadTestSecretFromFile(ClientKeyNoPassPath), + ServerName: "localhost", + InsecureSkipVerify: false, + }, } - rootCAs := x509.NewCertPool() - rootCAs.AppendCertsFromPEM(tlsCAChain) - expectedTLSConfig := &tls.Config{ - RootCAs: rootCAs, - ServerName: configTLSConfig.ServerName, - InsecureSkipVerify: configTLSConfig.InsecureSkipVerify} + for name, configTLSConfig := range testcases { + t.Run(name, func(t *testing.T) { + tlsCAChain, err := ioutil.ReadFile(TLSCAChainPath) + if err != nil { + t.Fatalf("Can't read the CA certificate chain (%s)", + TLSCAChainPath) + } + rootCAs := x509.NewCertPool() + rootCAs.AppendCertsFromPEM(tlsCAChain) - tlsConfig, err := NewTLSConfig(&configTLSConfig) - if err != nil { - t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err) - } + expectedTLSConfig := &tls.Config{ + RootCAs: rootCAs, + ServerName: configTLSConfig.ServerName, + InsecureSkipVerify: configTLSConfig.InsecureSkipVerify} - clientCertificate, err := tls.LoadX509KeyPair(ClientCertificatePath, ClientKeyNoPassPath) - if err != nil { - t.Fatalf("Can't load the client key pair ('%s' and '%s'). Reason: %s", - ClientCertificatePath, ClientKeyNoPassPath, err) - } - cert, err := tlsConfig.GetClientCertificate(nil) - if err != nil { - t.Fatalf("unexpected error returned by tlsConfig.GetClientCertificate(): %s", err) - } - if !reflect.DeepEqual(cert, &clientCertificate) { - t.Fatalf("Unexpected client certificate result: \n\n%+v\n expected\n\n%+v", cert, clientCertificate) - } + tlsConfig, err := NewTLSConfig(&configTLSConfig) + if err != nil { + t.Fatalf("Can't create a new TLS Config from a configuration (%s).", err) + } - // tlsConfig.rootCAs.LazyCerts contains functions getCert() in go 1.16, which are - // never equal. Compare the Subjects instead. - if !reflect.DeepEqual(tlsConfig.RootCAs.Subjects(), expectedTLSConfig.RootCAs.Subjects()) { - t.Fatalf("Unexpected RootCAs result: \n\n%+v\n expected\n\n%+v", tlsConfig.RootCAs.Subjects(), expectedTLSConfig.RootCAs.Subjects()) - } - tlsConfig.RootCAs = nil - expectedTLSConfig.RootCAs = nil + clientCertificate, err := tls.LoadX509KeyPair(ClientCertificatePath, ClientKeyNoPassPath) + if err != nil { + t.Fatalf("Can't load the client key pair ('%s' and '%s'). Reason: %s", + ClientCertificatePath, ClientKeyNoPassPath, err) + } + cert, err := tlsConfig.GetClientCertificate(nil) + if err != nil { + t.Fatalf("unexpected error returned by tlsConfig.GetClientCertificate(): %s", err) + } + if !reflect.DeepEqual(cert, &clientCertificate) { + t.Fatalf("Unexpected client certificate result: \n\n%+v\n expected\n\n%+v", cert, clientCertificate) + } - // Non-nil functions are never equal. - tlsConfig.GetClientCertificate = nil + // tlsConfig.rootCAs.LazyCerts contains functions getCert() in go 1.16, which are + // never equal. Compare the Subjects instead. + if !reflect.DeepEqual(tlsConfig.RootCAs.Subjects(), expectedTLSConfig.RootCAs.Subjects()) { + t.Fatalf("Unexpected RootCAs result: \n\n%+v\n expected\n\n%+v", tlsConfig.RootCAs.Subjects(), expectedTLSConfig.RootCAs.Subjects()) + } + tlsConfig.RootCAs = nil + expectedTLSConfig.RootCAs = nil - if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) { - t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig) + // Non-nil functions are never equal. + tlsConfig.GetClientCertificate = nil + + if !reflect.DeepEqual(tlsConfig, expectedTLSConfig) { + t.Fatalf("Unexpected TLS Config result: \n\n%+v\n expected\n\n%+v", tlsConfig, expectedTLSConfig) + } + }) } } @@ -662,7 +740,7 @@ func TestTLSConfigInvalidCA(t *testing.T) { KeyFile: "", ServerName: "", InsecureSkipVerify: false}, - errorMessage: fmt.Sprintf("unable to load specified CA cert %s:", MissingCA), + errorMessage: fmt.Sprintf("unable to load specified certificate file %s:", MissingCA), }, { configTLSConfig: TLSConfig{ CAFile: "", @@ -772,6 +850,43 @@ func TestBasicAuthPasswordFile(t *testing.T) { } } +// TestTLSConfigFile checks that a configuration containing inlined +// certificates can be loaded, and that the certificate is correctly +// passed to the HTTP client's roudtripper. +func TestTLSConfigFile(t *testing.T) { + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.tlsconfig.good.yml") + if err != nil { + t.Fatalf("Error loading HTTP client config: %v", err) + } + + client, err := NewClientFromConfig(*cfg, "test") + if err != nil { + t.Fatalf("Error creating HTTP Client: %v", err) + } + + rt, ok := client.Transport.(*tlsRoundTripper) + if !ok { + t.Fatalf("Error casting to TLS transport, %v", client.Transport) + } + + buf, updated, err := rt.certStore.GetCert() + if err != nil { + t.Fatalf("Error getting certificate from TLS transport: %s", err) + } + + if len(buf) == 0 { + t.Fatal("Unexpected empty certificate from TLS transport") + } + + if !bytes.Equal(buf, []byte(cfg.TLSConfig.CA)) { + t.Fatal("Expecting configuration CA to match certificate in TLS transport") + } + + if updated { + t.Fatal("Unexpected updated certificate from TLS transport") + } +} + func getCertificateBlobs(t *testing.T) map[string][]byte { files := []string{ TLSCAChainPath, @@ -1418,3 +1533,11 @@ func TestUnmarshalURL(t *testing.T) { t.Fatalf("URL not properly unmarshaled in YAML, got '%s'", u.String()) } } + +func mustLoadTestSecretFromFile(fn string) Secret { + b, err := ioutil.ReadFile(fn) + if err != nil { + panic(err) + } + return Secret(b) +} diff --git a/config/testdata/http.conf.tlsconfig.good.yml b/config/testdata/http.conf.tlsconfig.good.yml new file mode 100644 index 00000000..4f71783e --- /dev/null +++ b/config/testdata/http.conf.tlsconfig.good.yml @@ -0,0 +1,294 @@ +proxy_url: "http://remote.host" +tls_config: + # this is config/testdata/tls-ca-chain.pem + ca: !!binary | + Q2VydGlmaWNhdGU6CiAgICBEYXRhOgogICAgICAgIFZlcnNpb246IDMgKDB4MikKICAgICAgICBT + ZXJpYWwgTnVtYmVyOiAyICgweDIpCiAgICAgICAgU2lnbmF0dXJlIEFsZ29yaXRobTogc2hhMVdp + dGhSU0FFbmNyeXB0aW9uCiAgICAgICAgSXNzdWVyOiBDPVVTLCBPPVByb21ldGhldXMsIE9VPVBy + b21ldGhldXMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5LCBDTj1Qcm9tZXRoZXVzIFJvb3QgQ0EKICAg + ICAgICBWYWxpZGl0eQogICAgICAgICAgICBOb3QgQmVmb3JlOiBBcHIgIDUgMDg6MDA6MzcgMjAx + OSBHTVQKICAgICAgICAgICAgTm90IEFmdGVyIDogTWFyIDI2IDA4OjAwOjM3IDIwNTkgR01UCiAg + ICAgICAgU3ViamVjdDogQz1VUywgTz1Qcm9tZXRoZXVzLCBPVT1Qcm9tZXRoZXVzIENlcnRpZmlj + YXRlIEF1dGhvcml0eSwgQ049UHJvbWV0aGV1cyBUTFMgQ0EKICAgICAgICBTdWJqZWN0IFB1Ymxp + YyBLZXkgSW5mbzoKICAgICAgICAgICAgUHVibGljIEtleSBBbGdvcml0aG06IHJzYUVuY3J5cHRp + b24KICAgICAgICAgICAgICAgIFJTQSBQdWJsaWMtS2V5OiAoMjA0OCBiaXQpCiAgICAgICAgICAg + ICAgICBNb2R1bHVzOgogICAgICAgICAgICAgICAgICAgIDAwOmFhOmQyOjM0OjZiOmVkOmYxOmY0 + OjAxOjA4OmU1OjAwOjlmOjc1OmM4OgogICAgICAgICAgICAgICAgICAgIGJhOmZjOjRiOjcyOmM2 + OjA0OjkzOmFmOmYxOmY2OmI1OmNlOjAxOjBkOmM2OgogICAgICAgICAgICAgICAgICAgIGJkOmQz + OjE2Ojk4OjlkOmU1OjUxOjU2OjEyOjU4OjE2OmVlOjE4OjZlOmYwOgogICAgICAgICAgICAgICAg + ICAgIDY4OmE5OjQyOjE2OjY1OmNmOmUzOjMxOmY1OjkwOjc5OjlkOjEzOjMyOjg3OgogICAgICAg + ICAgICAgICAgICAgIDNiOjFmOjY1OmZkOjg0Ojg4OmE0OjU2OjNkOjI2OjU0OjY5OjA1OjI3OjVh + OgogICAgICAgICAgICAgICAgICAgIGVhOjg5OjAyOmU3OjMxOjliOjdkOjdmOjc2OjkzOjU0Ojcw + OmJjOjE3OjkyOgogICAgICAgICAgICAgICAgICAgIDA2OjlmOjlmOjkwOjRhOjhhOmNmOjgyOmE3 + OjdiOjdjOjcxOmM0OmZhOjM0OgogICAgICAgICAgICAgICAgICAgIDU2OjAwOjMyOjFhOjg1OmM1 + OmY4OmU0OjRhOjYzOjQzOjM3OjlkOjYwOjg0OgogICAgICAgICAgICAgICAgICAgIDRkOjc4OjZl + Ojg3OjEyOmM0OjJiOjFmOjkzOmE1OmZlOmNjOjVlOmYxOmRmOgogICAgICAgICAgICAgICAgICAg + IGMxOjk3OmZmOmI3OjNlOjIwOjM4OjFkOjcxOjE1OjExOmVjOjZjOjdhOmNjOgogICAgICAgICAg + ICAgICAgICAgIDBlOjg3OjUyOjMxOmIxOmI5Ojc0OmMzOjA3OjFjOjQyOjRiOjFlOmMxOjE3Ogog + ICAgICAgICAgICAgICAgICAgIGJjOmU0OjEzOmI3OmIwOjIwOjJlOmM0OjA3OjkzOmJkOmE4OjEx + OmY5OmRhOgogICAgICAgICAgICAgICAgICAgIGE3OmQwOmRmOjRhOjQ4OmJlOjliOjZkOjY1OmMz + OmFlOjU4OjU2OmMwOjlmOgogICAgICAgICAgICAgICAgICAgIDE3OmM1OmQ4OjMyOmIxOjA0OjIy + OmZiOjViOjE4OmY2OjIwOjEwOjUwOmVjOgogICAgICAgICAgICAgICAgICAgIDJkOjEwOjRmOmNj + OjQ4OjhmOmYyOjc1OmRkOjMzOmE0OjBlOmY1OjU1OmRhOgogICAgICAgICAgICAgICAgICAgIDJj + Ojg5OmExOjNhOjUyOmJiOjExOjExOjBiOjk3OjI3OjE3OjczOjM1OmRhOgogICAgICAgICAgICAg + ICAgICAgIDEwOjcxOmIzOjlmOmE4OjQyOjkxOmU2OjNhOjY2OjAwOmY5OmU1OjExOjhmOgogICAg + ICAgICAgICAgICAgICAgIDViOjU3CiAgICAgICAgICAgICAgICBFeHBvbmVudDogNjU1MzcgKDB4 + MTAwMDEpCiAgICAgICAgWDUwOXYzIGV4dGVuc2lvbnM6CiAgICAgICAgICAgIFg1MDl2MyBLZXkg + VXNhZ2U6IGNyaXRpY2FsCiAgICAgICAgICAgICAgICBDZXJ0aWZpY2F0ZSBTaWduLCBDUkwgU2ln + bgogICAgICAgICAgICBYNTA5djMgQmFzaWMgQ29uc3RyYWludHM6IGNyaXRpY2FsCiAgICAgICAg + ICAgICAgICBDQTpUUlVFLCBwYXRobGVuOjAKICAgICAgICAgICAgWDUwOXYzIFN1YmplY3QgS2V5 + IElkZW50aWZpZXI6IAogICAgICAgICAgICAgICAgNEQ6MDI6QkY6NzE6OTU6NkE6QUE6NTg6QzU6 + OUM6Qjg6ODM6Njc6NUU6NjQ6MTY6OTk6RTE6MkE6OUUKICAgICAgICAgICAgWDUwOXYzIEF1dGhv + cml0eSBLZXkgSWRlbnRpZmllcjogCiAgICAgICAgICAgICAgICBrZXlpZDozQzoxRTpBODpDNjo0 + QzowNTo0RDoyMDpFQzo4ODpEQjoyOTpENDo3QjpGOToxMjo1RDpDRTpFQToxQQoKICAgICAgICAg + ICAgQXV0aG9yaXR5IEluZm9ybWF0aW9uIEFjY2VzczogCiAgICAgICAgICAgICAgICBDQSBJc3N1 + ZXJzIC0gVVJJOmh0dHBzOi8vZXhhbXBsZS5jb20vY2Evcm9vdC1jYS5jZXIKCiAgICAgICAgICAg + IFg1MDl2MyBDUkwgRGlzdHJpYnV0aW9uIFBvaW50czogCgogICAgICAgICAgICAgICAgRnVsbCBO + YW1lOgogICAgICAgICAgICAgICAgICBVUkk6aHR0cHM6Ly9leGFtcGxlLmNvbS9jYS9yb290LWNh + LmNybAoKICAgIFNpZ25hdHVyZSBBbGdvcml0aG06IHNoYTFXaXRoUlNBRW5jcnlwdGlvbgogICAg + ICAgICA2MzpmYzpiYTozMDphNTowNTpkNjo3NjoxNDpmMTo3NzozODpiMTo0MTo2Zjo4MTpkOTpi + NDoKICAgICAgICAgMDI6ZmQ6YmM6ZTU6ZjY6ZDk6ZTY6NzM6ZTA6NzE6Y2Y6NGM6ZmI6MTM6YjU6 + NmI6YmQ6Yjk6CiAgICAgICAgIGM2OmY2OjI4OjE4OjM2OmUxOjhjOmQ5OjkzOmIzOjc4OjRhOjNk + OjM5OjFiOmY0OmZiOjY5OgogICAgICAgICA3NToyNDphZTplMTphMDoyZjo5NDowNTpiZjoxMDoz + YzozZTpkMjoyYjphODpmMzozMToyNToKICAgICAgICAgMmU6ZWQ6MTM6YWQ6NjA6NWQ6MjI6OWE6 + MjY6MTU6MjA6ODY6OTg6NzM6NGM6ZjY6NGI6NDg6CiAgICAgICAgIGI4OjFmOjY3OmJhOjRlOmM5 + OjQ3OmVkOjg1OmRjOjM4OmRjOjAyOjBjOmZiOjU0OmQ1OjJlOgogICAgICAgICA2YzpiNDo5NTox + ODo1MTpkMTphZTplYTplODpmYjpiNDoxOTo1MDowNDpiYzozMTo3ZTo1MToKICAgICAgICAgOWU6 + ODU6Mjk6NGQ6Yzg6Zjc6MjY6ZDY6ZDY6OGQ6MzU6MmQ6OWU6ZTI6MDY6MTY6Mzg6ZTI6CiAgICAg + ICAgIDU2OjgwOmVjOmYzOmEzOjM0OmUzOjI4OmM0OmU4OjEwOmQwOjhhOmE2OjZmOjIwOjlhOmI5 + OgogICAgICAgICBkYzpiOTo5MDo2YjpiYTo4YToyNzoyYzoyOTo3MjoyODo1NTplNzo1OTphNjph + Nzo5MDplYzoKICAgICAgICAgMzI6ZTg6ZDA6MjY6NGE6YzE6NDQ6ZGQ6MjA6YmY6ZGM6NGQ6MWU6 + N2U6Y2M6ZTU6YTI6NWI6CiAgICAgICAgIGU4OmRmOjNkOjRiOjAxOmFhOjQ4OjU2OjE3OmU5OjI5 + OmQ4OjcxOjgzOjA1OjM2OjhjOjExOgogICAgICAgICA0Zjo3NzpiODo5NToyMDpiNzpjNzoyMTow + NjpjMjo4Nzo5NzpiNDo2YjpkMzpmNzoyMzpiYToKICAgICAgICAgNGQ6NWY6MTU6ZDE6MGM6NGQ6 + NmU6ZjE6NmE6OWQ6NTc6NWM6MDI6NmE6ZDc6MzE6MTg6ZWY6CiAgICAgICAgIDVjOmZjOmY4OjA0 + Ci0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFTFRDQ0F4V2dBd0lCQWdJQkFqQU5CZ2tx + aGtpRzl3MEJBUVVGQURCcU1Rc3dDUVlEVlFRR0V3SlZVekVUCk1CRUdBMVVFQ2d3S1VISnZiV1Yw + YUdWMWN6RXBNQ2NHQTFVRUN3d2dVSEp2YldWMGFHVjFjeUJEWlhKMGFXWnAKWTJGMFpTQkJkWFJv + YjNKcGRIa3hHekFaQmdOVkJBTU1FbEJ5YjIxbGRHaGxkWE1nVW05dmRDQkRRVEFnRncweApPVEEw + TURVd09EQXdNemRhR0E4eU1EVTVNRE15TmpBNE1EQXpOMW93YVRFTE1Ba0dBMVVFQmhNQ1ZWTXhF + ekFSCkJnTlZCQW9NQ2xCeWIyMWxkR2hsZFhNeEtUQW5CZ05WQkFzTUlGQnliMjFsZEdobGRYTWdR + MlZ5ZEdsbWFXTmgKZEdVZ1FYVjBhRzl5YVhSNU1Sb3dHQVlEVlFRRERCRlFjbTl0WlhSb1pYVnpJ + RlJNVXlCRFFUQ0NBU0l3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFLclNO + R3Z0OGZRQkNPVUFuM1hJdXZ4TGNzWUVrNi94CjlyWE9BUTNHdmRNV21KM2xVVllTV0JidUdHN3dh + S2xDRm1YUDR6SDFrSG1kRXpLSE94OWwvWVNJcEZZOUpsUnAKQlNkYTZva0M1ekdiZlg5MmsxUnd2 + QmVTQnArZmtFcUt6NEtuZTN4eHhQbzBWZ0F5R29YRitPUktZME0zbldDRQpUWGh1aHhMRUt4K1Rw + ZjdNWHZIZndaZi90ejRnT0IxeEZSSHNiSHJNRG9kU01iRzVkTU1ISEVKTEhzRVh2T1FUCnQ3QWdM + c1FIazcyb0VmbmFwOURmU2tpK20yMWx3NjVZVnNDZkY4WFlNckVFSXZ0YkdQWWdFRkRzTFJCUHpF + aVAKOG5YZE02UU85VlhhTEltaE9sSzdFUkVMbHljWGN6WGFFSEd6bjZoQ2tlWTZaZ0Q1NVJHUFcx + Y0NBd0VBQWFPQgozRENCMlRBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0Jn + RUIvd0lCQURBZEJnTlZIUTRFCkZnUVVUUUsvY1pWcXFsakZuTGlEWjE1a0ZwbmhLcDR3SHdZRFZS + MGpCQmd3Rm9BVVBCNm94a3dGVFNEc2lOc3AKMUh2NUVsM082aG93UGdZSUt3WUJCUVVIQVFFRU1q + QXdNQzRHQ0NzR0FRVUZCekFDaGlKb2RIUndjem92TDJWNApZVzF3YkdVdVkyOXRMMk5oTDNKdmIz + UXRZMkV1WTJWeU1ETUdBMVVkSHdRc01Db3dLS0Ftb0NTR0ltaDBkSEJ6Ck9pOHZaWGhoYlhCc1pT + NWpiMjB2WTJFdmNtOXZkQzFqWVM1amNtd3dEUVlKS29aSWh2Y05BUUVGQlFBRGdnRUIKQUdQOHVq + Q2xCZFoyRlBGM09MRkJiNEhadEFMOXZPWDIyZVp6NEhIUFRQc1R0V3U5dWNiMktCZzI0WXpaazdO + NApTajA1Ry9UN2FYVWtydUdnTDVRRnZ4QThQdElycVBNeEpTN3RFNjFnWFNLYUpoVWdocGh6VFBa + TFNMZ2ZaN3BPCnlVZnRoZHc0M0FJTSsxVFZMbXkwbFJoUjBhN3E2UHUwR1ZBRXZERitVWjZGS1Uz + STl5YlcxbzAxTFo3aUJoWTQKNGxhQTdQT2pOT01veE9nUTBJcW1ieUNhdWR5NWtHdTZpaWNzS1hJ + b1ZlZFpwcWVRN0RMbzBDWkt3VVRkSUwvYwpUUjUrek9XaVcramZQVXNCcWtoV0Yra3AySEdEQlRh + TUVVOTN1SlVndDhjaEJzS0hsN1JyMC9janVrMWZGZEVNClRXN3hhcDFYWEFKcTF6RVk3MXo4K0FR + PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCkNlcnRpZmljYXRlOgogICAgRGF0YToKICAgICAg + ICBWZXJzaW9uOiAzICgweDIpCiAgICAgICAgU2VyaWFsIE51bWJlcjogMSAoMHgxKQogICAgICAg + IFNpZ25hdHVyZSBBbGdvcml0aG06IHNoYTFXaXRoUlNBRW5jcnlwdGlvbgogICAgICAgIElzc3Vl + cjogQz1VUywgTz1Qcm9tZXRoZXVzLCBPVT1Qcm9tZXRoZXVzIENlcnRpZmljYXRlIEF1dGhvcml0 + eSwgQ049UHJvbWV0aGV1cyBSb290IENBCiAgICAgICAgVmFsaWRpdHkKICAgICAgICAgICAgTm90 + IEJlZm9yZTogQXByICA1IDA3OjU1OjAwIDIwMTkgR01UCiAgICAgICAgICAgIE5vdCBBZnRlciA6 + IE1hciAyNiAwNzo1NTowMCAyMDU5IEdNVAogICAgICAgIFN1YmplY3Q6IEM9VVMsIE89UHJvbWV0 + aGV1cywgT1U9UHJvbWV0aGV1cyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHksIENOPVByb21ldGhldXMg + Um9vdCBDQQogICAgICAgIFN1YmplY3QgUHVibGljIEtleSBJbmZvOgogICAgICAgICAgICBQdWJs + aWMgS2V5IEFsZ29yaXRobTogcnNhRW5jcnlwdGlvbgogICAgICAgICAgICAgICAgUlNBIFB1Ymxp + Yy1LZXk6ICgyMDQ4IGJpdCkKICAgICAgICAgICAgICAgIE1vZHVsdXM6CiAgICAgICAgICAgICAg + ICAgICAgMDA6YmY6Yjk6ZTI6YWI6NWY6NjE6MjI6ZTE6NGU6Y2Q6ZWU6ZGE6YjA6MjY6CiAgICAg + ICAgICAgICAgICAgICAgMmU6YmI6YjA6N2U6MWM6Y2U6MTA6YmU6MTY6Mjk6MzU6MGM6MGM6MWQ6 + OTM6CiAgICAgICAgICAgICAgICAgICAgMDE6Mjk6MmE6ZjY6Zjk6YzI6NmU6NWM6MTA6NDQ6Y2E6 + Zjg6ZGM6YWQ6N2E6CiAgICAgICAgICAgICAgICAgICAgMDY6NjQ6MGY6OGE6MTg6YWQ6YjI6YTI6 + OTQ6NDk6Yzk6YmE6OGM6NDU6OTQ6CiAgICAgICAgICAgICAgICAgICAgN2M6ZDk6ZTA6MTE6NDU6 + ZDg6MTY6Nzk6YTI6MjA6OWY6OGM6NjM6NjA6NzI6CiAgICAgICAgICAgICAgICAgICAgMmE6NWI6 + Zjk6NjY6ODA6YWM6ODU6Njc6MDE6NWE6ZWI6OTE6YzE6ZDI6ODg6CiAgICAgICAgICAgICAgICAg + ICAgODc6OWU6NGM6MTg6Yzk6ZjI6ZjA6N2E6MTg6YzA6ZTY6YWI6MmM6Nzg6ZGU6CiAgICAgICAg + ICAgICAgICAgICAgNWY6YjI6MjI6NGU6OTQ6OWM6ZjU6Y2Q6ZTY6ZTI6MzM6MzA6ZTk6MjA6MTA6 + CiAgICAgICAgICAgICAgICAgICAgYTY6YTE6NzU6ZWI6NTk6YWI6NDU6YTk6Zjc6M2U6NTQ6NDA6 + YWU6MDU6MjU6CiAgICAgICAgICAgICAgICAgICAgYmU6NzQ6YzU6M2E6ZmQ6YWY6NzM6MTY6NjA6 + NDU6N2M6NGE6ZTA6MGU6MGQ6CiAgICAgICAgICAgICAgICAgICAgYTE6MTU6N2Y6OWE6MWY6YzI6 + YTc6MDQ6YWQ6ZWY6YjM6ZTQ6ZjY6MDA6MmM6CiAgICAgICAgICAgICAgICAgICAgNGU6MGI6MDQ6 + OTA6NDk6ZWU6ZDM6ZGI6YTY6MTI6YzQ6OTE6MGI6MzI6NGY6CiAgICAgICAgICAgICAgICAgICAg + MTE6ODQ6Yzc6YzQ6OGE6ZWY6NTE6NjY6N2E6YjA6MjA6MmY6Y2I6OTU6OGQ6CiAgICAgICAgICAg + ICAgICAgICAgOTY6NTc6NjA6NjY6NWU6Zjk6NGY6NWE6OTQ6OWM6NzE6YWQ6ZWI6Y2E6NzA6CiAg + ICAgICAgICAgICAgICAgICAgM2U6NjI6MDY6YzI6M2E6Mjk6Zjg6OWU6ODY6YWY6ZGE6MDc6Nzg6 + Zjg6MzE6CiAgICAgICAgICAgICAgICAgICAgYWY6NDI6NDg6NDk6OWU6NGE6ZGY6MWI6Mjc6MWY6 + NDQ6MzU6ODE6NmQ6ZmE6CiAgICAgICAgICAgICAgICAgICAgN2E6YzU6NmE6MGE6MzU6MjM6Yzc6 + YzQ6ZDU6ZmU6Yzk6OWU6NjE6Yzk6MzA6CiAgICAgICAgICAgICAgICAgICAgY2Q6MWYKICAgICAg + ICAgICAgICAgIEV4cG9uZW50OiA2NTUzNyAoMHgxMDAwMSkKICAgICAgICBYNTA5djMgZXh0ZW5z + aW9uczoKICAgICAgICAgICAgWDUwOXYzIEtleSBVc2FnZTogY3JpdGljYWwKICAgICAgICAgICAg + ICAgIENlcnRpZmljYXRlIFNpZ24sIENSTCBTaWduCiAgICAgICAgICAgIFg1MDl2MyBCYXNpYyBD + b25zdHJhaW50czogY3JpdGljYWwKICAgICAgICAgICAgICAgIENBOlRSVUUKICAgICAgICAgICAg + WDUwOXYzIFN1YmplY3QgS2V5IElkZW50aWZpZXI6IAogICAgICAgICAgICAgICAgM0M6MUU6QTg6 + QzY6NEM6MDU6NEQ6MjA6RUM6ODg6REI6Mjk6RDQ6N0I6Rjk6MTI6NUQ6Q0U6RUE6MUEKICAgICAg + ICAgICAgWDUwOXYzIEF1dGhvcml0eSBLZXkgSWRlbnRpZmllcjogCiAgICAgICAgICAgICAgICBr + ZXlpZDozQzoxRTpBODpDNjo0QzowNTo0RDoyMDpFQzo4ODpEQjoyOTpENDo3QjpGOToxMjo1RDpD + RTpFQToxQQoKICAgIFNpZ25hdHVyZSBBbGdvcml0aG06IHNoYTFXaXRoUlNBRW5jcnlwdGlvbgog + ICAgICAgICA1NjoyZjo3OTplNToxMjo5MTpmNToxOTphNzpkMTozMjoyODpmZDplMzo5ZDo4Zjpl + MTozYzoKICAgICAgICAgYmI6YTM6YTU6ZjI6NTU6OGE6MDM6YWQ6MmM6MWQ6MTg6ODI6ZTE6N2Y6 + MTk6NzU6ZDk6NDc6CiAgICAgICAgIDViOmU3OjdjOmU0OmE1OmUwOmViOmRjOjdlOjI0OmEzOjdk + Ojk5OjFhOmNmOjM5OmJhOmE1OgogICAgICAgICBiNDpiODo0NTo2ODo4MzpjZjo3MDphZDo1Njpm + MjozNDo3Mzo2NTpmYzo2YzpiMDo1Mzo5YToKICAgICAgICAgNzk6MDQ6Zjc6M2U6N2U6NGI6MjI6 + MWI6ZTc6NzY6MjM6MjA6YmM6OWM6MDU6YTI6NWQ6MDE6CiAgICAgICAgIGQyOmYwOjA5OjQ5OjE3 + OmIyOjYxOjc0OjFhOjViOmY0OmUwOmZkOmNlOjExOmJhOjEzOjRhOgogICAgICAgICBlNjowNzox + MTo3ZDozMDplMjoxMTo4NzplZTozMzoxYTo2ODpkZTo2NzpmNDphYzpiNTo1ODoKICAgICAgICAg + MWE6YWM6Y2Y6N2E6MmQ6ZmQ6YzM6NDQ6NWI6NGI6Y2Q6NmM6ZmY6ZjY6NDk6YjQ6NTU6NGE6CiAg + ICAgICAgIDA5OmEwOjkyOjJkOjU3OjNiOjY5Ojg1OjU0OjNlOmU5OmVjOmVmOmIyOmE1OjdhOjI5 + Ojc1OgogICAgICAgICAyYjpmODplYjo0YjpkNDpjZjo2ODplZTozZTpjODo2Mzo3ZToxMjplYjpl + NDoyZjo2MzphMzoKICAgICAgICAgYTc6Yzg6MGY6ZTk6Mzk6ZmY6NWM6Mjk6NjU6N2Y6MjU6ZjA6 + NDI6YmY6MDc6YmE6MDY6Yjg6CiAgICAgICAgIDVlOmQ2OjU2OmJhOmY4OjY3OjU2OjFiOjQyOmFh + OmIzOjA0OmQ4OjZlOjg4OjEwOmE1OjcwOgogICAgICAgICBiNTo4MTowNDphNDo5MDphMzpmMDo4 + Mzo0ZDowYzo2YjoxMjo1ZDphNDo0Yzo4Mzo1YTpmZjoKICAgICAgICAgYTg6N2E6ODY6NjE6ZmY6 + MGY6NGM6ZTU6MGY6MTc6ZDE6NjQ6M2M6YmQ6ZDk6MjI6N2U6Yjc6CiAgICAgICAgIGZhOjliOjgz + OmJhCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlEdERDQ0FweWdBd0lCQWdJQkFUQU5C + Z2txaGtpRzl3MEJBUVVGQURCcU1Rc3dDUVlEVlFRR0V3SlZVekVUCk1CRUdBMVVFQ2d3S1VISnZi + V1YwYUdWMWN6RXBNQ2NHQTFVRUN3d2dVSEp2YldWMGFHVjFjeUJEWlhKMGFXWnAKWTJGMFpTQkJk + WFJvYjNKcGRIa3hHekFaQmdOVkJBTU1FbEJ5YjIxbGRHaGxkWE1nVW05dmRDQkRRVEFnRncweApP + VEEwTURVd056VTFNREJhR0E4eU1EVTVNRE15TmpBM05UVXdNRm93YWpFTE1Ba0dBMVVFQmhNQ1ZW + TXhFekFSCkJnTlZCQW9NQ2xCeWIyMWxkR2hsZFhNeEtUQW5CZ05WQkFzTUlGQnliMjFsZEdobGRY + TWdRMlZ5ZEdsbWFXTmgKZEdVZ1FYVjBhRzl5YVhSNU1Sc3dHUVlEVlFRRERCSlFjbTl0WlhSb1pY + VnpJRkp2YjNRZ1EwRXdnZ0VpTUEwRwpDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFR + Qy91ZUtyWDJFaTRVN043dHF3Smk2N3NINGN6aEMrCkZpazFEQXdka3dFcEt2YjV3bTVjRUVUSytO + eXRlZ1prRDRvWXJiS2lsRW5KdW94RmxIelo0QkZGMkJaNW9pQ2YKakdOZ2NpcGIrV2FBcklWbkFW + cnJrY0hTaUllZVRCako4dkI2R01EbXF5eDQzbCt5SWs2VW5QWE41dUl6TU9rZwpFS2FoZGV0WnEw + V3A5ejVVUUs0RkpiNTB4VHI5cjNNV1lFVjhTdUFPRGFFVmY1b2Z3cWNFcmUrejVQWUFMRTRMCkJK + Qko3dFBicGhMRWtRc3lUeEdFeDhTSzcxRm1lckFnTDh1VmpaWlhZR1plK1U5YWxKeHhyZXZLY0Q1 + aUJzSTYKS2ZpZWhxL2FCM2o0TWE5Q1NFbWVTdDhiSng5RU5ZRnQrbnJGYWdvMUk4ZkUxZjdKbm1I + Sk1NMGZBZ01CQUFHagpZekJoTUE0R0ExVWREd0VCL3dRRUF3SUJCakFQQmdOVkhSTUJBZjhFQlRB + REFRSC9NQjBHQTFVZERnUVdCQlE4CkhxakdUQVZOSU95STJ5blVlL2tTWGM3cUdqQWZCZ05WSFNN + RUdEQVdnQlE4SHFqR1RBVk5JT3lJMnluVWUva1MKWGM3cUdqQU5CZ2txaGtpRzl3MEJBUVVGQUFP + Q0FRRUFWaTk1NVJLUjlSbW4wVElvL2VPZGorRTh1Nk9sOGxXSwpBNjBzSFJpQzRYOFpkZGxIVytk + ODVLWGc2OXgrSktOOW1SclBPYnFsdExoRmFJUFBjSzFXOGpSelpmeHNzRk9hCmVRVDNQbjVMSWh2 + bmRpTWd2SndGb2wwQjB2QUpTUmV5WVhRYVcvVGcvYzRSdWhOSzVnY1JmVERpRVlmdU14cG8KM21m + MHJMVllHcXpQZWkzOXcwUmJTODFzLy9aSnRGVktDYUNTTFZjN2FZVlVQdW5zNzdLbGVpbDFLL2py + UzlUUAphTzQreUdOK0V1dmtMMk9qcDhnUDZUbi9YQ2xsZnlYd1FyOEh1Z2E0WHRaV3V2aG5WaHRD + cXJNRTJHNklFS1Z3CnRZRUVwSkNqOElOTkRHc1NYYVJNZzFyL3FIcUdZZjhQVE9VUEY5RmtQTDNa + SW42MytwdUR1Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + # this is config/testdata/client.crt + cert: !!binary | + Q2VydGlmaWNhdGU6CiAgICBEYXRhOgogICAgICAgIFZlcnNpb246IDMgKDB4MikKICAgICAgICBT + ZXJpYWwgTnVtYmVyOiAzICgweDMpCiAgICAgICAgU2lnbmF0dXJlIEFsZ29yaXRobTogc2hhMVdp + dGhSU0FFbmNyeXB0aW9uCiAgICAgICAgSXNzdWVyOiBDPVVTLCBPPVByb21ldGhldXMsIE9VPVBy + b21ldGhldXMgQ2VydGlmaWNhdGUgQXV0aG9yaXR5LCBDTj1Qcm9tZXRoZXVzIFRMUyBDQQogICAg + ICAgIFZhbGlkaXR5CiAgICAgICAgICAgIE5vdCBCZWZvcmU6IEFwciAgNSAwODoxMDoxMiAyMDE5 + IEdNVAogICAgICAgICAgICBOb3QgQWZ0ZXIgOiBNYXIgMjYgMDg6MTA6MTIgMjA1OSBHTVQKICAg + ICAgICBTdWJqZWN0OiBDPVVTLCBPPVByb21ldGhldXMsIENOPUNsaWVudAogICAgICAgIFN1Ympl + Y3QgUHVibGljIEtleSBJbmZvOgogICAgICAgICAgICBQdWJsaWMgS2V5IEFsZ29yaXRobTogcnNh + RW5jcnlwdGlvbgogICAgICAgICAgICAgICAgUlNBIFB1YmxpYy1LZXk6ICgyMDQ4IGJpdCkKICAg + ICAgICAgICAgICAgIE1vZHVsdXM6CiAgICAgICAgICAgICAgICAgICAgMDA6Yjc6ZDM6YjY6ZmM6 + MjI6NWY6NzM6NmE6MzI6YjA6OWE6NDM6YTI6ODc6CiAgICAgICAgICAgICAgICAgICAgY2I6MWY6 + NjA6OGY6OGU6ZjY6MDQ6OTM6YmU6ZmM6OTA6Mzc6YjA6NjE6Zjg6CiAgICAgICAgICAgICAgICAg + ICAgMWI6YmE6OTQ6YjM6N2U6NWU6MWI6NTE6YzY6ZGY6OTk6YTg6ZTE6ZGY6YWE6CiAgICAgICAg + ICAgICAgICAgICAgOGQ6ZjQ6MTI6ZTM6ZTY6NzU6Mjc6MGM6YWU6YWE6ZGU6ODI6YWI6YTk6NTQ6 + CiAgICAgICAgICAgICAgICAgICAgZjE6OGE6ODE6Zjk6MTc6NTQ6ZmQ6ZTE6MTc6OWE6ZDg6NzU6 + NmE6OTk6Yzc6CiAgICAgICAgICAgICAgICAgICAgODU6Y2U6Mjk6ZGM6YjE6NmQ6YTY6YWI6NjY6 + ZWE6NjQ6MDI6ZmQ6YTA6YjU6CiAgICAgICAgICAgICAgICAgICAgNTM6NDQ6MDU6Mjk6OTU6NGE6 + M2Y6MmU6YWU6ZGU6NTY6NjQ6ZTI6NTU6OWM6CiAgICAgICAgICAgICAgICAgICAgNWU6ZDA6MWE6 + Njg6NDI6MDA6N2E6NzE6ZGY6ODI6Zjk6MDg6MjM6ZDg6MGQ6CiAgICAgICAgICAgICAgICAgICAg + NzI6NDE6Nzc6OTE6MzE6MmY6MDE6ODg6MDc6MjI6YjE6NDA6ZGI6YTA6YTI6CiAgICAgICAgICAg + ICAgICAgICAgYmU6ZGQ6Mjc6MWY6MWU6ODY6NjU6NjQ6MTg6YWI6Njg6ZDM6NTE6OTY6OGU6CiAg + ICAgICAgICAgICAgICAgICAgMDY6M2U6YjA6ZjY6Mjk6OTU6NWY6NGE6YzY6ZjA6Zjg6Zjc6Mjg6 + MTc6NjE6CiAgICAgICAgICAgICAgICAgICAgMGU6OTU6MDI6YTg6MmQ6ZmQ6NWQ6ODQ6MWI6ZjM6 + Y2M6OTk6M2Q6M2Y6OGQ6CiAgICAgICAgICAgICAgICAgICAgNGI6NjY6MzM6NmI6NTg6MGM6NWM6 + ZWQ6M2U6NDQ6ODg6NDg6OTg6MzQ6YmM6CiAgICAgICAgICAgICAgICAgICAgMWY6ZGY6Zjc6MzE6 + ZTU6NjA6ODc6NDM6MWE6Mzk6MDE6OGU6Nzg6MWU6OTA6CiAgICAgICAgICAgICAgICAgICAgMDg6 + YTM6ZWY6YjQ6ZmQ6ZGY6MTE6MmU6YTI6ZWE6MzE6ZGI6OTU6MmQ6NWU6CiAgICAgICAgICAgICAg + ICAgICAgNjg6M2E6MDI6OWE6YWY6MGQ6NTE6MjI6MDc6MTY6NjY6Mzc6OTA6ZWQ6ZWY6CiAgICAg + ICAgICAgICAgICAgICAgNDE6YzE6YjE6MGY6ODg6N2U6ZDE6MGQ6MTE6NGE6MTg6ZjI6Mzg6NmI6 + MjI6CiAgICAgICAgICAgICAgICAgICAgNmM6MDEKICAgICAgICAgICAgICAgIEV4cG9uZW50OiA2 + NTUzNyAoMHgxMDAwMSkKICAgICAgICBYNTA5djMgZXh0ZW5zaW9uczoKICAgICAgICAgICAgWDUw + OXYzIEtleSBVc2FnZTogY3JpdGljYWwKICAgICAgICAgICAgICAgIERpZ2l0YWwgU2lnbmF0dXJl + CiAgICAgICAgICAgIFg1MDl2MyBCYXNpYyBDb25zdHJhaW50czogCiAgICAgICAgICAgICAgICBD + QTpGQUxTRQogICAgICAgICAgICBYNTA5djMgRXh0ZW5kZWQgS2V5IFVzYWdlOiAKICAgICAgICAg + ICAgICAgIFRMUyBXZWIgQ2xpZW50IEF1dGhlbnRpY2F0aW9uCiAgICAgICAgICAgIFg1MDl2MyBT + dWJqZWN0IEtleSBJZGVudGlmaWVyOiAKICAgICAgICAgICAgICAgIDNBOjQ2OkQxOkM1OjhDOjQy + OjYwOkFDOkVGOjBDOkREOjRCOjU1OjFFOkYwOkQ3OjVDOjc2OkMzOjMzCiAgICAgICAgICAgIFg1 + MDl2MyBBdXRob3JpdHkgS2V5IElkZW50aWZpZXI6IAogICAgICAgICAgICAgICAga2V5aWQ6NEQ6 + MDI6QkY6NzE6OTU6NkE6QUE6NTg6QzU6OUM6Qjg6ODM6Njc6NUU6NjQ6MTY6OTk6RTE6MkE6OUUK + CiAgICAgICAgICAgIEF1dGhvcml0eSBJbmZvcm1hdGlvbiBBY2Nlc3M6IAogICAgICAgICAgICAg + ICAgQ0EgSXNzdWVycyAtIFVSSTpodHRwOi8vZXhhbXBsZS5jb20vY2EvdGxzLWNhLmNlcgoKICAg + ICAgICAgICAgWDUwOXYzIENSTCBEaXN0cmlidXRpb24gUG9pbnRzOiAKCiAgICAgICAgICAgICAg + ICBGdWxsIE5hbWU6CiAgICAgICAgICAgICAgICAgIFVSSTpodHRwOi8vZXhhbXBsZS5jb20vY2Ev + dGxzLWNhLmNybAoKICAgICAgICAgICAgWDUwOXYzIFN1YmplY3QgQWx0ZXJuYXRpdmUgTmFtZTog + CiAgICAgICAgICAgICAgICBlbWFpbDpjbGllbnRAcHJvbWV0aGV1cy5leGFtcGxlLmNvbQogICAg + U2lnbmF0dXJlIEFsZ29yaXRobTogc2hhMVdpdGhSU0FFbmNyeXB0aW9uCiAgICAgICAgIDczOmZj + Ojg3OmYyOmNmOmUzOmIxOmRmOjJmOmY3OmJmOmY5Ojc0OmRjOjBiOmYwOjdmOjk1OgogICAgICAg + ICBlZjo3NzpiYTo2YTo3ZDpjNjpjNTpmMzpkOTpkNjpjNzplYjpmODphODozMDpkMzo5MDpkNToK + ICAgICAgICAgYTU6MGM6MzI6MzM6OTU6ODU6YTI6MDU6NmU6Nzg6YTc6MDc6YTU6ZTA6Y2Y6ZjQ6 + NjU6ZWY6CiAgICAgICAgIGQyOjZkOjg2OjY2OjJhOjdmOjEzOjc4OjJmOjkwOmRkOjlkOmE0OjM0 + OmQ0OjhmOmRmOjQxOgogICAgICAgICAxYjowZjoxNzo5OTo5OTowNjoyZDoyNjo4NjplMjo1ODoz + ZTo4NDpjYToxMzo5ZTowMDpjYToKICAgICAgICAgODI6MDc6NjM6ZTc6NmM6ZGY6ZTk6NDc6ZDY6 + YjM6Zjc6NTE6MWE6MzE6ZjQ6M2Q6Nzk6OTU6CiAgICAgICAgIGU3OmVhOmJmOjQwOjg0OjQ4OjA5 + OjIzOmJhOjMxOmIxOjY3OmNkOjA1OjUwOmVjOmU2OjBhOgogICAgICAgICBkODoyYjo3ZDo3ZDo3 + Mzo3YTo4YTo1ZjpmNzo3MjoyODo1Nzo5ZjoxNToyZDpiMTo0ZTphMToKICAgICAgICAgM2M6MDY6 + NTM6NjA6NmU6YjI6Zjk6MDQ6MDg6ODE6M2E6ZjI6YmE6NWQ6N2U6YWM6OTM6Zjc6CiAgICAgICAg + IDNiOjFhOmRlOjA3OjZlOjE0OmEyOjBiOmUyOjI4OjZhOjUwOjJkOmQ4OjliOjNjOjI1OmUyOgog + ICAgICAgICA4Mjo2Yjo5MDo3ZTo0NTo3YjpkZDozYTo3YTo4ZTo3MTo5OTphNzplODo4ODo1Zjow + Njo3MToKICAgICAgICAgNWI6M2Y6MTg6ODU6NzA6Zjk6ZWI6Yzc6MjY6NDM6MmI6NDk6OGY6MTc6 + OTA6YWE6YmE6ODY6CiAgICAgICAgIDhhOjUyOjYzOjgzOjlmOjlkOjVkOjc5OjUzOmFmOjZkOjFh + OjdlOjQ3OjBkOmVhOjNmOjMzOgogICAgICAgICAxODpjMDo1Zjo5MDpkMDpjNTowNDo4YjplMzo0 + YTo0NTozZDphNjo4YzpjMzpkMTo0NzoxYzoKICAgICAgICAgNDU6NzA6YTQ6NzUKLS0tLS1CRUdJ + TiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVLakNDQXhLZ0F3SUJBZ0lCQXpBTkJna3Foa2lHOXcwQkFR + VUZBREJwTVFzd0NRWURWUVFHRXdKVlV6RVQKTUJFR0ExVUVDZ3dLVUhKdmJXVjBhR1YxY3pFcE1D + Y0dBMVVFQ3d3Z1VISnZiV1YwYUdWMWN5QkRaWEowYVdacApZMkYwWlNCQmRYUm9iM0pwZEhreEdq + QVlCZ05WQkFNTUVWQnliMjFsZEdobGRYTWdWRXhUSUVOQk1DQVhEVEU1Ck1EUXdOVEE0TVRBeE1s + b1lEekl3TlRrd016STJNRGd4TURFeVdqQXpNUXN3Q1FZRFZRUUdFd0pWVXpFVE1CRUcKQTFVRUNn + d0tVSEp2YldWMGFHVjFjekVQTUEwR0ExVUVBd3dHUTJ4cFpXNTBNSUlCSWpBTkJna3Foa2lHOXcw + QgpBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF0OU8yL0NKZmMyb3lzSnBEb29mTEgyQ1BqdllFazc3 + OGtEZXdZZmdiCnVwU3pmbDRiVWNiZm1hamgzNnFOOUJMajVuVW5ESzZxM29LcnFWVHhpb0g1RjFU + OTRSZWEySFZxbWNlRnppbmMKc1cybXEyYnFaQUw5b0xWVFJBVXBsVW8vTHE3ZVZtVGlWWnhlMEJw + b1FnQjZjZCtDK1FnajJBMXlRWGVSTVM4QgppQWNpc1VEYm9LSyszU2NmSG9abFpCaXJhTk5SbG80 + R1ByRDJLWlZmU3NidytQY29GMkVPbFFLb0xmMWRoQnZ6CnpKazlQNDFMWmpOcldBeGM3VDVFaUVp + WU5Md2YzL2N4NVdDSFF4bzVBWTU0SHBBSW8rKzAvZDhSTHFMcU1kdVYKTFY1b09nS2FydzFSSWdj + V1pqZVE3ZTlCd2JFUGlIN1JEUkZLR1BJNGF5SnNBUUlEQVFBQm80SUJEekNDQVFzdwpEZ1lEVlIw + UEFRSC9CQVFEQWdlQU1Ba0dBMVVkRXdRQ01BQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUhBd0l3 + CkhRWURWUjBPQkJZRUZEcEcwY1dNUW1Dczd3emRTMVVlOE5kY2RzTXpNQjhHQTFVZEl3UVlNQmFB + RkUwQ3YzR1YKYXFwWXhaeTRnMmRlWkJhWjRTcWVNRHdHQ0NzR0FRVUZCd0VCQkRBd0xqQXNCZ2dy + QmdFRkJRY3dBb1lnYUhSMApjRG92TDJWNFlXMXdiR1V1WTI5dEwyTmhMM1JzY3kxallTNWpaWEl3 + TVFZRFZSMGZCQ293S0RBbW9DU2dJb1lnCmFIUjBjRG92TDJWNFlXMXdiR1V1WTI5dEwyTmhMM1Jz + Y3kxallTNWpjbXd3S0FZRFZSMFJCQ0V3SDRFZFkyeHAKWlc1MFFIQnliMjFsZEdobGRYTXVaWGho + YlhCc1pTNWpiMjB3RFFZSktvWklodmNOQVFFRkJRQURnZ0VCQUhQOApoL0xQNDdIZkwvZS8rWFRj + Qy9CL2xlOTN1bXA5eHNYejJkYkg2L2lvTU5PUTFhVU1Nak9WaGFJRmJuaW5CNlhnCnovUmw3OUp0 + aG1ZcWZ4TjRMNURkbmFRMDFJL2ZRUnNQRjVtWkJpMG1odUpZUG9US0U1NEF5b0lIWStkczMrbEgK + MXJQM1VSb3g5RDE1bGVmcXYwQ0VTQWtqdWpHeFo4MEZVT3ptQ3RncmZYMXplb3BmOTNJb1Y1OFZM + YkZPb1R3RwpVMkJ1c3ZrRUNJRTY4cnBkZnF5VDl6c2EzZ2R1RktJTDRpaHFVQzNZbXp3bDRvSnJr + SDVGZTkwNmVvNXhtYWZvCmlGOEdjVnMvR0lWdytldkhKa01yU1k4WGtLcTZob3BTWTRPZm5WMTVV + Njl0R241SERlby9NeGpBWDVEUXhRU0wKNDBwRlBhYU13OUZISEVWd3BIVT0KLS0tLS1FTkQgQ0VS + VElGSUNBVEUtLS0tLQo= + # this is config/testdata/client-no-pass.key + key: !!binary | + LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZB + QVNDQktrd2dnU2xBZ0VBQW9JQkFRQzMwN2I4SWw5emFqS3cKbWtPaWg4c2ZZSStPOWdTVHZ2eVFO + N0JoK0J1NmxMTitYaHRSeHQrWnFPSGZxbzMwRXVQbWRTY01ycXJlZ3F1cApWUEdLZ2ZrWFZQM2hG + NXJZZFdxWng0WE9LZHl4YmFhclp1cGtBdjJndFZORUJTbVZTajh1cnQ1V1pPSlZuRjdRCkdtaENB + SHB4MzRMNUNDUFlEWEpCZDVFeEx3R0lCeUt4UU51Z29yN2RKeDhlaG1Wa0dLdG8wMUdXamdZK3NQ + WXAKbFY5S3h2RDQ5eWdYWVE2VkFxZ3QvVjJFRy9QTW1UMC9qVXRtTTJ0WURGenRQa1NJU0pnMHZC + L2Y5ekhsWUlkRApHamtCam5nZWtBaWo3N1Q5M3hFdW91b3gyNVV0WG1nNkFwcXZEVkVpQnhabU41 + RHQ3MEhCc1ErSWZ0RU5FVW9ZCjhqaHJJbXdCQWdNQkFBRUNnZ0VCQUpObGdqSzNTUHZkS2xucXg5 + S1p1YWdtSDlZTXMrelgxZUc1bFlkb2pxdFQKc256ZjdsM3E3YjFpNmdJUzJwSGJWN3VoTWpkOEVt + d3FNSVN0SktQZnhhQU11U2owYVdlbzlsbnAzd05KRTdsOAo1NGhHRkNrdk1MamN5N0FkeDVMNkhx + RksrK0lnTUU5ZSs3TTNpV05xeU1ObjZiZk83QmEvNlY1UEJpOSt0bWFmCm5aV3FnWTJLZjhBMmlO + bm05UnZtaXdRNDJuc2pWc0tjWHpHZEJtRlRwNjlhci9RV3RrMWRXRGFqVVZ3L05jdE0KY3MrSXlw + UGpaaUFFM0NneXlpTEt6RzlDV0Nqa2ZNRWQxNHV4RkU3M3EyU0FHNlJXWVNudjFNM1dPdXBBRjBy + UApsbC9OTVhhTWpMbHEycTNCOXYyWkFhb2piYldsSExEZEVwRS9qd1hra3dFQ2dZRUE1aVdON1NH + SDhaRTZ3RGZPCkVZdVRRS3BxWXQxV2JDUXh2NzdsZXVHY20xS2xGWWZWOExzQi85eGlvY1Z0R203 + TjEyNnp1d2ZnemZrSVpXUUQKS3Jwb0ZVa3oxalVnK2tIQ3FmNEZPOGh6UjBCeTNoYmRUSW1KUUlM + dEMvSzNmSEp0ZXhGS2lXODJtYjQwbGdZYworTWs2TmI1Q21MNlZDWDV1OE1OQnZEOFdhTEVDZ1lF + QXpIb2ZJbmVMTExxRjJmMnVWekY3NDNDZGdQMWgwZlBJCkJTM2FrcDU2LzhxelFXTlcrbmF0SlJ4 + aVRoMlI4Z2R2QitQL1V0RVpSOEUrRmJTelo0ZElScnhJaTQ0ZXcwQ3IKc1JPYVA0TGthWkZmbEtT + L2ZEOFMxTTd5WlFodXNzUm9SV0gwQkR2TTBoc3U2VVRHbEVTSFg3M2I3anM0QUhwQgoycTRmckpN + VERGRUNnWUJyMmYyQXVzM3lMcFRScjFVcWM3WTEvNmFMWGg0NTMxeFE5eXlqUVVjYW9zZ3FKdFhq + ClVqL0ZuNG01TmNQRE4xblBNMW1XdEVKdFE5N2paTkwzR3hQYnBjcGMvOWpNYmpURFpQOGUzUGpv + MHhNQmNNV1UKTUgvWmM0R1NyOU84eGdMNFFVb2t6YkZRcXdvSnBDTy9rczFza2hTemI5eDM3b0Fl + NCtIU1RkNDZnUUtCZ1FDaworOWhKU0NsOGtwZFRsNU5tK1I5Y0dVNk1lR1hJTUtud085cERPU3BI + WDdjWkNGMXl3L1RhbjdkV0RoZm5NRVpQCkdKQzNzczF5RHlMWUFyQksxV1hrNVNDbnNhbHlvNmlr + dlF0Vk9YaXhFVUlNdm8xZVk4bisrV2V0UzR0K0pHbDUKcWhwb25CT2NaNkNIU1IzdEhnb1lueWxv + WkZIQVdPVHYzRlRrT3R0QXNRS0JnUUN6V1NPMlRBNHYvdklLSXJTVgpMZjJjSTUxaW1jeS9KQ3NZ + VVUrbzY2VlE2UWRJSmxmYW11QUthS1lBd2ZKdEh0Wk96QWdyaDA5SlYzcUVFdE41CmR1QmRYaXV5 + Z0F6OGVIYnFTb1NlNUZZZ0ltSTBCUkVEcThabTNBcmdVaHY2UzlhQmVnL21TMVcvNVpmbVYyY1QK + ME1kbEU4dlV0Y2JEa21LcGk3Q2FrbHpNTnc9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg== + insecure_skip_verify: true