Merge pull request #4659 from dolthub/aaron/remotesrv-tls-san

go/libraries/doltcore/sqle/cluster: Add the ability to configure SAN assertions on URIs and DNS names in the server certificate when configuring TLS.
This commit is contained in:
Aaron Son
2022-10-28 16:29:39 -07:00
committed by GitHub
24 changed files with 1240 additions and 285 deletions
+14 -4
View File
@@ -517,10 +517,12 @@ func (c *ClusterYAMLConfig) RemotesAPIConfig() cluster.RemotesAPIConfig {
}
type clusterRemotesAPIYAMLConfig struct {
Port_ int `yaml:"port"`
TLSKey_ string `yaml:"tls_key"`
TLSCert_ string `yaml:"tls_cert"`
TLSCA_ string `yaml:"tls_ca"`
Port_ int `yaml:"port"`
TLSKey_ string `yaml:"tls_key"`
TLSCert_ string `yaml:"tls_cert"`
TLSCA_ string `yaml:"tls_ca"`
URLMatches []string `yaml:"server_name_urls"`
DNSMatches []string `yaml:"server_name_dns"`
}
func (c clusterRemotesAPIYAMLConfig) Port() int {
@@ -538,3 +540,11 @@ func (c clusterRemotesAPIYAMLConfig) TLSCert() string {
func (c clusterRemotesAPIYAMLConfig) TLSCA() string {
return c.TLSCA_
}
func (c clusterRemotesAPIYAMLConfig) ServerNameURLMatches() []string {
return c.URLMatches
}
func (c clusterRemotesAPIYAMLConfig) ServerNameDNSMatches() []string {
return c.DNSMatches
}
@@ -26,6 +26,8 @@ type RemotesAPIConfig interface {
TLSKey() string
TLSCert() string
TLSCA() string
ServerNameURLMatches() []string
ServerNameDNSMatches() []string
}
type StandbyRemoteConfig interface {
@@ -193,7 +193,7 @@ func (c *Controller) applyCommitHooks(ctx context.Context, name string, bt *sql.
}
func (c *Controller) gRPCDialProvider(denv *env.DoltEnv) dbfactory.GRPCDialProvider {
return grpcDialProvider{env.NewGRPCDialProviderFromDoltEnv(denv), &c.cinterceptor, c.cfg.RemotesAPIConfig().TLSCA()}
return grpcDialProvider{env.NewGRPCDialProviderFromDoltEnv(denv), &c.cinterceptor, c.cfg}
}
func (c *Controller) RegisterStoredProcedures(store procedurestore) {
@@ -34,9 +34,9 @@ import (
// - client interceptors for transmitting our replication role.
// - do not use environment credentials. (for now).
type grpcDialProvider struct {
orig dbfactory.GRPCDialProvider
ci *clientinterceptor
caPath string
orig dbfactory.GRPCDialProvider
ci *clientinterceptor
cfg Config
}
func (p grpcDialProvider) GetGRPCDialParams(config grpcendpoint.Config) (dbfactory.GRPCRemoteConfig, error) {
@@ -86,16 +86,19 @@ func (p grpcDialProvider) GetGRPCDialParams(config grpcendpoint.Config) (dbfacto
// if the remotesapi endpoints is HTTPS, then the system roots are used and
// ServerName is verified against the presented URL SANs of the certificates.
func (p grpcDialProvider) tlsConfig() (*tls.Config, error) {
if p.caPath == "" {
tlsCA := p.cfg.RemotesAPIConfig().TLSCA()
if tlsCA == "" {
return nil, nil
}
pem, err := ioutil.ReadFile(p.caPath)
urlmatches := p.cfg.RemotesAPIConfig().ServerNameURLMatches()
dnsmatches := p.cfg.RemotesAPIConfig().ServerNameDNSMatches()
pem, err := ioutil.ReadFile(tlsCA)
if err != nil {
return nil, err
}
roots := x509.NewCertPool()
if ok := roots.AppendCertsFromPEM(pem); !ok {
return nil, errors.New("error loading ca roots from " + p.caPath)
return nil, errors.New("error loading ca roots from " + tlsCA)
}
verifyFunc := func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
certs := make([]*x509.Certificate, len(rawCerts))
@@ -120,6 +123,40 @@ func (p grpcDialProvider) tlsConfig() (*tls.Config, error) {
if err != nil {
return err
}
if len(urlmatches) > 0 {
found := false
for _, n := range urlmatches {
for _, cn := range certs[0].URIs {
if n == cn.String() {
found = true
}
break
}
if found {
break
}
}
if !found {
return errors.New("expected certificate to match something in server_name_urls, but it did not")
}
}
if len(dnsmatches) > 0 {
found := false
for _, n := range dnsmatches {
for _, cn := range certs[0].DNSNames {
if n == cn {
found = true
}
break
}
if found {
break
}
}
if !found {
return errors.New("expected certificate to match something in server_name_dns, but it did not")
}
}
return nil
}
return &tls.Config{
@@ -0,0 +1,3 @@
Create the ../*.pem files that are used by these tests.
Expects to be run from this directory like `go run .`.
@@ -0,0 +1,3 @@
module github.com/dolthub/dolt/integration-tests/go-sql-server-driver/gencerts
go 1.19
@@ -0,0 +1,337 @@
// Copyright 2022 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"path/filepath"
"math/big"
"net/url"
"os"
"time"
)
// Generates a 4096-bit RSA chain and an ed25519 chain.
// Each chain includes a root, an intermediate, a leaf with DNS and URI SANs.
// Root and intermediate have isCA=true and key usage CertSign.
// Leaf has isCA=false and key usage digitalSignature and extKeyUsage ServerAuth.
//
// Generates separate expired leafs for each key type.
//
// Emits private keys of the leafs. RSA keys are emitted PEM encoded PKCS1.
// ed25519 keys are emitted PEM encoded PKCS8.
//
// These certificates and private keys are used by
// tests/sql-server-cluster-tls.yaml and tests/sql-server-tls.yaml, for
// example.
//
// TODO: Further tests which should not verify? (SHA-1 signatures, expired
// roots or intermediates, wrong isCA, wrong key usage, etc.)
const RelPath = "../testdata"
func main() {
rsacerts, err := MakeRSACerts()
if err != nil {
panic(err)
}
err = WriteRSACerts(rsacerts)
if err != nil {
panic(err)
}
edcerts, err := MakeEd25519Certs()
if err != nil {
panic(err)
}
err = WriteEd25519Certs(edcerts)
if err != nil {
panic(err)
}
}
func WriteRSACerts(rsacerts TestCerts) error {
err := os.WriteFile(filepath.Join(RelPath, "rsa_root.pem"), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rsacerts.Root.Raw,
}), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "rsa_chain.pem"), append(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rsacerts.Leaf.Raw,
}), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rsacerts.Intermediate.Raw,
})...), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "rsa_key.pem"), pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(rsacerts.LeafKey.(*rsa.PrivateKey)),
}), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "rsa_exp_chain.pem"), append(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rsacerts.ExpiredLeaf.Raw,
}), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: rsacerts.Intermediate.Raw,
})...), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "rsa_exp_key.pem"), pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(rsacerts.ExpiredLeafKey.(*rsa.PrivateKey)),
}), 0664)
if err != nil {
return err
}
return nil
}
func WriteEd25519Certs(edcerts TestCerts) error {
err := os.WriteFile(filepath.Join(RelPath, "ed25519_root.pem"), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: edcerts.Root.Raw,
}), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "ed25519_chain.pem"), append(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: edcerts.Leaf.Raw,
}), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: edcerts.Intermediate.Raw,
})...), 0664)
if err != nil {
return err
}
keybytes, err := x509.MarshalPKCS8PrivateKey(edcerts.LeafKey)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "ed25519_key.pem"), pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: keybytes,
}), 0664)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "ed25519_exp_chain.pem"), append(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: edcerts.ExpiredLeaf.Raw,
}), pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: edcerts.Intermediate.Raw,
})...), 0664)
if err != nil {
return err
}
keybytes, err = x509.MarshalPKCS8PrivateKey(edcerts.ExpiredLeafKey)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(RelPath, "edcerts_exp_key.pem"), pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: keybytes,
}), 0664)
if err != nil {
return err
}
return nil
}
type TestCerts struct {
Root *x509.Certificate
Intermediate *x509.Certificate
Leaf *x509.Certificate
LeafKey any
ExpiredLeaf *x509.Certificate
ExpiredLeafKey any
}
func MakeRSACerts() (TestCerts, error) {
genKey := func() (any, any, error) {
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, err
}
return key.Public(), key, nil
}
return MakeCerts("RSA 4096-bit", genKey)
}
func MakeEd25519Certs() (TestCerts, error) {
genKey := func() (any, any, error) {
return ed25519.GenerateKey(rand.Reader)
}
return MakeCerts("ed25519", genKey)
}
func MakeCerts(desc string, genKey func() (any, any, error)) (TestCerts, error) {
nbf := time.Now().Add(-24 * time.Hour)
exp := nbf.Add(24 * 365 * 10 * time.Hour)
badExp := nbf.Add(12 * time.Hour)
rootpub, rootpriv, err := genKey()
if err != nil {
return TestCerts{}, err
}
intpub, intpriv, err := genKey()
if err != nil {
return TestCerts{}, err
}
leafpub, leafpriv, err := genKey()
if err != nil {
return TestCerts{}, err
}
exppub, exppriv, err := genKey()
if err != nil {
return TestCerts{}, err
}
signer, err := NewRootSigner(&x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Country: []string{"US"},
Organization: []string{"DoltHub, Inc."},
CommonName: "dolt integration tests " + desc + " Root",
},
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageCertSign,
NotBefore: nbf,
NotAfter: exp,
}, rootpub, rootpriv)
if err != nil {
return TestCerts{}, err
}
intcert, err := signer.Sign(&x509.Certificate{
SerialNumber: big.NewInt(2),
Subject: pkix.Name{
Country: []string{"US"},
Organization: []string{"DoltHub, Inc."},
CommonName: "dolt integration tests " + desc + " Intermediate",
},
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageCertSign,
NotBefore: nbf,
NotAfter: exp,
}, intpub)
if err != nil {
return TestCerts{}, err
}
intsigner := Signer{intcert, intpriv}
leafdns := "dolt-instance.dolt-integration-test.example"
leafurl, err := url.Parse("spiffe://dolt-integration-tests.dev.trust.dolthub.com.example/dolt-instance")
if err != nil {
return TestCerts{}, err
}
leafcert, err := intsigner.Sign(&x509.Certificate{
SerialNumber: big.NewInt(3),
Subject: pkix.Name{
Country: []string{"US"},
Organization: []string{"DoltHub, Inc."},
CommonName: "dolt integration tests " + desc + " Leaf",
},
BasicConstraintsValid: true,
IsCA: false,
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
NotBefore: nbf,
NotAfter: exp,
DNSNames: []string{leafdns},
URIs: []*url.URL{leafurl},
}, leafpub)
if err != nil {
return TestCerts{}, err
}
expcert, err := intsigner.Sign(&x509.Certificate{
SerialNumber: big.NewInt(4),
Subject: pkix.Name{
Country: []string{"US"},
Organization: []string{"DoltHub, Inc."},
CommonName: "dolt integration tests " + desc + " Expired Leaf",
},
BasicConstraintsValid: true,
IsCA: false,
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
NotBefore: nbf,
NotAfter: badExp,
DNSNames: []string{leafdns},
URIs: []*url.URL{leafurl},
}, exppub)
if err != nil {
return TestCerts{}, err
}
return TestCerts{
Root: signer.Cert,
Intermediate: intsigner.Cert,
Leaf: leafcert,
ExpiredLeaf: expcert,
LeafKey: leafpriv,
ExpiredLeafKey: exppriv,
}, nil
}
type Signer struct {
Cert *x509.Certificate
Key interface{}
}
func (s Signer) Sign(cert *x509.Certificate, pub any) (*x509.Certificate, error) {
der, err := x509.CreateCertificate(rand.Reader, cert, s.Cert, pub, s.Key)
if err != nil {
return nil, err
}
return x509.ParseCertificate(der)
}
func NewRootSigner(cert *x509.Certificate, pub, priv any) (Signer, error) {
der, err := x509.CreateCertificate(rand.Reader, cert, cert, pub, priv)
if err != nil {
return Signer{}, err
}
cert, err = x509.ParseCertificate(der)
if err != nil {
return Signer{}, err
}
return Signer{cert, priv}, nil
}
@@ -26,6 +26,10 @@ func TestCluster(t *testing.T) {
RunTestsFile(t, "tests/sql-server-cluster.yaml")
}
func TestClusterTLS(t *testing.T) {
RunTestsFile(t, "tests/sql-server-cluster-tls.yaml")
}
func TestOriginal(t *testing.T) {
RunTestsFile(t, "tests/sql-server-orig.yaml")
}
@@ -1,46 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIUB7Qx4HU3Ezu1FCmp4EKMLGzQW5wwDQYJKoZIhvcNAQEL
BQAwWzELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xNDAyBgNV
BAMTK3Rlc3RkYXRhIEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
HhcNMjIxMDI2MjA0MTAwWhcNMjQxMDE1MjA0MTAwWjBBMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjEaMBgGA1UEAxMRdGVzdGRhdGEgSW5zdGFu
Y2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC40mH/fY9PcLNkmDhD
TLW4jRYpZWaQx5GD2rSgodO7HcdEvECnvFH9AzktNnU2V/O18Ns+Q66DqACdBFie
wvi3HVD1lp16PeDDzd+U1gsv09aJkyMQ9rgsc9xER1YsW+9W0jVgCi+uYAgXKRol
kh5E1GPcgXC0PBHs4EhCXIvQ6VsHkswKLjwTWn3RSotkwGlxNQwbKX4BSFdoc5k/
QFjW0gG+OoISPJyN3zkU//fKP4/jncxw6jev9KNe7iR8D81Or2s5WhAfA6iv86a9
qDTWEwP01YmW7bodiv1iytJqrmqLq/Nan1B0HyU9szDE1Ulftf3pSfWJo7pBb1Vc
Rh+3AgMBAAGjgdMwgdAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
BwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSwrZlshrfvOW37
q6uxSNSYshC2tDAfBgNVHSMEGDAWgBSfaRPMObTFtIs5n3a3/gUuHw+7cjBRBgNV
HREESjBIghF0ZXN0ZGF0YS50ZXN0ZGF0YYYzc3BpZmZlOi8vbG9jYWwuYXdzZGV2
LmxkLWNvcnAuY29tL3NlcnZpY2VzL3Rlc3RkYXRhMA0GCSqGSIb3DQEBCwUAA4IB
AQAUWUnILP1AtiL9e4M0dWfPiVyXBDKhJI4DjF/phNF0X+ou+rjFUCJunf29A9YD
QzJOQaJY0Gw3Gy1zyx7QG1nkZAhNwqsrzHx5XP9b/p07/Oh7RXk27LbMJZ6JTdQ2
zR4V+oWDRJ4Fm81cgLaRlXg77xsg69pblubLGvPp3/YLYItoA9oTJdmSftFXDUUa
vz/PqfWriwiBU3BD8plERt7ljbsOUbo1LQEEd9zxYoPzBKDKj8NMIfmY9NK2QiOy
vAzyAvB7jU7EhcJsrq3G9KW0Fji0/rsLNb9h8U0ketwdXrCjEq9aEOfKDcHYwvPj
TSo+uj5MuTBHveAuwmcXy7hB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDnTCCAoWgAwIBAgIUfoPtM9PmrcMNEV4V7XhM0NyrE2AwDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xJzAlBgNV
BAMTHnRlc3RkYXRhIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0yMjEwMjYyMDQw
MDBaFw0yNDEwMTUyMDQwMDBaMFsxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Eb2x0
SHViLCBJbmMuMTQwMgYDVQQDEyt0ZXN0ZGF0YSBJbnRlcm1lZGlhdGUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
wcKXpc7l19CyYhbkl6j9EfRP5o2VMoRDUHndxvYIciRhy44lmAscjI3ZnCGRV/TX
iP2x8pvvhltqD5h6Rb0pHG91PwdOb/vqLIfSZ91tCQbpSHIKwWvZmkefp7Xt7AQM
VPZwMJNq2o1S3m167CkXHzSlHBVq+ztAc9rvkgLSe85dDN54OFWUwwJY8QToLANp
ElIym6RIKAqwRASWe8bLG18lGEUnpYwseR0KWYcfL5R15QD3Lk8Xb93FSPakYmvI
7kMje0RwjHZv8GEmiFweFgEiJNtCtdsyoc3reSPHf/hfRSLDV4aqW/BtdYnXJHVn
RGwT/ZrIDinCSSWEQNiY+wIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0T
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUn2kTzDm0xbSLOZ92t/4FLh8Pu3IwHwYD
VR0jBBgwFoAUxMCLKgcsWqPtQd5U7ZtkVYR1vIIwDQYJKoZIhvcNAQELBQADggEB
AHwJIEc04BIkww0ljW8A1K9JoNVsnJyxL7cjeEB+A+S64bcG3QN8N1+qwvyOI3a4
WjhWNfV2oJi7PkJ0WPz+anTHugtwbekKqV45Y3W1X/OdPTKMPWBZ5mvkLecTlobl
jMh9kWg3F3n+d+KaWGlvdKDPSwaOhpmkgwPthAuztcAkpvJuz7/4jP5jrM2cqD4+
otDRKr+b73m2w7jqICXxdYXEuFQ9qCZ8VvlYCTF9qOuBlCeAwanRaPj5na+cME5m
0AIZyTeYCpB6eP5HLWCGvEP6lD5Hv8PMAzh8xgfFDyxZc3jAWFRB5xRidAVC/wtF
Nhs1l1AIQ5vUOZrOmsHaIHI=
-----END CERTIFICATE-----
@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuNJh/32PT3CzZJg4Q0y1uI0WKWVmkMeRg9q0oKHTux3HRLxA
p7xR/QM5LTZ1NlfztfDbPkOug6gAnQRYnsL4tx1Q9Zadej3gw83flNYLL9PWiZMj
EPa4LHPcREdWLFvvVtI1YAovrmAIFykaJZIeRNRj3IFwtDwR7OBIQlyL0OlbB5LM
Ci48E1p90UqLZMBpcTUMGyl+AUhXaHOZP0BY1tIBvjqCEjycjd85FP/3yj+P453M
cOo3r/SjXu4kfA/NTq9rOVoQHwOor/Omvag01hMD9NWJlu26HYr9YsrSaq5qi6vz
Wp9QdB8lPbMwxNVJX7X96Un1iaO6QW9VXEYftwIDAQABAoIBAQC4yEaIPQ2yG/iP
g40E5EXvDMfyfVntOEopLNlYnFLnCl+3PgvaZ/ME5lsc9Ax+V7Lm3bclal+pa6ep
VLYRjNdDpMDTuVEa7ZCx0zxNPy8SE1a0V3JAvJrofrHjZfsnAIerIyGQMr73NTYB
ieuFUrCGml55EMUQvdoiHR7BkmuLYn+3TNJ4Lr2WsNGmChG/W+IwkdmW4RFLZo67
qHjb7yAYEXFBppgm1YpaHwEnCmOsErmBlAwFZwvPLRezjumics+2yrHt/Tm7uicR
GQI2ROCp2rst2UOiPtYd+vWCabYB2TtMq9/CLAgQsIkC/iABWDsB/Yasu/xfo1k+
C0GhlfgJAoGBAMpo1qqjoSDDL+tJrVFg/dEpU7CWodXJ/6vm3Qb1WB7Nm93j5tsf
7v390uQGsPSl/KD9MqTnDWs4xVgvO6eu/LCB9749ctbBkHvpN1eLjlApWG+eLGHf
gfqHMiokQ228J0CUhgvrfb0SxIsRnmHqxfbHo8oHBIW+WnlNwMOG0WvTAoGBAOnB
dlsWedSQJGngsQg7zc9NOJbJz4SxAv/Vp6KjVMiFQOcTJa/PUyaoTDUGoxSysMTl
+5RF70gxPtcZJrqC2OWuULkI1Lm0A69SHU/P2tCJ+Wt/AcK7yH/vTEQd44Pwjkct
uoCM3Euf/S66GOIPkM3RG5CxuU+SBp+wGaOYhAINAoGAQ+WnHNaG1lajXGn6mbHP
crpKOJJO90grW561xf/G745JGsW4SwkLQmhCtfsIoQiNFfPZaTeYaL9Cc7JkcHti
iFMQp+A1BZUowmgZCGTn+DvmTorgmHRBRajUSw6fD9Bt2lv4G0eDhkklZQEj//Sh
M4cEimCQQ8z2zHooj25KEcECgYAV9792ufsDFfTGGn6opm4mEDzENv0QnE4K2vph
F3ZtTdCWpr8A8bv/wws+ZHxJAq4IIxDsk1H0d+RO9KcmGgvmMeaWLRVIynkaLd5h
VMhclsrg5lO1CE7Ebym8sQ5jpOTKHasMT7CYTtXNYWHbRNk37nHnvDwNFU0YDsWq
ETg+tQKBgBSeRiTSx9Up58kNqRj+Z+EAKY3FoIgN6b83pL71gCXLdP0SQmZ9QOiV
5RGF0cbE1n3dx+HMKzNKnKhj783hnLosttq5OlO2cxqLTGLjv5aLPDji3HtK1HaA
IBIg58byFOMoKp95W0QSXVIAymXyvKRyj7dT1kDOidjQo354Y+5R
-----END RSA PRIVATE KEY-----
@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDbDCCAlSgAwIBAgIUSixGHtBJBKsVdj56puZy3LHvtkgwDQYJKoZIhvcNAQEL
BQAwTjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xJzAlBgNV
BAMTHnRlc3RkYXRhIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0yMjEwMjUyMjU1
MDBaFw0yNzEwMjQyMjU1MDBaME4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Eb2x0
SHViLCBJbmMuMScwJQYDVQQDEx50ZXN0ZGF0YSBDZXJ0aWZpY2F0ZSBBdXRob3Jp
dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDArzGWFksWPijYVrsq
Hj1YakHQiUcK7KLsXZHm0Tx3ryUvJZAX86UM+/QXO/TVYoWPoIXVaFFCDMlwKzXU
FgEHJHQU7NaKcDUN8xaM36Y79VouHJzkUl6UvMGZrQXqdsPsQ56t/GcJCbbBLgki
9uQPGOB2KhLTkPV4L6CmubIOakCmNI99Ivoo2YGc3m5RYSv5f8/RnyDYBKWAenwI
omWPFs9te5AriIaXXq4nQhJQ40TCK/P9AZTlJOO5jaZ4Gnt/XWSHoSwxd15bkEos
19wdqK4oHHnO8luIA4lL7PxyOB5Wz/P+n9epY7aM/AHy7gVoekLhFk1CVuzA30Uv
ZEfbAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
A1UdDgQWBBTEwIsqByxao+1B3lTtm2RVhHW8gjANBgkqhkiG9w0BAQsFAAOCAQEA
kSXCYNgsLdyWVru8rhshoW7sZjKCttgmUzacv79JPpYuZOTS/YthlYAh6NHqnCuW
cMRNxjr88LQu/U8MwJ+8qeHZBm2k6RMvvm8/w8WfyP1E/2PgFtF9nqlehj1o3BaR
UohLNl7YfJORiW8L/z0FAsz24+xsCtvQnvaGxFZcYHKYyg9xS4dbspN5fg2daxP7
jzzI0xcmpOFJfDpRywhx9iI8J+tJLtVJLZutuah9cK2Y5PGqsTikly//WAv99Rw8
naMb8DOC0p1RiXakbF7LMSyIbaLdmItlx3Ea/b/Ul/kFw/cueHTCyGZ4swvkq6pR
1lEUD4MQPt0u9IterfN4yg==
-----END CERTIFICATE-----
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAe2gAwIBAgIBAzAFBgMrZXAwWzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DURvbHRIdWIsIEluYy4xNDAyBgNVBAMTK2RvbHQgaW50ZWdyYXRpb24gdGVzdHMg
ZWQyNTUxOSBJbnRlcm1lZGlhdGUwHhcNMjIxMDI2MjEwMTQyWhcNMzIxMDIzMjEw
MTQyWjBTMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRG9sdEh1YiwgSW5jLjEsMCoG
A1UEAxMjZG9sdCBpbnRlZ3JhdGlvbiB0ZXN0cyBlZDI1NTE5IExlYWYwKjAFBgMr
ZXADIQBq59gmS/TqiLFwMpug/QSxGiq/zzMPQBWOe+l0o8tbkKOB3TCB2jAOBgNV
HQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAf
BgNVHSMEGDAWgBS8Fugt5Yjb7mabErluXQOwId4DfTCBgwYDVR0RBHwweoIrZG9s
dC1pbnN0YW5jZS5kb2x0LWludGVncmF0aW9uLXRlc3QuZXhhbXBsZYZLc3BpZmZl
Oi8vZG9sdC1pbnRlZ3JhdGlvbi10ZXN0cy5kZXYudHJ1c3QuZG9sdGh1Yi5jb20u
ZXhhbXBsZS9kb2x0LWluc3RhbmNlMAUGAytlcANBAF7vtPl1usXT+WgeD72BEdYB
2E8PbORVYT05SrjRYRcdHNegWQUN2fhKE/+WNeeOVfGQBcwMlObof6deraq9uw8=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBwDCCAXKgAwIBAgIBAjAFBgMrZXAwUzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DURvbHRIdWIsIEluYy4xLDAqBgNVBAMTI2RvbHQgaW50ZWdyYXRpb24gdGVzdHMg
ZWQyNTUxOSBSb290MB4XDTIyMTAyNjIxMDE0MloXDTMyMTAyMzIxMDE0MlowWzEL
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xNDAyBgNVBAMTK2Rv
bHQgaW50ZWdyYXRpb24gdGVzdHMgZWQyNTUxOSBJbnRlcm1lZGlhdGUwKjAFBgMr
ZXADIQC63kDzz+nGeTtt2CcA2M3Q1R8YephuuUzxlvEB+cgj5KNjMGEwDgYDVR0P
AQH/BAQDAgIEMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLwW6C3liNvuZpsS
uW5dA7Ah3gN9MB8GA1UdIwQYMBaAFOE9s81S97V1S09D3k0obt02yhrpMAUGAytl
cANBAJkX45OPKCFrJ2EmgXntZQFznQuUriA68Pxaxxzy3/W1jDtxf2cccDxtS1TJ
uPGtJ5Ri8dbk+5FgK3GQFQweDwA=
-----END CERTIFICATE-----
@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIICQzCCAfWgAwIBAgIBBDAFBgMrZXAwWzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DURvbHRIdWIsIEluYy4xNDAyBgNVBAMTK2RvbHQgaW50ZWdyYXRpb24gdGVzdHMg
ZWQyNTUxOSBJbnRlcm1lZGlhdGUwHhcNMjIxMDI2MjEwMTQyWhcNMjIxMDI3MDkw
MTQyWjBbMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRG9sdEh1YiwgSW5jLjE0MDIG
A1UEAxMrZG9sdCBpbnRlZ3JhdGlvbiB0ZXN0cyBlZDI1NTE5IEV4cGlyZWQgTGVh
ZjAqMAUGAytlcAMhAF6ENDzBPmj6JXxySz9SBR4eh6pOI+IEeepQuqa0Pvn4o4Hd
MIHaMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMB
Af8EAjAAMB8GA1UdIwQYMBaAFLwW6C3liNvuZpsSuW5dA7Ah3gN9MIGDBgNVHREE
fDB6gitkb2x0LWluc3RhbmNlLmRvbHQtaW50ZWdyYXRpb24tdGVzdC5leGFtcGxl
hktzcGlmZmU6Ly9kb2x0LWludGVncmF0aW9uLXRlc3RzLmRldi50cnVzdC5kb2x0
aHViLmNvbS5leGFtcGxlL2RvbHQtaW5zdGFuY2UwBQYDK2VwA0EAsJcZ7AAXXkmW
78cvfT7aa++y/t++altVJs0Qy8zZcP4XBBuPpdzxrQRcILQ2lyrpER8wrSB67UH6
LSeDh4FuCA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBwDCCAXKgAwIBAgIBAjAFBgMrZXAwUzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DURvbHRIdWIsIEluYy4xLDAqBgNVBAMTI2RvbHQgaW50ZWdyYXRpb24gdGVzdHMg
ZWQyNTUxOSBSb290MB4XDTIyMTAyNjIxMDE0MloXDTMyMTAyMzIxMDE0MlowWzEL
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xNDAyBgNVBAMTK2Rv
bHQgaW50ZWdyYXRpb24gdGVzdHMgZWQyNTUxOSBJbnRlcm1lZGlhdGUwKjAFBgMr
ZXADIQC63kDzz+nGeTtt2CcA2M3Q1R8YephuuUzxlvEB+cgj5KNjMGEwDgYDVR0P
AQH/BAQDAgIEMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLwW6C3liNvuZpsS
uW5dA7Ah3gN9MB8GA1UdIwQYMBaAFOE9s81S97V1S09D3k0obt02yhrpMAUGAytl
cANBAJkX45OPKCFrJ2EmgXntZQFznQuUriA68Pxaxxzy3/W1jDtxf2cccDxtS1TJ
uPGtJ5Ri8dbk+5FgK3GQFQweDwA=
-----END CERTIFICATE-----
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIIq53ao+dZ09B33ER3RWNEbIhuQAOP/aza1sLDcCaBwN
-----END PRIVATE KEY-----
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBlzCCAUmgAwIBAgIBATAFBgMrZXAwUzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
DURvbHRIdWIsIEluYy4xLDAqBgNVBAMTI2RvbHQgaW50ZWdyYXRpb24gdGVzdHMg
ZWQyNTUxOSBSb290MB4XDTIyMTAyNjIxMDE0MloXDTMyMTAyMzIxMDE0MlowUzEL
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRIdWIsIEluYy4xLDAqBgNVBAMTI2Rv
bHQgaW50ZWdyYXRpb24gdGVzdHMgZWQyNTUxOSBSb290MCowBQYDK2VwAyEAUSTT
dZ6hXoZFVLDT4li0j/4K0//gRILcsNnPeTXeENSjQjBAMA4GA1UdDwEB/wQEAwIC
BDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBThPbPNUve1dUtPQ95NKG7dNsoa
6TAFBgMrZXADQQCS//dI2SsZnwaLk2I4m9WCHihUyZ2wWeDonwsPXkBtNBxJZnJb
tw0xf6bL+3opXeQfVTkn/BePZ8s4hbeBK9AO
-----END CERTIFICATE-----
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIIcPLEb34wrHmDff8cr7jjLaaaRyWEd+kuYw2h1GRA9U
-----END PRIVATE KEY-----
@@ -0,0 +1,67 @@
-----BEGIN CERTIFICATE-----
MIIGETCCA/mgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjE5MDcGA1UEAxMwZG9sdCBpbnRlZ3JhdGlv
biB0ZXN0cyBSU0EgNDA5Ni1iaXQgSW50ZXJtZWRpYXRlMB4XDTIyMTAyNjIxMDEz
N1oXDTMyMTAyMzIxMDEzN1owWDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRI
dWIsIEluYy4xMTAvBgNVBAMTKGRvbHQgaW50ZWdyYXRpb24gdGVzdHMgUlNBIDQw
OTYtYml0IExlYWYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVFmdv
tpYlR7XPQlnSbza5io/JAmGlOX30InseMZkddyURv+9rs8FY5PuEZyNH5VcJ/w7n
xP3MwD8Uctojnl2FoEZjXreIIefPmyeLRgSXBTNE+iioTXn7B2sfPXFr4GeRborH
E8GZJOgztlWrBkPinDn9dcY2tJzlh0HWIRedeohVlqs45Uy7u1UkpGyVZPobTXm3
9S7gSyeGRnAgaIRPfVZdTkUHCY4x+Hn94Uj5U7TAH6QYLzeKGmFIRoQxgabPaZw+
Ug0XAVDIoYmlOPgphQjkLpjLDEt7nhxnEvMG68ZrR6c7WGOS+eC6HasAdgnxWmRo
HRSMdKKyDh5TwVbRGxlHAhcFPEYqDwUXb+H781Cia4MAo4eUiblBdEtQs97ymeRt
HBoSU2ORQIOYx568SZwKDx3/HwyHd/5jZ0oM0kMoVJhvjjiF30su1Tuku6FT0Uu4
NsIPf0Sq3BHERPz244t9yyFobbT8WdtNHGOOjEUWSP/ho/9hez6rboH2No1K1RuN
2wQlQ5mNIQyPwkrACOdhYvQPCs0gp4Y3wgdrQ7jqccObXy5hokRC92WfgwCFVIEl
JT9lOoBElH5IS2BaP+4k9k/A/LXQ87OmqRvZlKsaMX9LdUZoLFS3EzSDFdnWdgtf
QJIDX0T1l8LQaNhbcbfNVrRbD8+BSB3tdllv9wIDAQABo4HdMIHaMA4GA1UdDwEB
/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB8GA1Ud
IwQYMBaAFFVLRPReehc5TLVcwASWmZzRgdVfMIGDBgNVHREEfDB6gitkb2x0LWlu
c3RhbmNlLmRvbHQtaW50ZWdyYXRpb24tdGVzdC5leGFtcGxlhktzcGlmZmU6Ly9k
b2x0LWludGVncmF0aW9uLXRlc3RzLmRldi50cnVzdC5kb2x0aHViLmNvbS5leGFt
cGxlL2RvbHQtaW5zdGFuY2UwDQYJKoZIhvcNAQELBQADggIBAKeAj0ALw5Qbc45u
kjGx856yoFdunVXRujz5/v37AuGEEV16DMnONroHD2DSss2vxGEQGEkvypgWOLE6
L5QPqH93W+deVrVeHS1FNWbEWGVEJEtIZOhZsTCU9bIj+WtgcHDCk7DHE2t2DBeh
QH4aDPfkPL0vOmD/H6Mq0dbPPJW6FuS0tIlCXorKHM98lqmOWcxDnbGl1aH4uITo
GB6dltX2YU9gM5G15Np9Nng2d1owTbOHt5sMvtKxCZeb+AYZvTGCFq8tRTlGvxHZ
Xr39YmtGbplzkEq8EVEMUTYHse0cdsw2xxYkq9aqYegrBHHfNFybv2U6Rz+yxco5
p44NecwZgsSm4+ZEb6gHg9RSZ/egDKHFEkQgapjQcRrHxrNqUmn2/zMmEs9uJLYM
nYCxrSlGY+wULDk9wsAStrz5n0xhsl0mE/CjRcwtiFyNW5QqBD//d4bacfFhPMA1
1Ce2mcha+PZhLC43zxuN5DMFNJWEiOzUpH72CwQ6UpnLZnL2Kkhff3SEuPAn83s/
8zHXEWYbvLlBVTZjTxJ5+4YqyEQaf4SHZoIJXLwUbp5ZSz1EIP6qlgqGtxHYBePo
KUtkFjf5aWt1nQ/Yu1sIBMa4i+xfQey/zwQS1smLrwlzh6QqvykINQCUUMzN2rQZ
kAddIrPAEFcBeHRQs93N+IqisBpA
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFljCCA36gAwIBAgIBAjANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjExMC8GA1UEAxMoZG9sdCBpbnRlZ3JhdGlv
biB0ZXN0cyBSU0EgNDA5Ni1iaXQgUm9vdDAeFw0yMjEwMjYyMTAxMzdaFw0zMjEw
MjMyMTAxMzdaMGAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Eb2x0SHViLCBJbmMu
MTkwNwYDVQQDEzBkb2x0IGludGVncmF0aW9uIHRlc3RzIFJTQSA0MDk2LWJpdCBJ
bnRlcm1lZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC47wob
mq2NLhf6EJdkWeli1E0ViOVpGOM05FNtcrYuX0A/y5VQtmavwchdn02Fa0ueEu3I
JU9gqYu8Ubpa9fE3xWGA97543yx8Y3/blL6EGD4yWzf+iMb3R2qOe/omTOPllk3g
D4pghlaSQe5ZRzzvVfUBH1Qj6WTSHcUoRCKUYaaBFpLxapjAS90Vf6PL1GQabdaq
JN/BUbC1dR/4Z+brelUy9NSvAXg7/HtndiRMl3sOU8wh6NXVpPYta4xhkGr230Cc
t1kOMPRSq4px9DOx3vZJCyOUy1Ro2CgAU2px2PlBG+95/TrqTgO6G8DxGYSV2bDY
ZpHX1MyRoaYAuRvvuffXt17CCHbiD5i9VYy6F8WBLd16l96RsgU6sREOryYoXFZ0
K9oUA69PEabq7H6Tlg6sQgaQ6u1No/H4H2eYTtmhdcOnaRWPq5i/x7EZ/cnwp9zc
7P0afMTrKl1ezXxXOVRVpmk7SD53lqXYXNJpy1pf2wTvPnl4mq1aCnQtHPmEFbuJ
LzejLBKrelfm7HMmQfxiKYKCHcth96eclP9GXhmA6XkU2BqbXGDEetDv+YiRdaQl
wKdfRhCZPBVBcy7DnqJoa0lss5l0e3lTu2+wW5Znb3FzXdJSnl1e6togF9IgJAkH
n4Fgs4/33TXQi0XPmy/iTbiUR8Ht8HhGBO4A2QIDAQABo2MwYTAOBgNVHQ8BAf8E
BAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVUtE9F56FzlMtVzABJaZ
nNGB1V8wHwYDVR0jBBgwFoAUmmgyBnblEP+8fE5WcVV1fDkenHswDQYJKoZIhvcN
AQELBQADggIBAIzbD8T6npRjMcTCHTfirl4r2eM9r6ANHIZgro5HK8EaTGaD2pQC
3nnh9dJfnw/bbIUG6yEacAAfp1Krba/f+z3B6PyIdbhGAkYaAZzyujzcyPZN3yx0
AIzZxwO4f9mpZ1Q95Xpn5ygozFKzZUg+AYW2qmyftDCVtHcZWBnKREgE64PMZ9b4
/sajWdmx9jdr6algdEUu4kIxGvAq5C2pgydh1mpVcx4Znvroczip+dlUAb5cudGP
krzCmdi9RxeGc/RIghNRNBtKVQtMh3nQwE0YOcIRY3T0WwCJHoRqCX9SoJvS/mYg
mpm4YxLf9NXxnhTCNTCgBZ+lYqqW4nt6msh10inYg/nSDgWoU50VC5WOQwmVbAXx
N4JrONvNXElWdEVkz8V2Lq1mwA6+4Mf1Rjau+j04z6bqZkdMYzCH0fG0to5B4fiM
+XfoFDgZfnymSuEPKjo4vsGLwwNAwfsVNIuiqEkJODKf31p9YNgNW23v6uKzV/GR
x6rKidp6XjfUkSXdmoPd4+qdhJLe+IQEVtoBUALlpGEYckin0L1/9Sl/GIucnkz3
bjq+NazgnPeRb2YdfiQBsY5C7b9x7bbRZdtskCtIjrdzvYr+Hil0xHDlqRSlOHZz
1snsRgG+DJF7rEPiXayz89JNrucWsrnyTYiQHANXWcwSKacILL1jneum
-----END CERTIFICATE-----
@@ -0,0 +1,67 @@
-----BEGIN CERTIFICATE-----
MIIGGTCCBAGgAwIBAgIBBDANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjE5MDcGA1UEAxMwZG9sdCBpbnRlZ3JhdGlv
biB0ZXN0cyBSU0EgNDA5Ni1iaXQgSW50ZXJtZWRpYXRlMB4XDTIyMTAyNjIxMDEz
N1oXDTIyMTAyNzA5MDEzN1owYDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDURvbHRI
dWIsIEluYy4xOTA3BgNVBAMTMGRvbHQgaW50ZWdyYXRpb24gdGVzdHMgUlNBIDQw
OTYtYml0IEV4cGlyZWQgTGVhZjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAN2eUhKl74hhAnLW4N5x3UHkiHkcoWzck6Qfg3u7d3OhtURYVMgUTynW/JKb
WfHBGT8yG77HT/GF0x+sV+IajZeZT1F4xou7sO9MFL7QDyEoaZo37dLkhr+mWkYb
YadcIRNAFY/vuI/xP5DMPVrZNzoDp6VHnW3NwlYWYlPLLkjIGcZafVkt3UfI0XzZ
4QhKtPDNopIt3lLmod5HLwcjiWIcMyjWJVue4kP71H9AA+7edCQ9kDmfO+v4JtUr
3AE1q+vwNQe8mXaAj8aRXJc2m6qmRfbeVdsI0YYdeDFyuhahb2hqaD/pAEbaNz0p
hy8AvPRY/oUwmF0oZ92YI94DUDgxneFyUp0I4+4ngUKUYwXHg0Elvw9w472rNBHB
qNAbPh1wi4bBKs4yVZaZB35ESWHl9gmFQMN5+dGgnB6kVgLZOmBKoaVwBjQ+SeSQ
QhDUnNph70y4LSNY+GEKWeYY6wZH0PbRa4PNhuXSs4aE9sHCbWKyRR1zlfoEloVr
xj1/Dx04nP0/tFcEcb0XMjOcTH/2484SJ9smBn8HZwybltIdZcpPNNVN98ZiPPK2
BXR9bOWYEJsjovGFVNSYQP0kURAez4qwFuppZ0WUHH5STJLBlkRhe3YQEG3RHojj
H8Tb1ynUJuLdM1dTCQe+Q9XVtUOXfxKBX+kJdphR/z3xS9FrAgMBAAGjgd0wgdow
DgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
MAAwHwYDVR0jBBgwFoAUVUtE9F56FzlMtVzABJaZnNGB1V8wgYMGA1UdEQR8MHqC
K2RvbHQtaW5zdGFuY2UuZG9sdC1pbnRlZ3JhdGlvbi10ZXN0LmV4YW1wbGWGS3Nw
aWZmZTovL2RvbHQtaW50ZWdyYXRpb24tdGVzdHMuZGV2LnRydXN0LmRvbHRodWIu
Y29tLmV4YW1wbGUvZG9sdC1pbnN0YW5jZTANBgkqhkiG9w0BAQsFAAOCAgEAQWgb
s9Y7kqnhxZr5UrZDqadVGCULU+M8+UqxLtT4IlS23z49uXcMgylX7Zzb1IwSHwN0
crZKzi/O0biTCFT0Kq3lTdLPrUUEt4qJXnMlLz5UYLs3ujSrDbCjNQMr7YM6/bjo
LPmThTlCUR1L611SJCYTg4zXlCOuTOqPLzrsyW7yoqk6++HIzf7x2CI5VAW7FrrV
J6QG80WKaDGRkVMINXGVxkcUEKQ69hc218jDA70J60PpiPHXmv/MzvzMc0dxnw1m
mB/4Cy9wsOP6M4YL8flmTbD6qLeMbmGVRDNJknQ+bo+RPAG6yO/TGXTYwSfPH9ki
wOE5OysRB8Rm9KGX+00W5OoRmRF8duj/b5EW+SnF6J3etKMbgzHUcKLrIB54ikMv
vNNcCbGS+Qb94cBfLXt9zK+ifywUjnT1au/ahlz5MonzVNmudeabn261A3UbXFg2
6dvlbPLbb/FDoDomr+uIQcipkjN2F3Pe7AYGW5JDr1+sqyfPx2BpYnASaKFZtVrL
FvlyYC/wtp29QW+zAn+csaS1r9WgUZfKoI29fIBE2Qw2367QpEQPgNdhZQEfXIwM
K10uZJPiam8buVt88PNKsc+wYFaOzHeGO3kmq86Em9j9SJa5EF+yU0Et+I3z7hna
xSEruA+hC+ccBaicl2rxNeiml7xbOTiuQD6Okx0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFljCCA36gAwIBAgIBAjANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjExMC8GA1UEAxMoZG9sdCBpbnRlZ3JhdGlv
biB0ZXN0cyBSU0EgNDA5Ni1iaXQgUm9vdDAeFw0yMjEwMjYyMTAxMzdaFw0zMjEw
MjMyMTAxMzdaMGAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Eb2x0SHViLCBJbmMu
MTkwNwYDVQQDEzBkb2x0IGludGVncmF0aW9uIHRlc3RzIFJTQSA0MDk2LWJpdCBJ
bnRlcm1lZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC47wob
mq2NLhf6EJdkWeli1E0ViOVpGOM05FNtcrYuX0A/y5VQtmavwchdn02Fa0ueEu3I
JU9gqYu8Ubpa9fE3xWGA97543yx8Y3/blL6EGD4yWzf+iMb3R2qOe/omTOPllk3g
D4pghlaSQe5ZRzzvVfUBH1Qj6WTSHcUoRCKUYaaBFpLxapjAS90Vf6PL1GQabdaq
JN/BUbC1dR/4Z+brelUy9NSvAXg7/HtndiRMl3sOU8wh6NXVpPYta4xhkGr230Cc
t1kOMPRSq4px9DOx3vZJCyOUy1Ro2CgAU2px2PlBG+95/TrqTgO6G8DxGYSV2bDY
ZpHX1MyRoaYAuRvvuffXt17CCHbiD5i9VYy6F8WBLd16l96RsgU6sREOryYoXFZ0
K9oUA69PEabq7H6Tlg6sQgaQ6u1No/H4H2eYTtmhdcOnaRWPq5i/x7EZ/cnwp9zc
7P0afMTrKl1ezXxXOVRVpmk7SD53lqXYXNJpy1pf2wTvPnl4mq1aCnQtHPmEFbuJ
LzejLBKrelfm7HMmQfxiKYKCHcth96eclP9GXhmA6XkU2BqbXGDEetDv+YiRdaQl
wKdfRhCZPBVBcy7DnqJoa0lss5l0e3lTu2+wW5Znb3FzXdJSnl1e6togF9IgJAkH
n4Fgs4/33TXQi0XPmy/iTbiUR8Ht8HhGBO4A2QIDAQABo2MwYTAOBgNVHQ8BAf8E
BAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVUtE9F56FzlMtVzABJaZ
nNGB1V8wHwYDVR0jBBgwFoAUmmgyBnblEP+8fE5WcVV1fDkenHswDQYJKoZIhvcN
AQELBQADggIBAIzbD8T6npRjMcTCHTfirl4r2eM9r6ANHIZgro5HK8EaTGaD2pQC
3nnh9dJfnw/bbIUG6yEacAAfp1Krba/f+z3B6PyIdbhGAkYaAZzyujzcyPZN3yx0
AIzZxwO4f9mpZ1Q95Xpn5ygozFKzZUg+AYW2qmyftDCVtHcZWBnKREgE64PMZ9b4
/sajWdmx9jdr6algdEUu4kIxGvAq5C2pgydh1mpVcx4Znvroczip+dlUAb5cudGP
krzCmdi9RxeGc/RIghNRNBtKVQtMh3nQwE0YOcIRY3T0WwCJHoRqCX9SoJvS/mYg
mpm4YxLf9NXxnhTCNTCgBZ+lYqqW4nt6msh10inYg/nSDgWoU50VC5WOQwmVbAXx
N4JrONvNXElWdEVkz8V2Lq1mwA6+4Mf1Rjau+j04z6bqZkdMYzCH0fG0to5B4fiM
+XfoFDgZfnymSuEPKjo4vsGLwwNAwfsVNIuiqEkJODKf31p9YNgNW23v6uKzV/GR
x6rKidp6XjfUkSXdmoPd4+qdhJLe+IQEVtoBUALlpGEYckin0L1/9Sl/GIucnkz3
bjq+NazgnPeRb2YdfiQBsY5C7b9x7bbRZdtskCtIjrdzvYr+Hil0xHDlqRSlOHZz
1snsRgG+DJF7rEPiXayz89JNrucWsrnyTYiQHANXWcwSKacILL1jneum
-----END CERTIFICATE-----
@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFbTCCA1WgAwIBAgIBATANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJVUzEW
MBQGA1UEChMNRG9sdEh1YiwgSW5jLjExMC8GA1UEAxMoZG9sdCBpbnRlZ3JhdGlv
biB0ZXN0cyBSU0EgNDA5Ni1iaXQgUm9vdDAeFw0yMjEwMjYyMTAxMzdaFw0zMjEw
MjMyMTAxMzdaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Eb2x0SHViLCBJbmMu
MTEwLwYDVQQDEyhkb2x0IGludGVncmF0aW9uIHRlc3RzIFJTQSA0MDk2LWJpdCBS
b290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqtesAvWsaJka6DLe
56o0b8xxuO5MIf7OC6SWX3GzFSNCW0rVBYZXK3v/Rv4hyni9DGgStQfvDWA+ZEvF
x1EtdtfRWx41RvtgrjQHj965Zh+fI41TSVyXYRL5v08tnXzu5Y1v51XlbCwmtXyP
cq1oYdNi/4XaVLEx+nYfZ2u3WXnzuHBcQc7n67zLdOUnHYszWpRrvqgmSCuqUz1x
Q431Kq4qORkRNUD/lvaXiE7Dgp3lJeYqcq27YX5AKODgBsPYCqD1iKiSphLWb84O
LUymJJDQ/ytYuMuwEK4Y0jsCLU1NnUI/Esdk4UeYQSdumNE70/9UuCGXSgpCOLt1
o/jKkEiagI4vQ8W3Daa+G3heNT2ukvK3JAnn2nCcH/El2/KsaJCX5idu7qjyxHMT
srkocltpEU3wLDQ8OuezcYUOig9fLX2lbZhNmEWdV5aXr2QrGXX4YmHw36awr1zm
6c33bjL6Hz3r9HgoBROIJDV4SvpCpnRRZJcx62sAQEUYjp0ASN2b95alPKYGFzti
m93kqVxMvb98b+L1XX/5LaU6Auqz6rWVJf8cBxgLlqope4IsSpP4jNUUw+m2l4Q6
dtaAg43UfHsVNuwgXYqvYrBJerSViPL1eDaxTLmjtyuWqHqb/MdGeU6EbTThieHq
cDEPLzk26VzxfVqgI4jL7ggJibECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgIEMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJpoMgZ25RD/vHxOVnFVdXw5Hpx7MA0G
CSqGSIb3DQEBCwUAA4ICAQBgkaeyYLRUku3eyBSzG9QGjTsYFRAj5ov4gEj3SkdG
3vBJ+QttGIyDksn0p/kSq6O1pWDWSk2hUqC/AV3w1mGZt/BX7MrM27HlwGPD42zh
ndxx73axiSLVovTpDD4b5gihjx55GJzM7VTjFKTTTD8DBsZg+vVNtbMJHG+oa8Fe
xCGE6TH4q39Xzy0mYMBxj90MLQlUgak1I7juWZTFs3T6eCPB+10onwYDwAaSjxt/
abqKz3FSEdCclBZ/t6W7HRJNznKjtgL3xm7B1yRkXJuGVRzdPOa9GW3n1XOzMmFy
OqEHGhlGov/5O+jGoAGMD1EyYzhMxD71Y0hfNMt6XVV39tsbzwFYM7SkhJ2xgHzs
mdGxac9S+Hcyki0JHKIAAkswAG2POsrBxMLcUsvp4Gie0H0Gz53/wZEc5zC05pr3
VSjMXwnrCKTNpx6/hJNqf1rJLjBkJCiCEpeK7o4FjnVNGnIE0KroUsnWpRXwVQ0I
b/BJTA1BwA5AOvCFWIN+kVJTIl3FBQAKmsEn37VCPhMiOuy2HbVeQL1P+VveMb7X
9K7JoFb2OA1V7UL1iak9489xvXBGQzsMnJXHzo43T2eIODBXH3Cd+cFCoC2Zshm3
IjGR72bNhDgb9DvnIE0cUA4Umrs+yJkK2BJe294fi6nD80SDwbuxj6pW1jOSChf8
vQ==
-----END CERTIFICATE-----
@@ -0,0 +1,489 @@
tests:
- name: tls, bad root, failover to standby fails
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/ed25519_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: "use repo1"
- query: "call dolt_assume_cluster_role('standby', '11')"
error_match: failed to transition from primary to standby gracefully
- exec: "create table vals (i int primary key)"
- exec: "insert into vals values (0)"
- name: tls, expired leaf, failover to standby fails
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_exp_key.pem
- name: cert.pem
source_path: testdata/rsa_exp_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: "use repo1"
- query: "call dolt_assume_cluster_role('standby', '11')"
error_match: failed to transition from primary to standby gracefully
- exec: "create table vals (i int primary key)"
- exec: "insert into vals values (0)"
- name: tls, mismatched dns, failover to standby fails
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
server_name_dns: ["does-not-match.dolt-instance.dolt-integration-test.example"]
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: "use repo1"
- query: "call dolt_assume_cluster_role('standby', '11')"
error_match: failed to transition from primary to standby gracefully
- exec: "create table vals (i int primary key)"
- exec: "insert into vals values (0)"
- name: tls, mismatched url, failover to standby fails
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
server_name_urls: ["spiffe://dolt-integration-tests.dev.trust.dolthub.com.example/dolt-instance/does-not-match"]
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: "use repo1"
- query: "call dolt_assume_cluster_role('standby', '11')"
error_match: failed to transition from primary to standby gracefully
- exec: "create table vals (i int primary key)"
- exec: "insert into vals values (0)"
- name: tls, good rsa certs, create new database, primary replicates to standby, fails over, new primary replicates to standby, fails over, new primary has all writes
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/rsa_key.pem
- name: cert.pem
source_path: testdata/rsa_chain.pem
- name: root.pem
source_path: testdata/rsa_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: 'use repo1'
- exec: 'create table vals (i int primary key)'
- exec: 'insert into vals values (0),(1),(2),(3),(4)'
- query: "call dolt_assume_cluster_role('standby', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["5"]]
- query: "call dolt_assume_cluster_role('primary', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (5),(6),(7),(8),(9)'
- query: "call dolt_assume_cluster_role('standby', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["10"]]
- query: "call dolt_assume_cluster_role('primary', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (10),(11),(12),(13),(14)'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["15"]]
- name: tls, good ed25519 certs, create new database, primary replicates to standby, fails over, new primary replicates to standby, fails over, new primary has all writes
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
server_name_urls: ["spiffe://dolt-integration-tests.dev.trust.dolthub.com.example/dolt-instance"]
server_name_dns: ["dolt-instance.dolt-integration-test.example"]
- name: key.pem
source_path: testdata/ed25519_key.pem
- name: cert.pem
source_path: testdata/ed25519_chain.pem
- name: root.pem
source_path: testdata/ed25519_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
server_name_urls: ["spiffe://dolt-integration-tests.dev.trust.dolthub.com.example/dolt-instance"]
server_name_dns: ["dolt-instance.dolt-integration-test.example"]
- name: key.pem
source_path: testdata/ed25519_key.pem
- name: cert.pem
source_path: testdata/ed25519_chain.pem
- name: root.pem
source_path: testdata/ed25519_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: 'use repo1'
- exec: 'create table vals (i int primary key)'
- exec: 'insert into vals values (0),(1),(2),(3),(4)'
- query: "call dolt_assume_cluster_role('standby', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["5"]]
- query: "call dolt_assume_cluster_role('primary', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (5),(6),(7),(8),(9)'
- query: "call dolt_assume_cluster_role('standby', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["10"]]
- query: "call dolt_assume_cluster_role('primary', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (10),(11),(12),(13),(14)'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["15"]]
@@ -924,177 +924,3 @@ tests:
result:
columns: ["count(*)"]
rows: [["15"]]
- name: tls, bad root, failover to standby fails
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/chain_key.pem
- name: cert.pem
source_path: testdata/chain_cert.pem
- name: root.pem
source_path: testdata/invalid_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/chain_key.pem
- name: cert.pem
source_path: testdata/chain_cert.pem
- name: root.pem
source_path: testdata/invalid_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: "use repo1"
- query: "call dolt_assume_cluster_role('standby', '11')"
error_match: failed to transition from primary to standby gracefully
- exec: "create table vals (i int primary key)"
- exec: "insert into vals values (0)"
- name: tls, good root, create new database, primary replicates to standby, fails over, new primary replicates to standby, fails over, new primary has all writes
multi_repos:
- name: server1
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3309
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50052/{database}
bootstrap_role: primary
bootstrap_epoch: 1
remotesapi:
port: 50051
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/chain_key.pem
- name: cert.pem
source_path: testdata/chain_cert.pem
- name: root.pem
source_path: testdata/chain_root.pem
server:
args: ["--config", "server.yaml"]
port: 3309
- name: server2
with_files:
- name: server.yaml
contents: |
log_level: trace
listener:
host: 0.0.0.0
port: 3310
cluster:
standby_remotes:
- name: standby
remote_url_template: https://localhost:50051/{database}
bootstrap_role: standby
bootstrap_epoch: 1
remotesapi:
port: 50052
tls_key: key.pem
tls_cert: cert.pem
tls_ca: root.pem
- name: key.pem
source_path: testdata/chain_key.pem
- name: cert.pem
source_path: testdata/chain_cert.pem
- name: root.pem
source_path: testdata/chain_root.pem
server:
args: ["--config", "server.yaml"]
port: 3310
connections:
- on: server1
queries:
- exec: 'create database repo1'
- exec: 'use repo1'
- exec: 'create table vals (i int primary key)'
- exec: 'insert into vals values (0),(1),(2),(3),(4)'
- query: "call dolt_assume_cluster_role('standby', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["5"]]
- query: "call dolt_assume_cluster_role('primary', 2)"
result:
columns: ["status"]
rows: [["0"]]
- on: server2
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (5),(6),(7),(8),(9)'
- query: "call dolt_assume_cluster_role('standby', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["10"]]
- query: "call dolt_assume_cluster_role('primary', 3)"
result:
columns: ["status"]
rows: [["0"]]
- on: server1
queries:
- exec: 'use repo1'
- exec: 'insert into vals values (10),(11),(12),(13),(14)'
- query: "select count(*) from vals"
result:
columns: ["count(*)"]
rows: [["15"]]
@@ -16,9 +16,9 @@ tests:
- name: repo1
with_files:
- name: chain_key.pem
source_path: testdata/chain_key.pem
source_path: testdata/rsa_key.pem
- name: chain_cert.pem
source_path: testdata/chain_cert.pem
source_path: testdata/rsa_chain.pem
- name: server.yaml
contents: |
listener:
@@ -33,9 +33,9 @@ tests:
- name: repo1
with_files:
- name: chain_key.pem
source_path: testdata/chain_key.pem
source_path: testdata/rsa_key.pem
- name: chain_cert.pem
source_path: testdata/chain_cert.pem
source_path: testdata/rsa_chain.pem
- name: server.yaml
contents: |
listener:
@@ -53,9 +53,9 @@ tests:
- name: repo1
with_files:
- name: chain_key.pem
source_path: testdata/chain_key.pem
source_path: testdata/rsa_key.pem
- name: chain_cert.pem
source_path: testdata/chain_cert.pem
source_path: testdata/rsa_chain.pem
- name: server.yaml
contents: |
listener: