Skip to content

Commit

Permalink
add new env config options for OTLP exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
seankhliao committed Oct 19, 2022
1 parent 1cbd4c2 commit 46817ba
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 25 deletions.
42 changes: 35 additions & 7 deletions exporters/otlp/internal/envconfig/envconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ func WithString(n string, fn func(string)) func(e *EnvOptionsReader) {
}
}

// WithBool retrieves the specified config and passes it to ConfigFn as a boolean.
func WithBool(n string, fn func(bool)) func(e *EnvOptionsReader) {
return func(e *EnvOptionsReader) {
if v, ok := e.GetEnvValue(n); ok {
if b, err := strconv.ParseBool(v); err == nil {
fn(b)
}
}
}
}

// WithDuration retrieves the specified config and passes it to ConfigFn as a duration.
func WithDuration(n string, fn func(time.Duration)) func(e *EnvOptionsReader) {
return func(e *EnvOptionsReader) {
Expand Down Expand Up @@ -91,18 +102,38 @@ func WithURL(n string, fn func(*url.URL)) func(e *EnvOptionsReader) {
}

// WithTLSConfig retrieves the specified config and passes it to ConfigFn as a crypto/tls.Config.
func WithTLSConfig(n string, fn func(*tls.Config)) func(e *EnvOptionsReader) {
func WithCertPool(n string, fn func(*x509.CertPool)) func(e *EnvOptionsReader) {
return func(e *EnvOptionsReader) {
if v, ok := e.GetEnvValue(n); ok {
if b, err := e.ReadFile(v); err == nil {
if c, err := createTLSConfig(b); err == nil {
if c, err := createCertPool(b); err == nil {
fn(c)
}
}
}
}
}

func WithClientCert(nc, nk string, fn func(tls.Certificate)) func(e *EnvOptionsReader) {
return func(e *EnvOptionsReader) {
vc, okc := e.GetEnvValue(nc)
vk, okk := e.GetEnvValue(nk)
if !okc || !okk {
return
}
cert, errc := e.ReadFile(vc)
key, errk := e.ReadFile(vk)
if errc != nil && errk != nil {
return
}
crt, err := tls.X509KeyPair(cert, key)
if err != nil {
return
}
fn(crt)
}
}

func keyWithNamespace(ns, key string) string {
if ns == "" {
return key
Expand Down Expand Up @@ -136,13 +167,10 @@ func stringToHeader(value string) map[string]string {
return headers
}

func createTLSConfig(certBytes []byte) (*tls.Config, error) {
func createCertPool(certBytes []byte) (*x509.CertPool, error) {
cp := x509.NewCertPool()
if ok := cp.AppendCertsFromPEM(certBytes); !ok {
return nil, errors.New("failed to append certificate to the cert pool")
}

return &tls.Config{
RootCAs: cp,
}, nil
return cp, nil
}
119 changes: 105 additions & 14 deletions exporters/otlp/internal/envconfig/envconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,39 @@ package envconfig // import "go.opentelemetry.io/otel/exporters/otlp/internal/en

import (
"crypto/tls"
"crypto/x509"
"net/url"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

const WeakKey = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEbrSPmnlSOXvVzxCyv+VR3a0HDeUTvOcqrdssZ2k4gFoAoGCCqGSM49
AwEHoUQDQgAEDMTfv75J315C3K9faptS9iythKOMEeV/Eep73nWX531YAkmmwBSB
2dXRD/brsgLnfG57WEpxZuY7dPRbxu33BA==
-----END EC PRIVATE KEY-----
`

const WeakCertificate = `
-----BEGIN CERTIFICATE-----
MIIBhzCCASygAwIBAgIRANHpHgAWeTnLZpTSxCKs0ggwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHb3RlbC1nbzAeFw0yMTA0MDExMzU5MDNaFw0yMTA0MDExNDU5MDNa
MBIxEDAOBgNVBAoTB290ZWwtZ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS9
nWSkmPCxShxnp43F+PrOtbGV7sNfkbQ/kxzi9Ego0ZJdiXxkmv/C05QFddCW7Y0Z
sJCLHGogQsYnWJBXUZOVo2MwYTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAsBgNVHREEJTAjgglsb2NhbGhvc3SHEAAA
AAAAAAAAAAAAAAAAAAGHBH8AAAEwCgYIKoZIzj0EAwIDSQAwRgIhANwZVVKvfvQ/
1HXsTvgH+xTQswOwSSKYJ1cVHQhqK7ZbAiEAus8NxpTRnp5DiTMuyVmhVNPB+bVH
Lhnm4N/QDk5rek0=
MIIBjjCCATWgAwIBAgIUKQSMC66MUw+kPp954ZYOcyKAQDswCgYIKoZIzj0EAwIw
EjEQMA4GA1UECgwHb3RlbC1nbzAeFw0yMjEwMTkwMDA5MTlaFw0yMzEwMTkwMDA5
MTlaMBIxEDAOBgNVBAoMB290ZWwtZ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AAQMxN+/vknfXkLcr19qm1L2LK2Eo4wR5X8R6nvedZfnfVgCSabAFIHZ1dEP9uuy
Aud8bntYSnFm5jt09FvG7fcEo2kwZzAdBgNVHQ4EFgQUicGuhnTTkYLZwofXMNLK
SHFeCWgwHwYDVR0jBBgwFoAUicGuhnTTkYLZwofXMNLKSHFeCWgwDwYDVR0TAQH/
BAUwAwEB/zAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIg
Lfma8FnnxeSOi6223AsFfYwsNZ2RderNsQrS0PjEHb0CIBkrWacqARUAu7uT4cGu
jVcIxYQqhId5L8p/mAv2PWZS
-----END CERTIFICATE-----
`

type testOption struct {
TestString string
TestBool bool
TestDuration time.Duration
TestHeaders map[string]string
TestURL *url.URL
Expand Down Expand Up @@ -134,6 +144,52 @@ func TestEnvConfig(t *testing.T) {
},
expectedOptions: []testOption{},
},
{
name: "with a bool config",
reader: EnvOptionsReader{
GetEnv: func(n string) string {
if n == "HELLO" {
return "true"
} else if n == "WORLD" {
return "false"
}
return ""
},
},
configs: []ConfigFn{
WithBool("HELLO", func(b bool) {
options = append(options, testOption{TestBool: b})
}),
WithBool("WORLD", func(b bool) {
options = append(options, testOption{TestBool: b})
}),
},
expectedOptions: []testOption{
{
TestBool: true,
},
{
TestBool: false,
},
},
},
{
name: "with an invalid bool config",
reader: EnvOptionsReader{
GetEnv: func(n string) string {
if n == "HELLO" {
return "world"
}
return ""
},
},
configs: []ConfigFn{
WithBool("HELLO", func(b bool) {
options = append(options, testOption{TestBool: b})
}),
},
expectedOptions: []testOption{},
},
{
name: "with a duration config",
reader: EnvOptionsReader{
Expand Down Expand Up @@ -265,7 +321,7 @@ func TestEnvConfig(t *testing.T) {
}

func TestWithTLSConfig(t *testing.T) {
tlsCert, err := createTLSConfig([]byte(WeakCertificate))
pool, err := createCertPool([]byte(WeakCertificate))
assert.NoError(t, err)

reader := EnvOptionsReader{
Expand All @@ -285,12 +341,47 @@ func TestWithTLSConfig(t *testing.T) {

var option testOption
reader.Apply(
WithTLSConfig("CERTIFICATE", func(v *tls.Config) {
option = testOption{TestTLS: v}
}))
WithCertPool("CERTIFICATE", func(cp *x509.CertPool) {
option = testOption{TestTLS: &tls.Config{RootCAs: cp}}
}),
)

// nolint:staticcheck // ignoring tlsCert.RootCAs.Subjects is deprecated ERR because cert does not come from SystemCertPool.
assert.Equal(t, tlsCert.RootCAs.Subjects(), option.TestTLS.RootCAs.Subjects())
assert.Equal(t, pool.Subjects(), option.TestTLS.RootCAs.Subjects())
}

func TestWithClientCert(t *testing.T) {
cert, err := tls.X509KeyPair([]byte(WeakCertificate), []byte(WeakKey))
assert.NoError(t, err)

reader := EnvOptionsReader{
GetEnv: func(n string) string {
switch n {
case "CLIENT_CERTIFICATE":
return "/path/tls.crt"
case "CLIENT_KEY":
return "/path/tls.key"
}
return ""
},
ReadFile: func(n string) ([]byte, error) {
switch n {
case "/path/tls.crt":
return []byte(WeakCertificate), nil
case "/path/tls.key":
return []byte(WeakKey), nil
}
return []byte{}, nil
},
}

var option testOption
reader.Apply(
WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) {
option = testOption{TestTLS: &tls.Config{Certificates: []tls.Certificate{c}}}
}),
)
assert.Equal(t, cert, option.TestTLS.Certificates[0])
}

func TestStringToHeader(t *testing.T) {
Expand Down
27 changes: 25 additions & 2 deletions exporters/otlp/otlpmetric/internal/oconf/envconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package oconf // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/inte

import (
"crypto/tls"
"crypto/x509"
"net/url"
"os"
"path"
Expand Down Expand Up @@ -53,6 +54,7 @@ func ApplyHTTPEnvConfigs(cfg Config) Config {
func getOptionsFromEnv() []GenericOption {
opts := []GenericOption{}

tlsConf := &tls.Config{}
DefaultEnvOptionsReader.Apply(
envconfig.WithURL("ENDPOINT", func(u *url.URL) {
opts = append(opts, withEndpointScheme(u))
Expand Down Expand Up @@ -81,8 +83,13 @@ func getOptionsFromEnv() []GenericOption {
return cfg
}, withEndpointForGRPC(u)))
}),
envconfig.WithTLSConfig("CERTIFICATE", func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithTLSConfig("METRICS_CERTIFICATE", func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithHeaders("HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
envconfig.WithHeaders("METRICS_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
Expand Down Expand Up @@ -125,3 +132,19 @@ func withEndpointScheme(u *url.URL) GenericOption {
return WithSecure()
}
}

// revive:disable-next-line:flag-parameter
func withInsecure(b bool) GenericOption {
if b {
return WithInsecure()
}
return WithSecure()
}

func withTLSConfig(c *tls.Config, fn func(*tls.Config)) func(e *envconfig.EnvOptionsReader) {
return func(e *envconfig.EnvOptionsReader) {
if c.RootCAs != nil || len(c.Certificates) > 0 {
fn(c)
}
}
}
27 changes: 25 additions & 2 deletions exporters/otlp/otlptrace/internal/otlpconfig/envconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package otlpconfig // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/

import (
"crypto/tls"
"crypto/x509"
"net/url"
"os"
"path"
Expand Down Expand Up @@ -53,6 +54,7 @@ func ApplyHTTPEnvConfigs(cfg Config) Config {
func getOptionsFromEnv() []GenericOption {
opts := []GenericOption{}

tlsConf := &tls.Config{}
DefaultEnvOptionsReader.Apply(
envconfig.WithURL("ENDPOINT", func(u *url.URL) {
opts = append(opts, withEndpointScheme(u))
Expand Down Expand Up @@ -81,8 +83,13 @@ func getOptionsFromEnv() []GenericOption {
return cfg
}, withEndpointForGRPC(u)))
}),
envconfig.WithTLSConfig("CERTIFICATE", func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithTLSConfig("TRACES_CERTIFICATE", func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
envconfig.WithCertPool("TRACES_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
envconfig.WithClientCert("TRACES_CLIENT_CERTIFICATE", "TRACES_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
envconfig.WithBool("TRACES_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
envconfig.WithHeaders("HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
envconfig.WithHeaders("TRACES_HEADERS", func(h map[string]string) { opts = append(opts, WithHeaders(h)) }),
WithEnvCompression("COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
Expand Down Expand Up @@ -125,3 +132,19 @@ func WithEnvCompression(n string, fn func(Compression)) func(e *envconfig.EnvOpt
}
}
}

// revive:disable-next-line:flag-parameter
func withInsecure(b bool) GenericOption {
if b {
return WithInsecure()
}
return WithSecure()
}

func withTLSConfig(c *tls.Config, fn func(*tls.Config)) func(e *envconfig.EnvOptionsReader) {
return func(e *envconfig.EnvOptionsReader) {
if c.RootCAs != nil || len(c.Certificates) > 0 {
fn(c)
}
}
}

0 comments on commit 46817ba

Please sign in to comment.