From 0ec9307004c5f1db07c0d57df276c827f3e6076e Mon Sep 17 00:00:00 2001 From: Andrea Spacca Date: Wed, 6 Oct 2021 13:33:19 +0200 Subject: [PATCH 1/3] [Libbeat] Security - fetch IMDSv2 token for add_cloud_metadata support on aws --- .../add_cloud_metadata/provider_aws_ec2.go | 83 ++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go index 350ec63b8c6..ec9af868bd9 100644 --- a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go +++ b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go @@ -18,12 +18,87 @@ package add_cloud_metadata import ( + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + + "github.com/elastic/beats/v7/libbeat/logp" + + "github.com/elastic/beats/v7/libbeat/common/transport/tlscommon" + "github.com/elastic/beats/v7/libbeat/common" s "github.com/elastic/beats/v7/libbeat/common/schema" c "github.com/elastic/beats/v7/libbeat/common/schema/mapstriface" ) const ec2InstanceIdentityURI = "/2014-02-25/dynamic/instance-identity/document" +const ec2InstanceIMDSv2TokenValueHeader = "X-aws-ec2-metadata-token" +const ec2InstanceIMDSv2TokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" +const ec2InstanceIMDSv2TokenTTLValue = "21600" +const ec2InstanceIMDSv2TokenURI = "/latest/api/token" + +// fetches IMDSv2 token, returns empty one on errors +func getIMDSv2Token(c *common.Config) string { + logger := logp.NewLogger("add_cloud_metadata") + + config := defaultConfig() + if err := c.Unpack(&config); err != nil { + logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + return "" + } + + tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) + if err != nil { + logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + return "" + } + + client := http.Client{ + Timeout: config.Timeout, + Transport: &http.Transport{ + DisableKeepAlives: true, + DialContext: (&net.Dialer{ + Timeout: config.Timeout, + KeepAlive: 0, + }).DialContext, + TLSClientConfig: tlsConfig.ToConfig(), + }, + } + + tokenReq, err := http.NewRequest("PUT", fmt.Sprintf("http://%s%s", metadataHost, ec2InstanceIMDSv2TokenURI), nil) + if err != nil { + logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + return "" + } + + tokenReq.Header.Add(ec2InstanceIMDSv2TokenTTLHeader, ec2InstanceIMDSv2TokenTTLValue) + rsp, err := client.Do(tokenReq) + defer func(body io.ReadCloser) { + if body != nil { + body.Close() + } + }(rsp.Body) + + if err != nil { + logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + return "" + } + + if rsp.StatusCode != http.StatusOK { + logger.Warnf("error while getting IMDSv2 token: http request status %d. No token in the metadata request will be used.", rsp.StatusCode) + return "" + } + + all, err := ioutil.ReadAll(rsp.Body) + if err != nil { + logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + return "" + } + + return string(all) +} // AWS EC2 Metadata Service var ec2MetadataFetcher = provider{ @@ -48,7 +123,13 @@ var ec2MetadataFetcher = provider{ return common.MapStr{"cloud": out} } - fetcher, err := newMetadataFetcher(config, "aws", nil, metadataHost, ec2Schema, ec2InstanceIdentityURI) + headers := make(map[string]string, 1) + token := getIMDSv2Token(config) + if len(token) > 0 { + headers[ec2InstanceIMDSv2TokenValueHeader] = token + } + + fetcher, err := newMetadataFetcher(config, "aws", headers, metadataHost, ec2Schema, ec2InstanceIdentityURI) return fetcher, err }, } From d894bfd7c7552cd5b9a5fda6767f44904e08acfb Mon Sep 17 00:00:00 2001 From: Andrea Spacca Date: Wed, 6 Oct 2021 17:19:29 +0200 Subject: [PATCH 2/3] changelog --- CHANGELOG.next.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 2997981db48..e205be40d5a 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -23,6 +23,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - Remove deprecated/undocumented IncludeCreatorMetadata setting from kubernetes metadata config options {pull}28006[28006] - Remove deprecated fields from kubernetes module {pull}28046[28046] - Remove deprecated config option aws_partition. {pull}28120[28120] +- Enable IMDSv2 support for `add_cloud_metadata` processor on AWS. {issue}22101[22101] {pull}28285[28285] *Auditbeat* From fc33e85e7153c9329777cb194611c3f0d6216083 Mon Sep 17 00:00:00 2001 From: Andrea Spacca Date: Wed, 13 Oct 2021 10:35:21 +0200 Subject: [PATCH 3/3] cr fixes --- .../add_cloud_metadata/provider_aws_ec2.go | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go index ec9af868bd9..8978d51ae32 100644 --- a/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go +++ b/libbeat/processors/add_cloud_metadata/provider_aws_ec2.go @@ -26,18 +26,19 @@ import ( "github.com/elastic/beats/v7/libbeat/logp" - "github.com/elastic/beats/v7/libbeat/common/transport/tlscommon" - "github.com/elastic/beats/v7/libbeat/common" s "github.com/elastic/beats/v7/libbeat/common/schema" c "github.com/elastic/beats/v7/libbeat/common/schema/mapstriface" + "github.com/elastic/beats/v7/libbeat/common/transport/tlscommon" ) -const ec2InstanceIdentityURI = "/2014-02-25/dynamic/instance-identity/document" -const ec2InstanceIMDSv2TokenValueHeader = "X-aws-ec2-metadata-token" -const ec2InstanceIMDSv2TokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" -const ec2InstanceIMDSv2TokenTTLValue = "21600" -const ec2InstanceIMDSv2TokenURI = "/latest/api/token" +const ( + ec2InstanceIdentityURI = "/2014-02-25/dynamic/instance-identity/document" + ec2InstanceIMDSv2TokenValueHeader = "X-aws-ec2-metadata-token" + ec2InstanceIMDSv2TokenTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" + ec2InstanceIMDSv2TokenTTLValue = "21600" + ec2InstanceIMDSv2TokenURI = "/latest/api/token" +) // fetches IMDSv2 token, returns empty one on errors func getIMDSv2Token(c *common.Config) string { @@ -45,13 +46,13 @@ func getIMDSv2Token(c *common.Config) string { config := defaultConfig() if err := c.Unpack(&config); err != nil { - logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + logger.Warnf("error when load config for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) return "" } tlsConfig, err := tlscommon.LoadTLSConfig(config.TLS) if err != nil { - logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + logger.Warnf("error when load TLS config for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) return "" } @@ -69,7 +70,7 @@ func getIMDSv2Token(c *common.Config) string { tokenReq, err := http.NewRequest("PUT", fmt.Sprintf("http://%s%s", metadataHost, ec2InstanceIMDSv2TokenURI), nil) if err != nil { - logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + logger.Warnf("error when make token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) return "" } @@ -82,18 +83,18 @@ func getIMDSv2Token(c *common.Config) string { }(rsp.Body) if err != nil { - logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + logger.Warnf("error when read token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) return "" } if rsp.StatusCode != http.StatusOK { - logger.Warnf("error while getting IMDSv2 token: http request status %d. No token in the metadata request will be used.", rsp.StatusCode) + logger.Warnf("error when check request status for getting IMDSv2 token: http request status %d. No token in the metadata request will be used.", rsp.StatusCode) return "" } all, err := ioutil.ReadAll(rsp.Body) if err != nil { - logger.Warnf("error while getting IMDSv2 token: %s. No token in the metadata request will be used.", err) + logger.Warnf("error when reading token request for getting IMDSv2 token: %s. No token in the metadata request will be used.", err) return "" }