Skip to content

Commit

Permalink
Add unit test to check awsentity logs for sensitive information (#855) (
Browse files Browse the repository at this point in the history
#865)

Co-authored-by: Varun <[email protected]>
  • Loading branch information
nathalapooja and varunch77 authored Oct 28, 2024
1 parent a090dd3 commit d361a7b
Showing 1 changed file with 137 additions and 0 deletions.
137 changes: 137 additions & 0 deletions plugins/processors/awsentity/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
package awsentity

import (
"bytes"
"context"
"testing"

"github.com/stretchr/testify/assert"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
semconv "go.opentelemetry.io/collector/semconv/v1.22.0"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"

"github.com/aws/amazon-cloudwatch-agent/extension/entitystore"
"github.com/aws/amazon-cloudwatch-agent/plugins/processors/awsentity/entityattributes"
Expand Down Expand Up @@ -80,6 +83,19 @@ func newMockGetEC2InfoFromEntityStore(instance, accountId, asg string) func() en
}
}

// This helper function creates a test logger
// so that it can send the log messages into a
// temporary buffer for pattern matching
func CreateTestLogger(buf *bytes.Buffer) *zap.Logger {
writer := zapcore.AddSync(buf)

// Create a custom zapcore.Core that writes to the buffer
encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
core := zapcore.NewCore(encoder, writer, zapcore.DebugLevel)
logger := zap.New(core)
return logger
}

func TestProcessMetricsLogGroupAssociation(t *testing.T) {
logger, _ := zap.NewDevelopment()
p := newAwsEntityProcessor(&Config{
Expand Down Expand Up @@ -467,6 +483,127 @@ func TestProcessMetricsResourceEntityProcessing(t *testing.T) {
}
}

func TestAWSEntityProcessorNoSensitiveInfoInLogs(t *testing.T) {
// Create a buffer to capture log output
var buf bytes.Buffer
logger := CreateTestLogger(&buf)

configs := []struct {
name string
config *Config
}{
{
name: "EC2Service",
config: &Config{
EntityType: entityattributes.Service,
Platform: config.ModeEC2,
},
},
{
name: "EKSService",
config: &Config{
EntityType: entityattributes.Service,
Platform: config.ModeEC2,
KubernetesMode: config.ModeEKS,
ClusterName: "test-cluster",
},
},
{
name: "EC2Resource",
config: &Config{
EntityType: entityattributes.Resource,
Platform: config.ModeEC2,
},
},
{
name: "K8sOnPremService",
config: &Config{
EntityType: entityattributes.Service,
Platform: config.ModeOnPrem,
KubernetesMode: config.ModeK8sOnPrem,
ClusterName: "test-cluster",
},
},
}

for _, cfg := range configs {
t.Run(cfg.name, func(t *testing.T) {
buf.Reset()
processor := newAwsEntityProcessor(cfg.config, logger)

resetServiceNameSource := getServiceNameSource
getServiceNameSource = newMockGetServiceNameAndSource("test-service", "UserConfiguration")
defer func() { getServiceNameSource = resetServiceNameSource }()

resetGetEC2InfoFromEntityStore := getEC2InfoFromEntityStore
asgName := "test-asg"
getEC2InfoFromEntityStore = newMockGetEC2InfoFromEntityStore("i-1234567890abcdef0", "123456789012", asgName)
defer func() { getEC2InfoFromEntityStore = resetGetEC2InfoFromEntityStore }()

md := generateTestMetrics()
_, err := processor.processMetrics(context.Background(), md)
assert.NoError(t, err)

logOutput := buf.String()
assertNoSensitiveInfo(t, logOutput, md, asgName)
})
}
}

func generateTestMetrics() pmetric.Metrics {
md := pmetric.NewMetrics()
rm := md.ResourceMetrics().AppendEmpty()

attrs := rm.Resource().Attributes()
attrs.PutStr(attributeAwsLogGroupNames, "test-log-group")
attrs.PutStr(attributeServiceName, "test-service")
attrs.PutStr(attributeDeploymentEnvironment, "test-environment")
attrs.PutStr(semconv.AttributeK8SPodName, "test-pod")
attrs.PutStr(semconv.AttributeK8SNamespaceName, "test-namespace")
attrs.PutStr(semconv.AttributeK8SDeploymentName, "test-deployment")
attrs.PutStr(semconv.AttributeK8SNodeName, "test-node")

metric := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty()
metric.SetName("test-metric")
dp := metric.SetEmptyGauge().DataPoints().AppendEmpty()
dp.Attributes().PutStr(attributeServiceName, "datapoint-service-name")
dp.Attributes().PutStr(attributeDeploymentEnvironment, "datapoint-environment")

return md
}

func assertNoSensitiveInfo(t *testing.T, logOutput string, md pmetric.Metrics, asgName string) {
rm := md.ResourceMetrics().At(0)
attrs := rm.Resource().Attributes()
dp := rm.ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0)

getStringOrEmpty := func(val pcommon.Value, exists bool) string {
if !exists {
return ""
}
return val.AsString()
}

sensitivePatterns := []string{
`i-[0-9a-f]{17}`, // EC2 Instance ID regex pattern
`\d{12}`, // AWS Account ID regex pattern
asgName, // Auto Scaling Group name
getStringOrEmpty(attrs.Get(attributeAwsLogGroupNames)),
getStringOrEmpty(attrs.Get(attributeServiceName)),
getStringOrEmpty(attrs.Get(attributeDeploymentEnvironment)),
getStringOrEmpty(attrs.Get(semconv.AttributeK8SPodName)),
getStringOrEmpty(attrs.Get(semconv.AttributeK8SNamespaceName)),
getStringOrEmpty(attrs.Get(semconv.AttributeK8SDeploymentName)),
getStringOrEmpty(attrs.Get(semconv.AttributeK8SNodeName)),
getStringOrEmpty(dp.Attributes().Get(attributeServiceName)),
getStringOrEmpty(dp.Attributes().Get(attributeDeploymentEnvironment)),
}

for _, pattern := range sensitivePatterns {
assert.NotRegexp(t, pattern, logOutput)
}
}

func TestProcessMetricsDatapointAttributeScraping(t *testing.T) {
logger, _ := zap.NewDevelopment()
ctx := context.Background()
Expand Down

0 comments on commit d361a7b

Please sign in to comment.