Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[internal/kafka] define a common validation function for kafka authentication #27674

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .chloggen/kafka-validate-authentication.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: internal/kafka, kafkaexporter, kafkametricsreceiver, kafkareceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "define a common validation function for kafka authentication"

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [27486]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [api]
29 changes: 1 addition & 28 deletions exporter/kafkaexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,34 +115,7 @@ func (cfg *Config) Validate() error {
return err
}

return validateSASLConfig(cfg.Authentication.SASL)
}

func validateSASLConfig(c *kafka.SASLConfig) error {
if c == nil {
return nil
}

if c.Username == "" {
return fmt.Errorf("auth.sasl.username is required")
}

if c.Password == "" {
return fmt.Errorf("auth.sasl.password is required")
}

switch c.Mechanism {
case "PLAIN", "AWS_MSK_IAM", "SCRAM-SHA-256", "SCRAM-SHA-512":
// Do nothing, valid mechanism
default:
return fmt.Errorf("auth.sasl.mechanism should be one of 'PLAIN', 'AWS_MSK_IAM', 'SCRAM-SHA-256' or 'SCRAM-SHA-512'. configured value %v", c.Mechanism)
}

if c.Version < 0 || c.Version > 1 {
return fmt.Errorf("auth.sasl.version has to be either 0 or 1. configured value %v", c.Version)
}

return nil
return cfg.Authentication.Validate()
}

func saramaProducerCompressionCodec(compression string) (sarama.CompressionCodec, error) {
Expand Down
66 changes: 55 additions & 11 deletions internal/kafka/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ package kafka // import "github.com/open-telemetry/opentelemetry-collector-contr
import (
"crypto/sha256"
"crypto/sha512"
"crypto/tls"
"fmt"

"github.com/IBM/sarama"
"go.opentelemetry.io/collector/config/configtls"
"go.uber.org/multierr"

"github.com/open-telemetry/opentelemetry-collector-contrib/internal/kafka/awsmsk"
)
Expand Down Expand Up @@ -91,13 +93,8 @@ func configurePlaintext(config PlainTextConfig, saramaConfig *sarama.Config) {
}

func configureSASL(config SASLConfig, saramaConfig *sarama.Config) error {

if config.Username == "" {
return fmt.Errorf("username have to be provided")
}

if config.Password == "" {
return fmt.Errorf("password have to be provided")
if err := validateSASL(config); err != nil {
return err
}

saramaConfig.Net.SASL.Enable = true
Expand All @@ -119,7 +116,7 @@ func configureSASL(config SASLConfig, saramaConfig *sarama.Config) error {
}
saramaConfig.Net.SASL.Mechanism = awsmsk.Mechanism
default:
return fmt.Errorf(`invalid SASL Mechanism %q: can be either "PLAIN", "AWS_MSK_IAM", "SCRAM-SHA-256" or "SCRAM-SHA-512"`, config.Mechanism)
// Do nothing, validateSASL validate mechanism
}

switch config.Version {
Expand All @@ -128,17 +125,18 @@ func configureSASL(config SASLConfig, saramaConfig *sarama.Config) error {
case 1:
saramaConfig.Net.SASL.Version = sarama.SASLHandshakeV1
default:
return fmt.Errorf(`invalid SASL Protocol Version %d: can be either 0 or 1`, config.Version)
// Do nothing, validateSASL validate version
}

return nil
}

func configureTLS(config configtls.TLSClientSetting, saramaConfig *sarama.Config) error {
tlsConfig, err := config.LoadTLSConfig()
tlsConfig, err := validateTLS(config)
if err != nil {
return fmt.Errorf("error loading tls config: %w", err)
return err
}

saramaConfig.Net.TLS.Enable = true
saramaConfig.Net.TLS.Config = tlsConfig
return nil
Expand All @@ -159,3 +157,49 @@ func configureKerberos(config KerberosConfig, saramaConfig *sarama.Config) {
saramaConfig.Net.SASL.GSSAPI.Realm = config.Realm
saramaConfig.Net.SASL.GSSAPI.ServiceName = config.ServiceName
}

// Validate validates authentication config
func (auth Authentication) Validate() error {
var errs error
if auth.TLS != nil {
_, err := validateTLS(*auth.TLS)
errs = multierr.Append(errs, err)
}
if auth.SASL != nil {
err := validateSASL(*auth.SASL)
errs = multierr.Append(errs, err)
}
return errs
}

func validateTLS(c configtls.TLSClientSetting) (*tls.Config, error) {
tlsConfig, err := c.LoadTLSConfig()
if err != nil {
return nil, fmt.Errorf("error loading tls config: %w", err)
}

return tlsConfig, nil
}

func validateSASL(c SASLConfig) error {
if c.Username == "" {
return fmt.Errorf("auth.sasl.username is required")
}

if c.Password == "" {
return fmt.Errorf("auth.sasl.password is required")
}

switch c.Mechanism {
case "PLAIN", "AWS_MSK_IAM", "SCRAM-SHA-256", "SCRAM-SHA-512":
// Do nothing, valid mechanism
default:
return fmt.Errorf("auth.sasl.mechanism should be one of 'PLAIN', 'AWS_MSK_IAM', 'SCRAM-SHA-256' or 'SCRAM-SHA-512'. configured value %v", c.Mechanism)
}

if c.Version < 0 || c.Version > 1 {
return fmt.Errorf("auth.sasl.version has to be either 0 or 1. configured value %v", c.Version)
}

return nil
}
8 changes: 4 additions & 4 deletions internal/kafka/authentication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,22 @@ func TestAuthentication(t *testing.T) {
{
auth: Authentication{SASL: &SASLConfig{Username: "jdoe", Password: "pass", Mechanism: "SCRAM-SHA-222"}},
saramaConfig: saramaSASLSCRAM512Config,
err: "invalid SASL Mechanism",
err: "auth.sasl.mechanism should be one of 'PLAIN', 'AWS_MSK_IAM', 'SCRAM-SHA-256' or 'SCRAM-SHA-512'",
},
{
auth: Authentication{SASL: &SASLConfig{Username: "", Password: "pass", Mechanism: "SCRAM-SHA-512"}},
saramaConfig: saramaSASLSCRAM512Config,
err: "username have to be provided",
err: "auth.sasl.username is required",
},
{
auth: Authentication{SASL: &SASLConfig{Username: "jdoe", Password: "", Mechanism: "SCRAM-SHA-512"}},
saramaConfig: saramaSASLSCRAM512Config,
err: "password have to be provided",
err: "auth.sasl.password is required",
},
{
auth: Authentication{SASL: &SASLConfig{Username: "jdoe", Password: "pass", Mechanism: "SCRAM-SHA-512", Version: 2}},
saramaConfig: saramaSASLSCRAM512Config,
err: "invalid SASL Protocol Version",
err: "auth.sasl.version has to be either 0 or 1",
},
}
for _, test := range tests {
Expand Down
7 changes: 4 additions & 3 deletions receiver/kafkametricsreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func TestLoadConfig(t *testing.T) {
require.NoError(t, err)
require.NoError(t, component.UnmarshalConfig(sub, cfg))

assert.NoError(t, component.ValidateConfig(cfg))
assert.Equal(t, &Config{
ScraperControllerSettings: scraperhelper.NewDefaultScraperControllerSettings(metadata.Type),
Brokers: []string{"10.10.10.10:9092"},
Expand All @@ -37,9 +38,9 @@ func TestLoadConfig(t *testing.T) {
Authentication: kafka.Authentication{
TLS: &configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "ca.pem",
CertFile: "cert.pem",
KeyFile: "key.pem",
CAFile: "./testdata/certs/ca.pem",
CertFile: "./testdata/certs/cert.pem",
KeyFile: "./testdata/certs/key.pem",
},
},
},
Expand Down
21 changes: 21 additions & 0 deletions receiver/kafkametricsreceiver/testdata/certs/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDeDCCAmCgAwIBAgIUEv6GM2Nfe1ZY14X0BrIab/gcN6kwDQYJKoZIhvcNAQEL
BQAwQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzANBgNVBAoM
BlNwbHVuazENMAsGA1UECwwEbzExeTAgFw0yMzExMTAyMjQ3NDNaGA8zMDIzMDMx
MzIyNDc0M1owQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzAN
BgNVBAoMBlNwbHVuazENMAsGA1UECwwEbzExeTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAL4vhZtMBcVjmgpAf9FX+IaUmf5uy4edU/FciSuG+ope5UrL
oVaaN+3qWAyz+YLDyBkMUBlORQuG3PnboOVx6ZgRKH58Q50ZWXtTmuj/Vof/Naj3
9vfxKe6whyTt5NT498+4x8Q0M+tsg9GkUyqpO5dNZVkpFqGiVmGkXvqHbiOvbrTt
pjc3R7XcXuYdRlwwPDFLdxBR9cTEQw+ISUg+y88OFRXla9/sAGJt27N+Y+xti5LQ
XFobtg7t5Cd/xFVlTpj95FhsQE/RNWYQrUCNSYDvQaM8Rs2TK0YcGU1qnZxXQo2F
oBBqPLdPlJlSfdxmfDOXqbAgdAwXjq0dfKgBb70CAwEAAaNkMGIwHQYDVR0OBBYE
FJe6Dwd8+SvhJBpnSLBJj9bvb/AnMB8GA1UdIwQYMBaAFJe6Dwd8+SvhJBpnSLBJ
j9bvb/AnMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0RBAgwBocEfwAAATANBgkqhkiG
9w0BAQsFAAOCAQEApw698ftzFl6QMBm1hC2BZsjTxg/dZXDFvr6Ft6ZN+fksKCWx
UMJgvvd3n/6KKrufp/EC5H4Gr049KUoMq0XZg05gVna1e1Ee9XSeKzB8Pd6DcPkC
8iTahh/RbXmVdVezccq59Fri7nyzlA+fDY8PaiayGYDvqEccSeD6ouL24AESvLwd
2RDnxTjNYu5iEie3M/28h+0fUEDkC7imCQmLcpPr0XWjXMR7v0bmdzksxp79RQUx
Eq46J3UX/zc8c3r3etSara2RjUBfNW2jvUT4Ic6yeyYgYWAb/Mqr6kK1GIBT99Fk
trN2MRYD4hmvAfAqdCbpzWbKJnrHRh9d9B0UXA==
-----END CERTIFICATE-----
20 changes: 20 additions & 0 deletions receiver/kafkametricsreceiver/testdata/certs/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIUPvmQl4flwH3wehEJ13F6SMjTm78wDQYJKoZIhvcNAQEL
BQAwQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzANBgNVBAoM
BlNwbHVuazENMAsGA1UECwwEbzExeTAgFw0yMzExMTAyMjU1MjdaGA8zMDIzMDMx
MzIyNTUyN1owVjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzAN
BgNVBAoMBlNwbHVuazENMAsGA1UECwwEbzExeTESMBAGA1UEAwwJbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvi+Fm0wFxWOaCkB/0Vf4
hpSZ/m7Lh51T8VyJK4b6il7lSsuhVpo37epYDLP5gsPIGQxQGU5FC4bc+dug5XHp
mBEofnxDnRlZe1Oa6P9Wh/81qPf29/Ep7rCHJO3k1Pj3z7jHxDQz62yD0aRTKqk7
l01lWSkWoaJWYaRe+oduI69utO2mNzdHtdxe5h1GXDA8MUt3EFH1xMRDD4hJSD7L
zw4VFeVr3+wAYm3bs35j7G2LktBcWhu2Du3kJ3/EVWVOmP3kWGxAT9E1ZhCtQI1J
gO9BozxGzZMrRhwZTWqdnFdCjYWgEGo8t0+UmVJ93GZ8M5epsCB0DBeOrR18qAFv
vQIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBSXug8HfPkr4SQa
Z0iwSY/W72/wJzANBgkqhkiG9w0BAQsFAAOCAQEAGGm4Fxl6uh0WOANUvCVQaCiS
712u98oU9mp0hyF2NVQjATCwEmVEmrPyARh00FmZuuFsTMNfb0zdYsrxRiG0tYqe
tRtQR91QdVQBpF+74IQr04VaoLf94CekXpokHyggC54Ak452jGht7oJY6FHsRPuu
9MB7o1AxHJkSvjCl/fU4NqVH3sjlt99iSKCv+aHau/bb+MDN+uwr+7gZiCVEqxgA
m5QZ773Zs6+SU+K8he2iD3AM5aclxQR1wT0VKnl2hMH5tcptyAcldGNEY/iqnyWf
fWebz6Gq8vakMN74qcW/UprKk4JgC9RxC80U9FkVyL37JHHQIXkVI1vJ+sIZNw==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions receiver/kafkametricsreceiver/testdata/certs/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+L4WbTAXFY5oK
QH/RV/iGlJn+bsuHnVPxXIkrhvqKXuVKy6FWmjft6lgMs/mCw8gZDFAZTkULhtz5
26DlcemYESh+fEOdGVl7U5ro/1aH/zWo9/b38SnusIck7eTU+PfPuMfENDPrbIPR
pFMqqTuXTWVZKRaholZhpF76h24jr2607aY3N0e13F7mHUZcMDwxS3cQUfXExEMP
iElIPsvPDhUV5Wvf7ABibduzfmPsbYuS0FxaG7YO7eQnf8RVZU6Y/eRYbEBP0TVm
EK1AjUmA70GjPEbNkytGHBlNap2cV0KNhaAQajy3T5SZUn3cZnwzl6mwIHQMF46t
HXyoAW+9AgMBAAECggEAHgVQWMA6VPsw8JdX1crGHzBL0p7Yn9KU0o+h024eFEOA
fDsCf7IeS/7m4TJzm1GeP13zMttpCLXEIeiqUC2YCvoCY1zoK186Ab6jwE218ge2
B7MEmATIcrYIzyqCKaAXNgHb/ruiynG5qRkAS8ak8nA0JEvZF7CRZB5XI8LG/vjH
ZVtZi4EWERi1q84pD7eB2Hnnnpr84SGiJKK5B19W+wZA1OZhcbMKexm13GKWZi1t
V0W4PyjUio9vb4KU8KHMaHYYacNAWevYXtM/5C7dotEvRi5XLwWwwZFpL9mAMjQT
UNE6AaAk2S4ilRW8suJ4hu8R2NRoDs88ZSTAVHxvvQKBgQDvEgKtQIvSG592V1/L
Q87zJeMPxNViyFitJg3wYVHv0WVYg9abWvJUl8vL+jUaz1XObxqpBG7XkVUR4xW3
z0T98rIsonJt9aAtkWhVZASjk/vIHOvM6YhJFVZbYrwHFd0n8v3UcmweY4Ed8lnM
vypSJBRughVuUGIiTFQravq3lwKBgQDLp03ivrpErLRD7sjXuTdzQxfTy2jjjo8W
9QNTevK9fpTRxje8f2uMgj7aygdEl0Tv+cnBw8T6t2egO06kyEeJb5HArCjvjHJB
JrNpa6wQg/td0xY25Mm7bnXw9jiyGZYz6/T674cgcpEGP9I3fud/RtSaLuckos6C
0EPABYBdywKBgQCGgvGynWCORTCBm0Ow0GQ+dpC9LJiLTgJm2cR5/afmcUC+ft9e
5dr3Mble+Var0QCMeALeGjprW8ArokNz+lDtOYJ6jqQnrk4DlY7IjM/3YaoGvA8I
alVeGX1PScxViD243oVm5UJkDsR1HwjbpKuhL9+3FcYNHXk5pwysqTKL3QKBgAdi
IWi/EXG78S0lUxK/HEuJeyuqjDrzyCxE5cH5CyPjmvGgBhVHaVbGwhCcknbiJRWu
MKpdtp6AV7lvbQJ8YFuTN+2MUE+e/+VsycRgqvROVKaqKHwE/2tULeJ2iseqNc/c
Fh2i4XtDrA5V8gEhELOEleChIrApVuNXOZ2UlXrRAoGAWGcyg5IOWjELFw5+aLRR
/LBgbDZUQ05UmYrdAaeUO8xB2Mnm5j3uA08PAWoUag5TcMcrufkWk6ikjNphMSE9
6jp3xn7hzHczig0xbNs6y23i5IerTxxSUaKT3myoLjSQeiab1js/kOuXie4Ss/7Z
91aAg6wAgiyKq/2TwUlThHQ=
-----END PRIVATE KEY-----
6 changes: 3 additions & 3 deletions receiver/kafkametricsreceiver/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ kafkametrics:
- consumers
auth:
tls:
ca_file: ca.pem
cert_file: cert.pem
key_file: key.pem
ca_file: ./testdata/certs/ca.pem
cert_file: ./testdata/certs/cert.pem
key_file: ./testdata/certs/key.pem
topic_match: test_\w+
group_match: test_\w+
12 changes: 6 additions & 6 deletions receiver/kafkareceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func TestLoadConfig(t *testing.T) {
Authentication: kafka.Authentication{
TLS: &configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "ca.pem",
CertFile: "cert.pem",
KeyFile: "key.pem",
CAFile: "./testdata/certs/ca.pem",
CertFile: "./testdata/certs/cert.pem",
KeyFile: "./testdata/certs/key.pem",
},
},
},
Expand Down Expand Up @@ -75,9 +75,9 @@ func TestLoadConfig(t *testing.T) {
Authentication: kafka.Authentication{
TLS: &configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "ca.pem",
CertFile: "cert.pem",
KeyFile: "key.pem",
CAFile: "./testdata/certs/ca.pem",
CertFile: "./testdata/certs/cert.pem",
KeyFile: "./testdata/certs/key.pem",
},
},
},
Expand Down
21 changes: 21 additions & 0 deletions receiver/kafkareceiver/testdata/certs/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDeDCCAmCgAwIBAgIUEv6GM2Nfe1ZY14X0BrIab/gcN6kwDQYJKoZIhvcNAQEL
BQAwQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzANBgNVBAoM
BlNwbHVuazENMAsGA1UECwwEbzExeTAgFw0yMzExMTAyMjQ3NDNaGA8zMDIzMDMx
MzIyNDc0M1owQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzAN
BgNVBAoMBlNwbHVuazENMAsGA1UECwwEbzExeTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAL4vhZtMBcVjmgpAf9FX+IaUmf5uy4edU/FciSuG+ope5UrL
oVaaN+3qWAyz+YLDyBkMUBlORQuG3PnboOVx6ZgRKH58Q50ZWXtTmuj/Vof/Naj3
9vfxKe6whyTt5NT498+4x8Q0M+tsg9GkUyqpO5dNZVkpFqGiVmGkXvqHbiOvbrTt
pjc3R7XcXuYdRlwwPDFLdxBR9cTEQw+ISUg+y88OFRXla9/sAGJt27N+Y+xti5LQ
XFobtg7t5Cd/xFVlTpj95FhsQE/RNWYQrUCNSYDvQaM8Rs2TK0YcGU1qnZxXQo2F
oBBqPLdPlJlSfdxmfDOXqbAgdAwXjq0dfKgBb70CAwEAAaNkMGIwHQYDVR0OBBYE
FJe6Dwd8+SvhJBpnSLBJj9bvb/AnMB8GA1UdIwQYMBaAFJe6Dwd8+SvhJBpnSLBJ
j9bvb/AnMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0RBAgwBocEfwAAATANBgkqhkiG
9w0BAQsFAAOCAQEApw698ftzFl6QMBm1hC2BZsjTxg/dZXDFvr6Ft6ZN+fksKCWx
UMJgvvd3n/6KKrufp/EC5H4Gr049KUoMq0XZg05gVna1e1Ee9XSeKzB8Pd6DcPkC
8iTahh/RbXmVdVezccq59Fri7nyzlA+fDY8PaiayGYDvqEccSeD6ouL24AESvLwd
2RDnxTjNYu5iEie3M/28h+0fUEDkC7imCQmLcpPr0XWjXMR7v0bmdzksxp79RQUx
Eq46J3UX/zc8c3r3etSara2RjUBfNW2jvUT4Ic6yeyYgYWAb/Mqr6kK1GIBT99Fk
trN2MRYD4hmvAfAqdCbpzWbKJnrHRh9d9B0UXA==
-----END CERTIFICATE-----
20 changes: 20 additions & 0 deletions receiver/kafkareceiver/testdata/certs/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIUPvmQl4flwH3wehEJ13F6SMjTm78wDQYJKoZIhvcNAQEL
BQAwQjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzANBgNVBAoM
BlNwbHVuazENMAsGA1UECwwEbzExeTAgFw0yMzExMTAyMjU1MjdaGA8zMDIzMDMx
MzIyNTUyN1owVjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExDzAN
BgNVBAoMBlNwbHVuazENMAsGA1UECwwEbzExeTESMBAGA1UEAwwJbG9jYWxob3N0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvi+Fm0wFxWOaCkB/0Vf4
hpSZ/m7Lh51T8VyJK4b6il7lSsuhVpo37epYDLP5gsPIGQxQGU5FC4bc+dug5XHp
mBEofnxDnRlZe1Oa6P9Wh/81qPf29/Ep7rCHJO3k1Pj3z7jHxDQz62yD0aRTKqk7
l01lWSkWoaJWYaRe+oduI69utO2mNzdHtdxe5h1GXDA8MUt3EFH1xMRDD4hJSD7L
zw4VFeVr3+wAYm3bs35j7G2LktBcWhu2Du3kJ3/EVWVOmP3kWGxAT9E1ZhCtQI1J
gO9BozxGzZMrRhwZTWqdnFdCjYWgEGo8t0+UmVJ93GZ8M5epsCB0DBeOrR18qAFv
vQIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBSXug8HfPkr4SQa
Z0iwSY/W72/wJzANBgkqhkiG9w0BAQsFAAOCAQEAGGm4Fxl6uh0WOANUvCVQaCiS
712u98oU9mp0hyF2NVQjATCwEmVEmrPyARh00FmZuuFsTMNfb0zdYsrxRiG0tYqe
tRtQR91QdVQBpF+74IQr04VaoLf94CekXpokHyggC54Ak452jGht7oJY6FHsRPuu
9MB7o1AxHJkSvjCl/fU4NqVH3sjlt99iSKCv+aHau/bb+MDN+uwr+7gZiCVEqxgA
m5QZ773Zs6+SU+K8he2iD3AM5aclxQR1wT0VKnl2hMH5tcptyAcldGNEY/iqnyWf
fWebz6Gq8vakMN74qcW/UprKk4JgC9RxC80U9FkVyL37JHHQIXkVI1vJ+sIZNw==
-----END CERTIFICATE-----
Loading