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

[filebeat] Add intermediary support for ssl.verification_mode #42368

Merged
merged 5 commits into from
Jan 28, 2025
Merged
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
63 changes: 50 additions & 13 deletions libbeat/otelbeat/oteltranslate/tls_otel.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"reflect"
"strings"

"github.com/mitchellh/mapstructure"
Expand All @@ -34,7 +35,6 @@ import (
// ssl.curve_types
// ssl.ca_sha256
// ssl.ca_trustred_fingerprint

// ssl.supported_protocols -> partially supported
// ssl.restart_on_cert_change.*
// ssl.renegotiation
Expand Down Expand Up @@ -77,6 +77,15 @@ func TLSCommonToOTel(tlscfg *tlscommon.Config) (map[string]any, error) {
return nil, err
}

//unpacks -> ssl.verification_mode
// not fully supported yet
switch tlscfg.VerificationMode {
case tlscommon.VerifyNone:
insecureSkipVerify = true
default:
// Handle all other cases, including VerifyFull, VerifyCertificate, or VerifyStrict
}

// unpacks -> ssl.certificate_authorities
// The OTel exporter accepts either single CA file or CA string. However,
// Beats support any combination and number of files and certificates
Expand Down Expand Up @@ -129,29 +138,57 @@ func TLSCommonToOTel(tlscfg *tlscommon.Config) (map[string]any, error) {
}

otelTLSConfig := map[string]any{
"insecure_skip_verify": insecureSkipVerify, // ssl.verirication_mode,

// Config
"insecure_skip_verify": insecureSkipVerify, // ssl.verification_mode:none
"include_system_ca_certs_pool": includeSystemCACertsPool,
"ca_pem": strings.Join(caCerts, ""), // ssl.certificate_authorities
"cert_pem": certPem, // ssl.certificate
"key_pem": certKeyPem, // ssl.key
"cipher_suites": ciphersuites, // ssl.cipher_suites
}

// For type safety check only
setIfNotNil(otelTLSConfig, "ca_pem", strings.Join(caCerts, "")) // ssl.certificate_authorities
setIfNotNil(otelTLSConfig, "cert_pem", certPem) // ssl.certificate
setIfNotNil(otelTLSConfig, "key_pem", certKeyPem) // ssl.key
setIfNotNil(otelTLSConfig, "cipher_suites", ciphersuites) // ssl.cipher_suites"

if err := typeSafetyCheck(otelTLSConfig); err != nil {
return nil, err
}
return otelTLSConfig, nil
}

// For type safety check
func typeSafetyCheck(value map[string]any) error {
// the returned valued should match `clienttls.Config` type.
// it throws an error if non existing key name is used in the returned map structure
// it throws an error if non existing key names are set
var result configtls.ClientConfig
d, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Squash: true,
Result: &result,
ErrorUnused: true,
})

if err := d.Decode(otelTLSConfig); err != nil {
return nil, err
err := d.Decode(value)
if err != nil {
return err
}
return err
}

return otelTLSConfig, nil
// Helper function to conditionally add fields to the map
func setIfNotNil(m map[string]any, key string, value any) {
if value == nil {
return
}

v := reflect.ValueOf(value)

switch v.Kind() {
case reflect.String:
if v.String() != "" {
m[key] = value
}
case reflect.Map, reflect.Slice:
if v.Len() > 0 {
m[key] = value
}
default:
m[key] = value
}
}
18 changes: 15 additions & 3 deletions libbeat/otelbeat/oteltranslate/tls_otel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package oteltranslate

import (
"crypto/tls"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -57,7 +58,18 @@ func TestTLSCommonToOTel(t *testing.T) {
err: true,
},
{
name: "when ca, cert, key and key_passphrase is provided",
name: "when ssl.verification_mode:none ",
input: &tlscommon.Config{
VerificationMode: tlscommon.VerifyNone,
},
want: map[string]any{
"insecure_skip_verify": true,
"include_system_ca_certs_pool": true,
},
err: false,
},
{
name: "when ca, cert, key and key_passphrase, cipher_suites is provided",
input: &tlscommon.Config{
CAs: []string{
"testdata/certs/rootCA.crt",
Expand Down Expand Up @@ -85,6 +97,7 @@ sxSmbIUfc2SGJGCJD4I=
Key: "testdata/certs/client.key",
Passphrase: "changeme",
},
CipherSuites: []tlscommon.CipherSuite{tlscommon.CipherSuite(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)},
},
want: map[string]any{
"ca_pem": `-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -183,12 +196,11 @@ m8TtceUhSOnXNrrO5agyMRmL0aYf8D425ot/uwTiSkOd4bdFeEaYs0ahHosxHq2N
me1zqwZ6EX7XHaa6j1mx9tcX
-----END RSA PRIVATE KEY-----
`,
"cipher_suites": []string{},
"insecure_skip_verify": false,
"include_system_ca_certs_pool": false,
"cipher_suites": []string{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"},
},
err: false,
// TODO: Add more scenarios
},
}

Expand Down
Loading