diff --git a/internal/aws/awsutil/awsconfig.go b/internal/aws/awsutil/awsconfig.go index e26751860f545..9f19b4e033a45 100644 --- a/internal/aws/awsutil/awsconfig.go +++ b/internal/aws/awsutil/awsconfig.go @@ -41,6 +41,8 @@ type AWSSessionSettings struct { Profile string `mapstructure:"profile"` // Change the default shared creds file location SharedCredentialsFile []string `mapstructure:"shared_credentials_file"` + // Add a custom certificates file + CertificateFilePath string `mapstructure:"certificate_file_path"` } func CreateDefaultSessionConfig() AWSSessionSettings { diff --git a/internal/aws/awsutil/conn.go b/internal/aws/awsutil/conn.go index 8c00d59f53ed9..9ddf208eb87ea 100644 --- a/internal/aws/awsutil/conn.go +++ b/internal/aws/awsutil/conn.go @@ -18,6 +18,7 @@ package awsutil // import "github.com/open-telemetry/opentelemetry-collector-con import ( "context" "crypto/tls" + "crypto/x509" "errors" "net/http" "net/url" @@ -70,11 +71,16 @@ const ( // newHTTPClient returns new HTTP client instance with provided configuration. func newHTTPClient(logger *zap.Logger, maxIdle int, requestTimeout int, noVerify bool, - proxyAddress string) (*http.Client, error) { + proxyAddress string, certificateFilePath string) (*http.Client, error) { logger.Debug("Using proxy address: ", zap.String("proxyAddr", proxyAddress), ) - tls := &tls.Config{ + rootCA, certPoolError := loadCertPool(certificateFilePath) + if certificateFilePath != "" && certPoolError != nil { + logger.Warn("could not create root ca from", zap.String("file", certificateFilePath), zap.Error(certPoolError)) + } + tlsConfig := &tls.Config{ + RootCAs: rootCA, InsecureSkipVerify: noVerify, } @@ -86,7 +92,7 @@ func newHTTPClient(logger *zap.Logger, maxIdle int, requestTimeout int, noVerify } transport := &http.Transport{ MaxIdleConnsPerHost: maxIdle, - TLSClientConfig: tls, + TLSClientConfig: tlsConfig, Proxy: http.ProxyURL(proxyURL), } @@ -104,6 +110,20 @@ func newHTTPClient(logger *zap.Logger, maxIdle int, requestTimeout int, noVerify return http, err } +func loadCertPool(bundleFile string) (*x509.CertPool, error) { + bundleBytes, err := os.ReadFile(bundleFile) + if err != nil { + return nil, err + } + + p := x509.NewCertPool() + if !p.AppendCertsFromPEM(bundleBytes) { + return nil, errors.New("unable to append certs") + } + + return p, nil +} + func getProxyAddress(proxyAddress string) string { var finalProxyAddress string switch { @@ -135,7 +155,7 @@ func GetAWSConfigSession(logger *zap.Logger, cn ConnAttr, cfg *AWSSessionSetting var s *session.Session var err error var awsRegion string - http, err := newHTTPClient(logger, cfg.NumberOfWorkers, cfg.RequestTimeoutSeconds, cfg.NoVerifySSL, cfg.ProxyAddress) + http, err := newHTTPClient(logger, cfg.NumberOfWorkers, cfg.RequestTimeoutSeconds, cfg.NoVerifySSL, cfg.ProxyAddress, cfg.CertificateFilePath) if err != nil { logger.Error("unable to obtain proxy URL", zap.Error(err)) return nil, nil, err diff --git a/internal/aws/awsutil/conn_test.go b/internal/aws/awsutil/conn_test.go index 658740e75dc6c..025e3a590b248 100644 --- a/internal/aws/awsutil/conn_test.go +++ b/internal/aws/awsutil/conn_test.go @@ -167,3 +167,15 @@ func TestGetSTSCreds(t *testing.T) { _, err = getSTSCreds(logger, region, roleArn) assert.NotNil(t, err) } + +func TestLoadAmazonCertificateFromFile(t *testing.T) { + certFromFile, err := loadCertPool("testdata/public_amazon_cert.pem") + assert.NoError(t, err) + assert.NotNil(t, certFromFile) +} + +func TestLoadEmptyFile(t *testing.T) { + certFromFile, err := loadCertPool("") + assert.Error(t, err) + assert.Nil(t, certFromFile) +} diff --git a/internal/aws/awsutil/testdata/public_amazon_cert.pem b/internal/aws/awsutil/testdata/public_amazon_cert.pem new file mode 100644 index 0000000000000..3778b1249e6ce --- /dev/null +++ b/internal/aws/awsutil/testdata/public_amazon_cert.pem @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIH0zCCBrugAwIBAgIQBMMGivZOi26mB1Jxp6uRcDANBgkqhkiG9w0BAQsFADBE +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMR4wHAYDVQQDExVE +aWdpQ2VydCBHbG9iYWwgQ0EgRzIwHhcNMjIxMDE5MDAwMDAwWhcNMjMxMDE4MjM1 +OTU5WjAZMRcwFQYDVQQDEw53d3cuYW1hem9uLmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBALunUFi0NPgRyIURIRcLxJKw71+JBt+r7lyTwiPD7laN +Ptkn1ty+NYjQF47OK1c16iod5tJfWsH498kCvEV4lvLTEO5zp69WC/hdKMyloKhT +aVz65sclqgaOxmhbYM4V+7WtkbPPcYIJdvUwa4rVgGq4ORT4hjSr/i4vlcd7nDRf +Ybny5eXrgcKdHvdihUa233aI2ee/t1YmKd6ofXz2DcIbWVbwwxQQ+WAkGdQK6eW0 +4p4h1xfWQaaRx59bJv6mWDBuDupq/gqg4CeceUnxo4sI2isrk9f8bcrCgOK0S5IZ +65q6LZ8/hsuTEW93WcowwDYmEarttx3erKPX23kYfCECAwEAAaOCBOowggTmMB8G +A1UdIwQYMBaAFCRuKy3QapJRUSVpAaqaR6aJ50AgMB0GA1UdDgQWBBQJKEE2vH1O +ZskdbNTSoXXdKOl2NTCCAbMGA1UdEQSCAaowggGmgg15cC5hbWF6b24uY29tghZ5 +ZWxsb3dwYWdlcy5hbWF6b24uY29tghB3d3cubS5hbWF6b24uY29tghJ3d3cuY2Ru +LmFtYXpvbi5jb22CDHd3dy5hbXpuLmNvbYIOd3d3LmFtYXpvbi5jb22CDXVzLmFt +YXpvbi5jb22CEXVlZGF0YS5hbWF6b24uY29tghN0ZXN0LXd3dy5hbWF6b24uY29t +giVwLXlvLXd3dy1hbWF6b24tY29tLWthbGlhcy5hbWF6b24uY29tgiVwLXkzLXd3 +dy1hbWF6b24tY29tLWthbGlhcy5hbWF6b24uY29tgiVwLW50LXd3dy1hbWF6b24t +Y29tLWthbGlhcy5hbWF6b24uY29tghJtcDNyZWNzLmFtYXpvbi5jb22CFmtvbnJh +ZC10ZXN0LmFtYXpvbi5jb22CEWlwaG9uZS5hbWF6b24uY29tgg9ob21lLmFtYXpv +bi5jb22CFGNvcnBvcmF0ZS5hbWF6b24uY29tghFidXlib3guYW1hem9uLmNvbYII +YW16bi5jb22CCmFtYXpvbi5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG +CCsGAQUFBwMBBggrBgEFBQcDAjB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3Js +My5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxDQUcyLmNybDA1oDOgMYYvaHR0 +cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsQ0FHMi5jcmwwPgYD +VR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdp +Y2VydC5jb20vQ1BTMHQGCCsGAQUFBwEBBGgwZjAkBggrBgEFBQcwAYYYaHR0cDov +L29jc3AuZGlnaWNlcnQuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vY2FjZXJ0cy5k +aWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxDQUcyLmNydDAMBgNVHRMBAf8EAjAA +MIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQCt9776fP8QyIudPZwePhhqtGcp +Xc+xDCTKhYY069yCigAAAYPxZtKeAAAEAwBGMEQCIEHj94FxBJ8R7ppg6lbbbjJJ +CbNgDZCU0mHPYG8LLKXRAiBfVs1t/DzZ22LzsnTDgMTTlyxjNeEwFkLrH3xjuONq +SQB3ALNzdwfhhFD4Y4bWBancEQlKeS2xZwwLh9zwAw55NqWaAAABg/Fm0qEAAAQD +AEgwRgIhAOcecwX51C1Qr6WQ7Q7KuVBzoxVqWr6oIgWXekD9Q0sxAiEAvIsX+xbd +dyTY/PWGU/ClQS+XmYi9FwCfAfNpmQOStVUAdwC3Pvsk35xNunXyOcW6WPRsXfxC +z3qfNcSeHQmBJe20mQAAAYPxZtJhAAAEAwBIMEYCIQDsrFwTZxxiy22Cbj1vvR17 +3nuLwI1bH8mVHKTvtJEcJAIhAMvq5gyZ6XX1jMezfx3b5TQdIdBMnyuigR+qnXV1 +dPPuMA0GCSqGSIb3DQEBCwUAA4IBAQDDsRWV7UkhGeZFKcid24rv8CcBJ4wBR4iW +c7PU6uTuy9qYIJIPEpRPc/vD1mmLrEU2XI4SRE0D8zkPspQ6eXkrzmJLTj/lOBZt +n6MklId5xXaN0ag3AU+wXnXI6rfUHsxshwi1pflFzbD2MZXG+vuHMZRQ2VL1j3gn +im+GLaqUNe9R5lp1L8qj4rR/5JSq8ufqFQnjaHhsdffOydakiArLljzHuAqZ4zLk +hxfXmx/SvgX5JAR1DWS3R5RhZ0QeoQWOQT3Udj3hBuR5Tk0g2jiOZwPu4AlZJu2H +mmlNh6Jl6yjICGlwuTYmKBuSOhFOvCquhoIKlPUJL7Vtb98Brfa/ +-----END CERTIFICATE----- \ No newline at end of file